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

492 lines
19 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.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=<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("[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<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 ("[XMREngine]: xmr pev -all | <part-of-script-name> <event-name> <params...>");
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 <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("[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<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 ("[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 | <part-of-script-name>");
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;
}
}
}
}