/* * Copyright (c) Contributors, http://opensimulator.org/ * See CONTRIBUTORS.TXT for a full list of copyright holders. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of the OpenSimulator Project nor the * names of its contributors may be used to endorse or promote products * derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ using log4net; using System; using System.Collections.Generic; using System.IO; using System.Reflection; using System.Text; using System.Threading; using LSL_Float = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLFloat; using LSL_Integer = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLInteger; using LSL_Key = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_List = OpenSim.Region.ScriptEngine.Shared.LSL_Types.list; using LSL_Rotation = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Quaternion; using LSL_String = OpenSim.Region.ScriptEngine.Shared.LSL_Types.LSLString; using LSL_Vector = OpenSim.Region.ScriptEngine.Shared.LSL_Types.Vector3; namespace OpenSim.Region.ScriptEngine.XMREngine { public partial class XMREngine { private void XmrTestLs (string[] args, int indx) { bool flagFull = false; bool flagQueues = false; bool flagTopCPU = false; int maxScripts = 0x7FFFFFFF; int numScripts = 0; string outName = null; XMRInstance[] instances; /* * Decode command line options. */ for (int i = indx; i < args.Length; i ++) { if (args[i] == "-full") { flagFull = true; continue; } if (args[i] == "-help") { m_log.Info ("[XMREngine]: xmr ls -full -max= -out= -queues -topcpu"); return; } if (args[i].StartsWith("-max=")) { try { maxScripts = Convert.ToInt32(args[i].Substring(5)); } catch (Exception e) { m_log.Error("[XMREngine]: bad max " + args[i].Substring(5) + ": " + e.Message); return; } continue; } if (args[i].StartsWith("-out=")) { outName = args[i].Substring(5); continue; } if (args[i] == "-queues") { flagQueues = true; continue; } if (args[i] == "-topcpu") { flagTopCPU = true; continue; } if (args[i][0] == '-') { m_log.Error("[XMREngine]: unknown option " + args[i] + ", try 'xmr ls -help'"); return; } } TextWriter outFile = null; if (outName != null) { try { outFile = File.CreateText(outName); } catch (Exception e) { m_log.Error("[XMREngine]: error creating " + outName + ": " + e.Message); return; } } else { outFile = new LogInfoTextWriter(m_log); } try { for (int i = 0; i < numThreadScriptWorkers; i ++) { XMRScriptThread th = m_ScriptThreads[i]; outFile.WriteLine("Script thread ID: " + th.m_ScriptThreadTID); long execTime = th.m_ScriptExecTime; if (execTime < 0) { execTime += (long)(DateTime.UtcNow - DateTime.MinValue).TotalMilliseconds; } outFile.WriteLine(" execution time: " + execTime + " mS"); outFile.WriteLine(" last ran at: " + th.m_LastRanAt.ToString()); XMRInstance rins = th.m_RunInstance; if (rins != null) { outFile.WriteLine(" running: " + rins.ItemID.ToString() + " " + rins.m_DescName); if (flagFull) { outFile.WriteLine (rins.RunTestLs (true)); } } } /* * Scan instance list to find those that match selection criteria. */ if (!Monitor.TryEnter(m_InstancesDict, 100)) { m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict); return; } try { instances = new XMRInstance[m_InstancesDict.Count]; foreach (XMRInstance ins in m_InstancesDict.Values) { if (InstanceMatchesArgs(ins, args, indx)) { instances[numScripts++] = ins; } } } finally { Monitor.Exit(m_InstancesDict); } /* * Maybe sort by descending CPU time. */ if (flagTopCPU) { Array.Sort(instances, CompareInstancesByCPUTime); } /* * Print the entries. */ if (!flagFull) { outFile.WriteLine(" ItemID" + " CPU(ms)" + " NumEvents" + " Status " + " World Position " + " :"); } for (int i = 0; (i < numScripts) && (i < maxScripts); i ++) { outFile.WriteLine(instances[i].RunTestLs(flagFull)); } /* * Print number of scripts that match selection criteria, * even if we were told to print fewer. */ outFile.WriteLine("total of {0} script(s)", numScripts); /* * If -queues given, print out queue contents too. */ if (flagQueues) { LsQueue(outFile, "start", m_StartQueue, args, indx); LsQueue(outFile, "sleep", m_SleepQueue, args, indx); LsQueue(outFile, "yield", m_YieldQueue, args, indx); } } finally { outFile.Close(); } } private void XmrTestPev (string[] args, int indx) { bool flagAll = false; int numScripts = 0; XMRInstance[] instances; /* * Decode command line options. */ int i, j; List selargs = new List (args.Length); MethodInfo[] eventmethods = typeof (IEventHandlers).GetMethods (); MethodInfo eventmethod; for (i = indx; i < args.Length; i ++) { string arg = args[i]; if (arg == "-all") { flagAll = true; continue; } if (arg == "-help") { m_log.Info ("[XMREngine]: xmr pev -all | "); return; } if (arg[0] == '-') { m_log.Error ("[XMREngine]: unknown option " + arg + ", try 'xmr pev -help'"); return; } for (j = 0; j < eventmethods.Length; j ++) { eventmethod = eventmethods[j]; if (eventmethod.Name == arg) goto gotevent; } selargs.Add (arg); } m_log.Error ("[XMREngine]: missing , try 'xmr pev -help'"); return; gotevent: string eventname = eventmethod.Name; StringBuilder sourcesb = new StringBuilder (); while (++ i < args.Length) { sourcesb.Append (' '); sourcesb.Append (args[i]); } string sourcest = sourcesb.ToString (); string sourcehash; youveanerror = false; Token t = TokenBegin.Construct ("", null, ErrorMsg, sourcest, out sourcehash); if (youveanerror) return; ParameterInfo[] paraminfos = eventmethod.GetParameters (); object[] paramvalues = new object[paraminfos.Length]; i = 0; while (!((t = t.nextToken) is TokenEnd)) { if (i >= paramvalues.Length) { ErrorMsg (t, "extra parameter(s)"); return; } paramvalues[i] = ParseParamValue (ref t); if (paramvalues[i] == null) return; i ++; } OpenSim.Region.ScriptEngine.Shared.EventParams eps = new OpenSim.Region.ScriptEngine.Shared.EventParams (eventname, paramvalues, zeroDetectParams); /* * Scan instance list to find those that match selection criteria. */ if (!Monitor.TryEnter(m_InstancesDict, 100)) { m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict); return; } try { instances = new XMRInstance[m_InstancesDict.Count]; foreach (XMRInstance ins in m_InstancesDict.Values) { if (flagAll || InstanceMatchesArgs (ins, selargs.ToArray (), 0)) { instances[numScripts++] = ins; } } } finally { Monitor.Exit(m_InstancesDict); } /* * Post event to the matching instances. */ for (i = 0; i < numScripts; i ++) { XMRInstance inst = instances[i]; m_log.Info ("[XMREngine]: post " + eventname + " to " + inst.m_DescName); inst.PostEvent (eps); } } private object ParseParamValue (ref Token token) { if (token is TokenFloat) { return new LSL_Float (((TokenFloat)token).val); } if (token is TokenInt) { return new LSL_Integer (((TokenInt)token).val); } if (token is TokenStr) { return new LSL_String (((TokenStr)token).val); } if (token is TokenKwCmpLT) { List valuelist = new List (); while (!((token = token.nextToken) is TokenKwCmpGT)) { if (!(token is TokenKwComma)) { object value = ParseParamValue (ref token); if (value == null) return null; if (value is int) value = (double)(int)value; if (!(value is double)) { ErrorMsg (token, "must be float or integer constant"); return null; } valuelist.Add ((double)value); } else if (token.prevToken is TokenKwComma) { ErrorMsg (token, "missing constant"); return null; } } double[] values = valuelist.ToArray (); switch (values.Length) { case 3: { return new LSL_Vector (values[0], values[1], values[2]); } case 4: { return new LSL_Rotation (values[0], values[1], values[2], values[3]); } default: { ErrorMsg (token, "not rotation or vector"); return null; } } } if (token is TokenKwBrkOpen) { List valuelist = new List (); while (!((token = token.nextToken) is TokenKwBrkClose)) { if (!(token is TokenKwComma)) { object value = ParseParamValue (ref token); if (value == null) return null; valuelist.Add (value); } else if (token.prevToken is TokenKwComma) { ErrorMsg (token, "missing constant"); return null; } } return new LSL_List (valuelist.ToArray ()); } if (token is TokenName) { FieldInfo field = typeof (OpenSim.Region.ScriptEngine.Shared.ScriptBase.ScriptBaseClass).GetField (((TokenName)token).val); if ((field != null) && field.IsPublic && (field.IsLiteral || (field.IsStatic && field.IsInitOnly))) { return field.GetValue (null); } } ErrorMsg (token, "invalid constant"); return null; } private bool youveanerror; private void ErrorMsg (Token token, string message) { youveanerror = true; m_log.Info ("[XMREngine]: " + token.posn + " " + message); } private void XmrTestReset (string[] args, int indx) { bool flagAll = false; int numScripts = 0; XMRInstance[] instances; if (args.Length <= indx) { m_log.Error("[XMREngine]: must specify part of script name or -all for all scripts"); return; } /* * Decode command line options. */ for (int i = indx; i < args.Length; i ++) { if (args[i] == "-all") { flagAll = true; continue; } if (args[i] == "-help") { m_log.Info ("[XMREngine]: xmr reset -all | "); return; } if (args[i][0] == '-') { m_log.Error ("[XMREngine]: unknown option " + args[i] + ", try 'xmr reset -help'"); return; } } /* * Scan instance list to find those that match selection criteria. */ if (!Monitor.TryEnter(m_InstancesDict, 100)) { m_log.Error("[XMREngine]: deadlock m_LockedDict=" + m_LockedDict); return; } try { instances = new XMRInstance[m_InstancesDict.Count]; foreach (XMRInstance ins in m_InstancesDict.Values) { if (flagAll || InstanceMatchesArgs (ins, args, indx)) { instances[numScripts++] = ins; } } } finally { Monitor.Exit(m_InstancesDict); } /* * Reset the instances as if someone clicked their "Reset" button. */ for (int i = 0; i < numScripts; i ++) { XMRInstance inst = instances[i]; m_log.Info ("[XMREngine]: resetting " + inst.m_DescName); inst.Reset(); } } private static int CompareInstancesByCPUTime(XMRInstance a, XMRInstance b) { if (a == null) { return (b == null) ? 0 : 1; } if (b == null) { return -1; } if (b.m_CPUTime < a.m_CPUTime) return -1; if (b.m_CPUTime > a.m_CPUTime) return 1; return 0; } private void LsQueue(TextWriter outFile, string name, XMRInstQueue queue, string[] args, int indx) { outFile.WriteLine("Queue " + name + ":"); lock (queue) { for (XMRInstance inst = queue.PeekHead(); inst != null; inst = inst.m_NextInst) { try { /* * Try to print instance name. */ if (InstanceMatchesArgs(inst, args, indx)) { outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName); } } catch (Exception e) { /* * Sometimes there are instances in the queue that are disposed. */ outFile.WriteLine(" " + inst.ItemID.ToString() + " " + inst.m_DescName + ": " + e.Message); } } } } private bool InstanceMatchesArgs(XMRInstance ins, string[] args, int indx) { bool hadSomethingToCompare = false; for (int i = indx; i < args.Length; i ++) { if (args[i][0] != '-') { hadSomethingToCompare = true; if (ins.m_DescName.Contains(args[i])) return true; if (ins.ItemID.ToString().Contains(args[i])) return true; if (ins.AssetID.ToString().Contains(args[i])) return true; } } return !hadSomethingToCompare; } } /** * @brief Make m_log.Info look like a text writer. */ public class LogInfoTextWriter : TextWriter { private StringBuilder sb = new StringBuilder(); private ILog m_log; public LogInfoTextWriter (ILog m_log) { this.m_log = m_log; } public override void Write (char c) { if (c == '\n') { m_log.Info("[XMREngine]: " + sb.ToString()); sb.Remove(0, sb.Length); } else { sb.Append(c); } } public override void Close () { } public override Encoding Encoding { get { return Encoding.UTF8; } } } }