Added event method invoke cache to Executor. "Bind once, Invoke multiple times". Will speed up script event execution considerable. But at the cost of some memory (will be optimized later with RuntimeXHandle).

afrisby
Tedd Hansen 2007-08-19 10:28:27 +00:00
parent 1893164d26
commit e70cdbc5ac
3 changed files with 70 additions and 39 deletions

View File

@ -5,7 +5,7 @@ using System.Reflection;
namespace OpenSim.Region.ScriptEngine.Common namespace OpenSim.Region.ScriptEngine.Common
{ {
public class Executor: MarshalByRefObject public class Executor : MarshalByRefObject
{ {
/* TODO: /* TODO:
* *
@ -16,10 +16,12 @@ namespace OpenSim.Region.ScriptEngine.Common
*/ */
private IScript m_Script; private IScript m_Script;
private Dictionary<string, MethodInfo> Events = new Dictionary<string, MethodInfo>();
public Executor(IScript Script) public Executor(IScript Script)
{ {
m_Script = Script; m_Script = Script;
} }
public void ExecuteEvent(string FunctionName, object[] args) public void ExecuteEvent(string FunctionName, object[] args)
{ {
@ -34,23 +36,51 @@ namespace OpenSim.Region.ScriptEngine.Common
//} //}
//} //}
Type type = m_Script.GetType();
Console.WriteLine("ScriptEngine Executor.ExecuteEvent: \"" + m_Script.State() + "_event_" + FunctionName + "\"");
string EventName = m_Script.State() + "_event_" + FunctionName;
//type.InvokeMember(EventName, BindingFlags.InvokeMethod, null, m_Script, args);
Console.WriteLine("ScriptEngine Executor.ExecuteEvent: \"" + EventName + "\"");
if (Events.ContainsKey(EventName) == false)
{
// Not found, create
Type type = m_Script.GetType();
try
{
MethodInfo mi = type.GetMethod(EventName);
Events.Add(EventName, mi);
}
catch (Exception e)
{
// Event name not found, cache it as not found
Events.Add(EventName, null);
}
}
// Get event
MethodInfo ev = null;
Events.TryGetValue(EventName, out ev);
if (ev == null) // No event by that name!
return;
// Found
try try
{ {
type.InvokeMember(m_Script.State() + "_event_" + FunctionName, BindingFlags.InvokeMethod, null, m_Script, args); // Invoke it
ev.Invoke(m_Script, args);
} }
catch (Exception e) catch (Exception e)
{ {
// TODO: Send to correct place // TODO: Send to correct place
Console.WriteLine("ScriptEngine Exception attempting to executing script function: " + e.ToString()); Console.WriteLine("ScriptEngine Exception attempting to executing script function: " + e.ToString());
} }
} }
} }
} }

View File

@ -14,7 +14,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
{ {
public class AppDomainManager public class AppDomainManager
{ {
private int MaxScriptsPerAppDomain = 1; private int MaxScriptsPerAppDomain = 3;
/// <summary> /// <summary>
/// Internal list of all AppDomains /// Internal list of all AppDomains
/// </summary> /// </summary>
@ -22,7 +22,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
/// <summary> /// <summary>
/// Structure to keep track of data around AppDomain /// Structure to keep track of data around AppDomain
/// </summary> /// </summary>
private struct AppDomainStructure private class AppDomainStructure
{ {
/// <summary> /// <summary>
/// The AppDomain itself /// The AppDomain itself
@ -57,33 +57,25 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
/// <returns>Free AppDomain</returns> /// <returns>Free AppDomain</returns>
private AppDomainStructure GetFreeAppDomain() private AppDomainStructure GetFreeAppDomain()
{ {
FreeAppDomains(); FreeAppDomains(); // Outsite lock, has its own GetLock
lock(GetLock) { lock (GetLock)
{
// Current full? // Current full?
if (CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain) if (CurrentAD != null && CurrentAD.ScriptsLoaded >= MaxScriptsPerAppDomain)
{ {
// Add it to AppDomains list and empty current // Add it to AppDomains list and empty current
AppDomains.Add(CurrentAD); AppDomains.Add(CurrentAD);
CurrentAD = new AppDomainStructure(); CurrentAD = null;
} }
// No current // No current
if (CurrentAD.CurrentAppDomain == null) if (CurrentAD == null)
{ {
// Create a new current AppDomain // Create a new current AppDomain
CurrentAD = new AppDomainStructure(); CurrentAD = new AppDomainStructure();
CurrentAD.ScriptsWaitingUnload = 0; // to avoid compile warning for not in use
CurrentAD.CurrentAppDomain = PrepareNewAppDomain(); CurrentAD.CurrentAppDomain = PrepareNewAppDomain();
} }
// Increase number of scripts loaded into this Console.WriteLine("Scripts loaded in this Appdomain: " + CurrentAD.ScriptsLoaded);
// TODO:
// - We assume that every time someone wants an AppDomain they will load into it
// if this assumption is wrong we end up with a miscount and will never unload it.
//
// Return AppDomain
return CurrentAD; return CurrentAD;
} // lock } // lock
} }
@ -143,19 +135,18 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
public OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass LoadScript(string FileName, IScriptHost host) public OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass LoadScript(string FileName)
{ {
//LSL_BaseClass mbrt = (LSL_BaseClass)FreeAppDomain.CreateInstanceAndUnwrap(FileName, "SecondLife.Script"); // Find next available AppDomain to put it in
//Console.WriteLine("Base directory: " + AppDomain.CurrentDomain.BaseDirectory);
// * Find next available AppDomain to put it in
AppDomainStructure FreeAppDomain = GetFreeAppDomain(); AppDomainStructure FreeAppDomain = GetFreeAppDomain();
if (FreeAppDomain == null) Console.WriteLine("FreeAppDomain == null");
if (FreeAppDomain.CurrentAppDomain == null) Console.WriteLine("FreeAppDomain.CurrentAppDomain == null");
LSL_BaseClass mbrt = (LSL_BaseClass)FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script"); LSL_BaseClass mbrt = (LSL_BaseClass)FreeAppDomain.CurrentAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
//LSL_BuiltIn_Commands_Interface mbrt = (LSL_BuiltIn_Commands_Interface)FreeAppDomain.CreateInstanceFromAndUnwrap(FileName, "SecondLife.Script");
//Type mytype = mbrt.GetType(); //Type mytype = mbrt.GetType();
//Console.WriteLine("is proxy={0}", RemotingServices.IsTransparentProxy(mbrt)); Console.WriteLine("ScriptEngine AppDomainManager: is proxy={0}", RemotingServices.IsTransparentProxy(mbrt));
// Increase script count in tihs AppDomain
FreeAppDomain.ScriptsLoaded++; FreeAppDomain.ScriptsLoaded++;
//mbrt.Start(); //mbrt.Start();
@ -169,7 +160,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
/// Increase "dead script" counter for an AppDomain /// Increase "dead script" counter for an AppDomain
/// </summary> /// </summary>
/// <param name="ad"></param> /// <param name="ad"></param>
[Obsolete("Needs fixing!!!")] [Obsolete("Needs fixing, needs a real purpose in life!!!")]
public void StopScript(AppDomain ad) public void StopScript(AppDomain ad)
{ {
lock (FreeLock) lock (FreeLock)
@ -188,10 +179,10 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
if (ads.CurrentAppDomain == ad) if (ads.CurrentAppDomain == ad)
{ {
// Found it - messy code to increase structure // Found it - messy code to increase structure
AppDomainStructure ads2 = ads; //AppDomainStructure ads2 = ads;
ads2.ScriptsWaitingUnload++; ads.ScriptsWaitingUnload++;
AppDomains.Remove(ads); //AppDomains.Remove(ads);
AppDomains.Add(ads2); //AppDomains.Add(ads2);
return; return;
} }
} // foreach } // foreach

View File

@ -34,6 +34,7 @@ using System.Reflection;
using System.Runtime.Remoting; using System.Runtime.Remoting;
using OpenSim.Region.Environment.Scenes; using OpenSim.Region.Environment.Scenes;
using OpenSim.Region.Environment.Scenes.Scripting; using OpenSim.Region.Environment.Scenes.Scripting;
using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler;
using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL; using OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL;
using OpenSim.Region.ScriptEngine.Common; using OpenSim.Region.ScriptEngine.Common;
@ -176,7 +177,16 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
//OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSO.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName); //OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSO.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName);
//OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName, ObjectID); //OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = LoadAndInitAssembly(FreeAppDomain, FileName, ObjectID);
OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL.LSL_BaseClass Script = m_scriptEngine.myAppDomainManager.LoadScript(FileName, ObjectID); long before;
before = GC.GetTotalMemory(true);
LSL_BaseClass Script = m_scriptEngine.myAppDomainManager.LoadScript(FileName);
Console.WriteLine("Script occupies {0} bytes", GC.GetTotalMemory(true) - before);
before = GC.GetTotalMemory(true);
Script = m_scriptEngine.myAppDomainManager.LoadScript(FileName);
Console.WriteLine("Script occupies {0} bytes", GC.GetTotalMemory(true) - before);
before = GC.GetTotalMemory(true);
Script = m_scriptEngine.myAppDomainManager.LoadScript(FileName);
Console.WriteLine("Script occupies {0} bytes", GC.GetTotalMemory(true) - before);
// Add it to our temporary active script keeper // Add it to our temporary active script keeper
@ -184,7 +194,7 @@ namespace OpenSim.Region.ScriptEngine.DotNetEngine
SetScript(ObjectID, ScriptID, Script); SetScript(ObjectID, ScriptID, Script);
// We need to give (untrusted) assembly a private instance of BuiltIns // We need to give (untrusted) assembly a private instance of BuiltIns
// this private copy will contain Read-Only FullScriptID so that it can bring that on to the server whenever needed. // this private copy will contain Read-Only FullScriptID so that it can bring that on to the server whenever needed.
OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands LSLB = new OpenSim.Region.ScriptEngine.DotNetEngine.Compiler.LSL_BuiltIn_Commands(this, ObjectID); LSL_BuiltIn_Commands LSLB = new LSL_BuiltIn_Commands(this, ObjectID);
// Start the script - giving it BuiltIns // Start the script - giving it BuiltIns
Script.Start(LSLB); Script.Start(LSLB);