OpenSimMirror/OpenSim/Region/ScriptEngine/YEngine/XMREngXmrTestLs.cs

579 lines
20 KiB
C#

/*
* 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.Yengine
{
public partial class Yengine
{
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("[YEngine]: xmr ls -full -max=<number> -out=<filename> -queues -topcpu");
return;
}
if(args[i].StartsWith("-max="))
{
try
{
maxScripts = Convert.ToInt32(args[i].Substring(5));
}
catch(Exception e)
{
m_log.Error("[YEngine]: 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("[YEngine]: 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("[YEngine]: error creating " + outName + ": " + e.Message);
return;
}
}
else
{
outFile = new LogInfoTextWriter(m_log);
}
try
{
/*
* Scan instance list to find those that match selection criteria.
*/
if(!Monitor.TryEnter(m_InstancesDict, 100))
{
m_log.Error("[YEngine]: 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<XMRInstance>(instances, CompareInstancesByCPUTime);
}
/*
* Print the entries.
*/
if(!flagFull)
{
outFile.WriteLine(" ItemID" +
" CPU(ms)" +
" NumEvents" +
" Status " +
" World Position " +
" <Part>:<Item>");
}
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<string> selargs = new List<string>(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("[YEngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
return;
}
if(arg[0] == '-')
{
m_log.Error("[YEngine]: 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("[YEngine]: missing <event-name> <params...>, 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("[YEngine]: 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("[YEngine]: 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<double> valuelist = new List<double>();
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<object> valuelist = new List<object>();
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("[YEngine]: " + 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("[YEngine]: 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("[YEngine]: xmr reset -all | <part-of-script-name>");
return;
}
if(args[i][0] == '-')
{
m_log.Error("[YEngine]: 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("[YEngine]: 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("[YEngine]: 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("[YEngine]: " + sb.ToString());
sb.Remove(0, sb.Length);
}
else
{
sb.Append(c);
}
}
public override void Close()
{
}
public override Encoding Encoding
{
get
{
return Encoding.UTF8;
}
}
}
}