XMREngXmrTestLs.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using log4net;
  28. using System;
  29. using System.Collections.Generic;
  30. using System.IO;
  31. using System.Reflection;
  32. using System.Text;
  33. using System.Threading;
  34. using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat;
  35. using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger;
  36. using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  37. using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list;
  38. using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion;
  39. using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString;
  40. using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3;
  41. using SharedEventParams = OpenSim.Region.ScriptEngine.Shared.EventParams;
  42. using SharedScriptBaseClass = OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass;
  43. namespace OpenSim.Region.ScriptEngine.Yengine
  44. {
  45. public partial class Yengine
  46. {
  47. private void XmrTestLs(string[] args, int indx)
  48. {
  49. bool flagFull = false;
  50. bool flagQueues = false;
  51. bool flagTopCPU = false;
  52. int maxScripts = 0x7FFFFFFF;
  53. int numScripts = 0;
  54. string outName = null;
  55. XMRInstance[] instances;
  56. // Decode command line options.
  57. for(int i = indx; i < args.Length; i++)
  58. {
  59. if(args[i] == "-full")
  60. {
  61. flagFull = true;
  62. continue;
  63. }
  64. if(args[i] == "-help")
  65. {
  66. m_log.Info("[YEngine]: yeng ls -full -max=<number> -out=<filename> -queues -topcpu");
  67. return;
  68. }
  69. if(args[i].StartsWith("-max="))
  70. {
  71. try
  72. {
  73. maxScripts = Convert.ToInt32(args[i].Substring(5));
  74. }
  75. catch(Exception e)
  76. {
  77. m_log.Error("[YEngine]: bad max " + args[i].Substring(5) + ": " + e.Message);
  78. return;
  79. }
  80. continue;
  81. }
  82. if(args[i].StartsWith("-out="))
  83. {
  84. outName = args[i].Substring(5);
  85. continue;
  86. }
  87. if(args[i] == "-queues")
  88. {
  89. flagQueues = true;
  90. continue;
  91. }
  92. if(args[i] == "-topcpu")
  93. {
  94. flagTopCPU = true;
  95. continue;
  96. }
  97. if(args[i][0] == '-')
  98. {
  99. m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'yeng ls -help'");
  100. return;
  101. }
  102. }
  103. TextWriter outFile = null;
  104. if(outName != null)
  105. {
  106. try
  107. {
  108. outFile = File.CreateText(outName);
  109. }
  110. catch(Exception e)
  111. {
  112. m_log.Error("[YEngine]: error creating " + outName + ": " + e.Message);
  113. return;
  114. }
  115. }
  116. else
  117. {
  118. outFile = new LogInfoTextWriter(m_log);
  119. }
  120. try
  121. {
  122. // Scan instance list to find those that match selection criteria.
  123. if(!Monitor.TryEnter(m_InstancesDict, 100))
  124. {
  125. m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
  126. return;
  127. }
  128. try
  129. {
  130. instances = new XMRInstance[m_InstancesDict.Count];
  131. foreach(XMRInstance ins in m_InstancesDict.Values)
  132. {
  133. if(InstanceMatchesArgs(ins, args, indx))
  134. {
  135. instances[numScripts++] = ins;
  136. }
  137. }
  138. }
  139. finally
  140. {
  141. Monitor.Exit(m_InstancesDict);
  142. }
  143. // Maybe sort by descending CPU time.
  144. if(flagTopCPU)
  145. {
  146. Array.Sort<XMRInstance>(instances, CompareInstancesByCPUTime);
  147. }
  148. // Print the entries.
  149. if(!flagFull)
  150. {
  151. outFile.WriteLine(" ItemID" +
  152. " CPU(ms)" +
  153. " NumEvents" +
  154. " Status " +
  155. " World Position " +
  156. " <Part>:<Item>");
  157. }
  158. for(int i = 0; (i < numScripts) && (i < maxScripts); i++)
  159. {
  160. outFile.WriteLine(instances[i].RunTestLs(flagFull));
  161. }
  162. // Print number of scripts that match selection criteria,
  163. // even if we were told to print fewer.
  164. outFile.WriteLine("total of {0} script(s)", numScripts);
  165. // If -queues given, print out queue contents too.
  166. if(flagQueues)
  167. {
  168. LsQueue(outFile, "start", m_StartQueue, args, indx);
  169. LsQueue(outFile, "sleep", m_SleepQueue, args, indx);
  170. LsQueue(outFile, "yield", m_YieldQueue, args, indx);
  171. }
  172. }
  173. finally
  174. {
  175. outFile.Close();
  176. }
  177. }
  178. private void XmrTestPev(string[] args, int indx)
  179. {
  180. bool flagAll = false;
  181. int numScripts = 0;
  182. XMRInstance[] instances;
  183. // Decode command line options.
  184. int i, j;
  185. List<string> selargs = new List<string>(args.Length);
  186. MethodInfo[] eventmethods = typeof(IEventHandlers).GetMethods();
  187. MethodInfo eventmethod;
  188. for(i = indx; i < args.Length; i++)
  189. {
  190. string arg = args[i];
  191. if(arg == "-all")
  192. {
  193. flagAll = true;
  194. continue;
  195. }
  196. if(arg == "-help")
  197. {
  198. m_log.Info("[YEngine]: yeng pev -all | <part-of-script-name> <event-name> <params...>");
  199. return;
  200. }
  201. if(arg[0] == '-')
  202. {
  203. m_log.Error("[YEngine]: unknown option " + arg + ", try 'yeng pev -help'");
  204. return;
  205. }
  206. for(j = 0; j < eventmethods.Length; j++)
  207. {
  208. eventmethod = eventmethods[j];
  209. if(eventmethod.Name == arg)
  210. goto gotevent;
  211. }
  212. selargs.Add(arg);
  213. }
  214. m_log.Error("[YEngine]: missing <event-name> <params...>, try 'yeng pev -help'");
  215. return;
  216. gotevent:
  217. string eventname = eventmethod.Name;
  218. StringBuilder sourcesb = new StringBuilder();
  219. while(++i < args.Length)
  220. {
  221. sourcesb.Append(' ');
  222. sourcesb.Append(args[i]);
  223. }
  224. string sourcest = sourcesb.ToString();
  225. string sourcehash;
  226. youveanerror = false;
  227. Token t = TokenBegin.Construct("", null, ErrorMsg, sourcest, out sourcehash);
  228. if(youveanerror)
  229. return;
  230. ParameterInfo[] paraminfos = eventmethod.GetParameters();
  231. object[] paramvalues = new object[paraminfos.Length];
  232. i = 0;
  233. while(!((t = t.nextToken) is TokenEnd))
  234. {
  235. if(i >= paramvalues.Length)
  236. {
  237. ErrorMsg(t, "extra parameter(s)");
  238. return;
  239. }
  240. paramvalues[i] = ParseParamValue(ref t);
  241. if(paramvalues[i] == null)
  242. return;
  243. i++;
  244. }
  245. SharedEventParams eps = new SharedEventParams(eventname, paramvalues, zeroDetectParams);
  246. // Scan instance list to find those that match selection criteria.
  247. if(!Monitor.TryEnter(m_InstancesDict, 100))
  248. {
  249. m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
  250. return;
  251. }
  252. try
  253. {
  254. instances = new XMRInstance[m_InstancesDict.Count];
  255. foreach(XMRInstance ins in m_InstancesDict.Values)
  256. {
  257. if(flagAll || InstanceMatchesArgs(ins, selargs.ToArray(), 0))
  258. {
  259. instances[numScripts++] = ins;
  260. }
  261. }
  262. }
  263. finally
  264. {
  265. Monitor.Exit(m_InstancesDict);
  266. }
  267. // Post event to the matching instances.
  268. for(i = 0; i < numScripts; i++)
  269. {
  270. XMRInstance inst = instances[i];
  271. m_log.Info("[YEngine]: post " + eventname + " to " + inst.m_DescName);
  272. inst.PostEvent(eps);
  273. }
  274. }
  275. private object ParseParamValue(ref Token token)
  276. {
  277. if(token is TokenFloat)
  278. {
  279. return new LSL_Float(((TokenFloat)token).val);
  280. }
  281. if(token is TokenInt)
  282. {
  283. return new LSL_Integer(((TokenInt)token).val);
  284. }
  285. if(token is TokenStr)
  286. {
  287. return new LSL_String(((TokenStr)token).val);
  288. }
  289. if(token is TokenKwCmpLT)
  290. {
  291. List<double> valuelist = new List<double>();
  292. while(!((token = token.nextToken) is TokenKwCmpGT))
  293. {
  294. if(!(token is TokenKwComma))
  295. {
  296. object value = ParseParamValue(ref token);
  297. if(value == null)
  298. return null;
  299. if(value is int)
  300. value = (double)(int)value;
  301. if(!(value is double))
  302. {
  303. ErrorMsg(token, "must be float or integer constant");
  304. return null;
  305. }
  306. valuelist.Add((double)value);
  307. }
  308. else if(token.prevToken is TokenKwComma)
  309. {
  310. ErrorMsg(token, "missing constant");
  311. return null;
  312. }
  313. }
  314. double[] values = valuelist.ToArray();
  315. switch(values.Length)
  316. {
  317. case 3:
  318. {
  319. return new LSL_Vector(values[0], values[1], values[2]);
  320. }
  321. case 4:
  322. {
  323. return new LSL_Rotation(values[0], values[1], values[2], values[3]);
  324. }
  325. default:
  326. {
  327. ErrorMsg(token, "not rotation or vector");
  328. return null;
  329. }
  330. }
  331. }
  332. if(token is TokenKwBrkOpen)
  333. {
  334. List<object> valuelist = new List<object>();
  335. while(!((token = token.nextToken) is TokenKwBrkClose))
  336. {
  337. if(!(token is TokenKwComma))
  338. {
  339. object value = ParseParamValue(ref token);
  340. if(value == null)
  341. return null;
  342. valuelist.Add(value);
  343. }
  344. else if(token.prevToken is TokenKwComma)
  345. {
  346. ErrorMsg(token, "missing constant");
  347. return null;
  348. }
  349. }
  350. return new LSL_List(valuelist.ToArray());
  351. }
  352. if(token is TokenName)
  353. {
  354. FieldInfo field = typeof(SharedScriptBaseClass).GetField(((TokenName)token).val);
  355. if((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly)))
  356. {
  357. return field.GetValue(null);
  358. }
  359. }
  360. ErrorMsg(token, "invalid constant");
  361. return null;
  362. }
  363. private bool youveanerror;
  364. private void ErrorMsg(Token token, string message)
  365. {
  366. youveanerror = true;
  367. m_log.Info("[YEngine]: " + token.posn + " " + message);
  368. }
  369. private void XmrTestReset(string[] args, int indx)
  370. {
  371. bool flagAll = false;
  372. int numScripts = 0;
  373. XMRInstance[] instances;
  374. if(args.Length <= indx)
  375. {
  376. m_log.Error("[YEngine]: must specify part of script name or -all for all scripts");
  377. return;
  378. }
  379. // Decode command line options.
  380. for(int i = indx; i < args.Length; i++)
  381. {
  382. if(args[i] == "-all")
  383. {
  384. flagAll = true;
  385. continue;
  386. }
  387. if(args[i] == "-help")
  388. {
  389. m_log.Info("[YEngine]: yeng reset -all | <part-of-script-name>");
  390. return;
  391. }
  392. if(args[i][0] == '-')
  393. {
  394. m_log.Error("[YEngine]: unknown option " + args[i] + ", try 'yeng reset -help'");
  395. return;
  396. }
  397. }
  398. // Scan instance list to find those that match selection criteria.
  399. if(!Monitor.TryEnter(m_InstancesDict, 100))
  400. {
  401. m_log.Error("[YEngine]: deadlock m_LockedDict=" + m_LockedDict);
  402. return;
  403. }
  404. try
  405. {
  406. instances = new XMRInstance[m_InstancesDict.Count];
  407. foreach(XMRInstance ins in m_InstancesDict.Values)
  408. {
  409. if(flagAll || InstanceMatchesArgs(ins, args, indx))
  410. {
  411. instances[numScripts++] = ins;
  412. }
  413. }
  414. }
  415. finally
  416. {
  417. Monitor.Exit(m_InstancesDict);
  418. }
  419. // Reset the instances as if someone clicked their "Reset" button.
  420. for(int i = 0; i < numScripts; i++)
  421. {
  422. XMRInstance inst = instances[i];
  423. m_log.Info("[YEngine]: resetting " + inst.m_DescName);
  424. inst.Reset();
  425. }
  426. }
  427. private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b)
  428. {
  429. if(a == null)
  430. {
  431. return (b == null) ? 0 : 1;
  432. }
  433. if(b == null)
  434. {
  435. return -1;
  436. }
  437. if(b.m_CPUTime < a.m_CPUTime)
  438. return -1;
  439. if(b.m_CPUTime > a.m_CPUTime)
  440. return 1;
  441. return 0;
  442. }
  443. private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx)
  444. {
  445. outFile.WriteLine("Queue " + name + ":");
  446. lock(queue)
  447. {
  448. for(XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst)
  449. {
  450. try
  451. {
  452. // Try to print instance name.
  453. if(InstanceMatchesArgs(inst, args, indx))
  454. {
  455. outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName);
  456. }
  457. }
  458. catch(Exception e)
  459. {
  460. // Sometimes there are instances in the queue that are disposed.
  461. outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message);
  462. }
  463. }
  464. }
  465. }
  466. private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx)
  467. {
  468. bool hadSomethingToCompare = false;
  469. for(int i = indx; i < args.Length; i++)
  470. {
  471. if(args[i][0] != '-')
  472. {
  473. hadSomethingToCompare = true;
  474. if(ins.m_DescName.Contains(args[i]))
  475. return true;
  476. if(ins.ItemID.ToString().Contains(args[i]))
  477. return true;
  478. if(ins.AssetID.ToString().Contains(args[i]))
  479. return true;
  480. }
  481. }
  482. return !hadSomethingToCompare;
  483. }
  484. }
  485. /**
  486. * @brief Make m_log.Info look like a text writer.
  487. */
  488. public class LogInfoTextWriter: TextWriter
  489. {
  490. private StringBuilder sb = new StringBuilder();
  491. private ILog m_log;
  492. public LogInfoTextWriter(ILog m_log)
  493. {
  494. this.m_log = m_log;
  495. }
  496. public override void Write(char c)
  497. {
  498. if(c == '\n')
  499. {
  500. m_log.Info("[YEngine]: " + sb.ToString());
  501. sb.Remove(0, sb.Length);
  502. }
  503. else
  504. {
  505. sb.Append(c);
  506. }
  507. }
  508. public override void Close()
  509. {
  510. }
  511. public override Encoding Encoding
  512. {
  513. get
  514. {
  515. return Encoding.UTF8;
  516. }
  517. }
  518. }
  519. }