Optimizations

0.6.8-post-fixes
Dan Lake 2009-10-26 07:50:25 -07:00 committed by John Hurliman
parent 5c894dac8b
commit 33448e4ba8
5 changed files with 124 additions and 119 deletions

View File

@ -34,9 +34,7 @@ namespace OpenSim.Region.ScriptEngine.Interfaces
{
public interface ICompiler
{
object PerformScriptCompile(string source, string asset, UUID ownerID);
void PerformScriptCompile(string source, string asset, UUID ownerID, out string assembly, out Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap);
string[] GetWarnings();
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
LineMap();
}
}

View File

@ -113,7 +113,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.ScriptBase
return;
//ILease lease = (ILease)RemotingServices.GetLifetimeService(data as MarshalByRefObject);
RemotingServices.GetLifetimeService(data as MarshalByRefObject);
//RemotingServices.GetLifetimeService(data as MarshalByRefObject);
// lease.Register(m_sponser);
MethodInfo mi = inits[api];

View File

@ -74,7 +74,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
private string FilePrefix;
private string ScriptEnginesPath = "ScriptEngines";
// mapping between LSL and C# line/column numbers
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> m_positionMap;
private ICodeConverter LSL_Converter;
private List<string> m_warnings = new List<string>();
@ -91,6 +90,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
private static UInt64 scriptCompileCounter = 0; // And a counter
public IScriptEngine m_scriptEngine;
private Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>> m_lineMaps =
new Dictionary<string, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>>();
public Compiler(IScriptEngine scriptEngine)
{
m_scriptEngine = scriptEngine;
@ -271,16 +273,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// </summary>
/// <param name="Script">LSL script</param>
/// <returns>Filename to .dll assembly</returns>
public object PerformScriptCompile(string Script, string asset, UUID ownerUUID)
public void PerformScriptCompile(string Script, string asset, UUID ownerUUID,
out string assembly, out Dictionary<KeyValuePair<int,int>, KeyValuePair<int,int>> linemap)
{
m_positionMap = null;
linemap = null;
m_warnings.Clear();
string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
assembly = Path.Combine(ScriptEnginesPath, Path.Combine(
m_scriptEngine.World.RegionInfo.RegionID.ToString(),
FilePrefix + "_compiled_" + asset + ".dll"));
// string OutFile = Path.Combine(ScriptEnginesPath,
// FilePrefix + "_compiled_" + asset + ".dll");
if (!Directory.Exists(ScriptEnginesPath))
{
@ -305,51 +306,53 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
}
}
// Don't recompile if we already have it
// Performing 3 file exists tests for every script can still be slow
if (File.Exists(assembly) && File.Exists(assembly + ".text") && File.Exists(assembly + ".map"))
{
// If we have already read this linemap file, then it will be in our dictionary.
// Don't build another copy of the dictionary (saves memory) and certainly
// don't keep reading the same file from disk multiple times.
if (!m_lineMaps.ContainsKey(assembly))
m_lineMaps[assembly] = ReadMapFile(assembly + ".map");
linemap = m_lineMaps[assembly];
return;
}
if (Script == String.Empty)
{
if (File.Exists(OutFile))
return OutFile;
throw new Exception("Cannot find script assembly and no script text present");
}
// Don't recompile if we already have it
//
if (File.Exists(OutFile) && File.Exists(OutFile+".text") && File.Exists(OutFile+".map"))
{
ReadMapFile(OutFile+".map");
return OutFile;
}
enumCompileType l = DefaultCompileLanguage;
enumCompileType language = DefaultCompileLanguage;
if (Script.StartsWith("//c#", true, CultureInfo.InvariantCulture))
l = enumCompileType.cs;
language = enumCompileType.cs;
if (Script.StartsWith("//vb", true, CultureInfo.InvariantCulture))
{
l = enumCompileType.vb;
language = enumCompileType.vb;
// We need to remove //vb, it won't compile with that
Script = Script.Substring(4, Script.Length - 4);
}
if (Script.StartsWith("//lsl", true, CultureInfo.InvariantCulture))
l = enumCompileType.lsl;
language = enumCompileType.lsl;
if (Script.StartsWith("//js", true, CultureInfo.InvariantCulture))
l = enumCompileType.js;
language = enumCompileType.js;
if (Script.StartsWith("//yp", true, CultureInfo.InvariantCulture))
l = enumCompileType.yp;
language = enumCompileType.yp;
if (!AllowedCompilers.ContainsKey(l.ToString()))
if (!AllowedCompilers.ContainsKey(language.ToString()))
{
// Not allowed to compile to this language!
string errtext = String.Empty;
errtext += "The compiler for language \"" + l.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
errtext += "The compiler for language \"" + language.ToString() + "\" is not in list of allowed compilers. Script will not be executed!";
throw new Exception(errtext);
}
if (m_scriptEngine.World.Permissions.CanCompileScript(ownerUUID, (int)l) == false) {
if (m_scriptEngine.World.Permissions.CanCompileScript(ownerUUID, (int)language) == false) {
// Not allowed to compile to this language!
string errtext = String.Empty;
errtext += ownerUUID + " is not in list of allowed users for this scripting language. Script will not be executed!";
@ -358,7 +361,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
string compileScript = Script;
if (l == enumCompileType.lsl)
if (language == enumCompileType.lsl)
{
// Its LSL, convert it to C#
LSL_Converter = (ICodeConverter)new CSCodeGenerator();
@ -370,16 +373,19 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
AddWarning(warning);
}
m_positionMap = ((CSCodeGenerator) LSL_Converter).PositionMap;
linemap = ((CSCodeGenerator) LSL_Converter).PositionMap;
// Write the linemap to a file and save it in our dictionary for next time.
m_lineMaps[assembly] = linemap;
WriteMapFile(assembly + ".map", linemap);
}
if (l == enumCompileType.yp)
if (language == enumCompileType.yp)
{
// Its YP, convert it to C#
compileScript = YP_Converter.Convert(Script);
}
switch (l)
switch (language)
{
case enumCompileType.cs:
case enumCompileType.lsl:
@ -396,7 +402,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
break;
}
return CompileFromDotNetText(compileScript, l, asset);
assembly = CompileFromDotNetText(compileScript, language, asset, assembly);
return;
}
public string[] GetWarnings()
@ -468,18 +475,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
/// </summary>
/// <param name="Script">CS script</param>
/// <returns>Filename to .dll assembly</returns>
internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset)
internal string CompileFromDotNetText(string Script, enumCompileType lang, string asset, string assembly)
{
string ext = "." + lang.ToString();
// Output assembly name
scriptCompileCounter++;
string OutFile = Path.Combine(ScriptEnginesPath, Path.Combine(
m_scriptEngine.World.RegionInfo.RegionID.ToString(),
FilePrefix + "_compiled_" + asset + ".dll"));
try
{
File.Delete(OutFile);
File.Delete(assembly);
}
catch (Exception e) // NOTLEGIT - Should be just FileIOException
{
@ -492,7 +496,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
if (WriteScriptSourceToDebugFile)
{
string srcFileName = FilePrefix + "_source_" +
Path.GetFileNameWithoutExtension(OutFile) + ext;
Path.GetFileNameWithoutExtension(assembly) + ext;
try
{
File.WriteAllText(Path.Combine(Path.Combine(
@ -528,7 +532,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
}
parameters.GenerateExecutable = false;
parameters.OutputAssembly = OutFile;
parameters.OutputAssembly = assembly;
parameters.IncludeDebugInformation = CompileWithDebugInformation;
//parameters.WarningLevel = 1; // Should be 4?
parameters.TreatWarningsAsErrors = false;
@ -609,7 +613,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
if (severity == "Error")
{
lslPos = FindErrorPosition(CompErr.Line, CompErr.Column);
lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
string text = CompErr.ErrorText;
// Use LSL type names
@ -635,14 +639,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
// the compile may not be immediately apparent. Wait a
// reasonable amount of time before giving up on it.
if (!File.Exists(OutFile))
if (!File.Exists(assembly))
{
for (int i=0; i<20 && !File.Exists(OutFile); i++)
for (int i=0; i<20 && !File.Exists(assembly); i++)
{
System.Threading.Thread.Sleep(250);
}
// One final chance...
if (!File.Exists(OutFile))
if (!File.Exists(assembly))
{
errtext = String.Empty;
errtext += "No compile error. But not able to locate compiled file.";
@ -658,7 +662,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
//
// Read the binary file into a buffer
//
FileInfo fi = new FileInfo(OutFile);
FileInfo fi = new FileInfo(assembly);
if (fi == null)
{
@ -671,7 +675,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
try
{
FileStream fs = File.Open(OutFile, FileMode.Open, FileAccess.Read);
FileStream fs = File.Open(assembly, FileMode.Open, FileAccess.Read);
fs.Read(data, 0, data.Length);
fs.Close();
}
@ -690,34 +694,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
Byte[] buf = enc.GetBytes(filetext);
FileStream sfs = File.Create(OutFile+".text");
FileStream sfs = File.Create(assembly+".text");
sfs.Write(buf, 0, buf.Length);
sfs.Close();
string posmap = String.Empty;
if (m_positionMap != null)
{
foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>> kvp in m_positionMap)
{
KeyValuePair<int, int> k = kvp.Key;
KeyValuePair<int, int> v = kvp.Value;
posmap += String.Format("{0},{1},{2},{3}\n",
k.Key, k.Value, v.Key, v.Value);
}
}
buf = enc.GetBytes(posmap);
FileStream mfs = File.Create(OutFile+".map");
mfs.Write(buf, 0, buf.Length);
mfs.Close();
return OutFile;
}
public KeyValuePair<int, int> FindErrorPosition(int line, int col)
{
return FindErrorPosition(line, col, m_positionMap);
return assembly;
}
private class kvpSorter : IComparer<KeyValuePair<int,int>>
@ -791,27 +772,32 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
return message;
}
public Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> LineMap()
private static void WriteMapFile(string filename, Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap)
{
if (m_positionMap == null)
return null;
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> ret =
new Dictionary<KeyValuePair<int,int>, KeyValuePair<int, int>>();
foreach (KeyValuePair<int, int> kvp in m_positionMap.Keys)
ret.Add(kvp, m_positionMap[kvp]);
return ret;
string mapstring = String.Empty;
foreach (KeyValuePair<KeyValuePair<int, int>, KeyValuePair<int, int>> kvp in linemap)
{
KeyValuePair<int, int> k = kvp.Key;
KeyValuePair<int, int> v = kvp.Value;
mapstring += String.Format("{0},{1},{2},{3}\n", k.Key, k.Value, v.Key, v.Value);
}
System.Text.ASCIIEncoding enc = new System.Text.ASCIIEncoding();
Byte[] mapbytes = enc.GetBytes(mapstring);
FileStream mfs = File.Create(filename);
mfs.Write(mapbytes, 0, mapbytes.Length);
mfs.Close();
}
private void ReadMapFile(string filename)
private static Dictionary<KeyValuePair<int,int>, KeyValuePair<int,int>> ReadMapFile(string filename)
{
Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>> linemap;
try
{
StreamReader r = File.OpenText(filename);
m_positionMap = new Dictionary<KeyValuePair<int,int>, KeyValuePair<int, int>>();
linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
string line;
while ((line = r.ReadLine()) != null)
@ -825,12 +811,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.CodeTools
KeyValuePair<int, int> k = new KeyValuePair<int, int>(kk, kv);
KeyValuePair<int, int> v = new KeyValuePair<int, int>(vk, vv);
m_positionMap[k] = v;
linemap[k] = v;
}
}
catch
{
linemap = new Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>();
}
return linemap;
}
}
}

View File

@ -93,7 +93,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
private StateSource m_stateSource;
private bool m_postOnRez;
private bool m_startedFromSavedState = false;
private string m_CurrentState = String.Empty;
private int m_CurrentStateHash;
private UUID m_RegionID = UUID.Zero;
private Dictionary<KeyValuePair<int, int>, KeyValuePair<int, int>>
@ -252,16 +252,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
{
m_Apis[api] = am.CreateApi(api);
m_Apis[api].Initialize(engine, part, m_LocalID, itemID);
}
}
try
{
if (dom != System.AppDomain.CurrentDomain)
m_Script = (IScript)dom.CreateInstanceAndUnwrap(
Path.GetFileNameWithoutExtension(assembly),
"SecondLife.Script");
else
m_Script = (IScript)Assembly.Load(
Path.GetFileNameWithoutExtension(assembly)).CreateInstance(
"SecondLife.Script");
try
{
m_Script = (IScript)dom.CreateInstanceAndUnwrap(
Path.GetFileNameWithoutExtension(assembly),
"SecondLife.Script");
//ILease lease = (ILease)RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
//RemotingServices.GetLifetimeService(m_Script as ScriptBaseClass);
// lease.Register(this);
}
catch (Exception)
@ -893,7 +899,9 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
string xml = ScriptSerializer.Serialize(this);
if (m_CurrentState != xml)
// Compare hash of the state we just just created with the state last written to disk
// If the state is different, update the disk file.
if(xml.GetHashCode() != m_CurrentStateHash)
{
try
{
@ -911,7 +919,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance
//{
// throw new Exception("Completed persistence save, but no file was created");
//}
m_CurrentState = xml;
m_CurrentStateHash = xml.GetHashCode();
}
}

View File

@ -73,9 +73,11 @@ namespace OpenSim.Region.ScriptEngine.XEngine
private bool m_InitialStartup = true;
private int m_ScriptFailCount; // Number of script fails since compile queue was last empty
private string m_ScriptErrorMessage;
private Dictionary<string, string> m_uniqueScripts = new Dictionary<string, string>();
private bool m_AppDomainLoading;
// disable warning: need to keep a reference to XEngine.EventManager
// alive to avoid it being garbage collected
// disable warning: need to keep a reference to XEngine.EventManager
// alive to avoid it being garbage collected
#pragma warning disable 414
private EventManager m_EventManager;
#pragma warning restore 414
@ -201,6 +203,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
m_MaxScriptQueue = m_ScriptConfig.GetInt("MaxScriptEventQueue",300);
m_StackSize = m_ScriptConfig.GetInt("ThreadStackSize", 262144);
m_SleepTime = m_ScriptConfig.GetInt("MaintenanceInterval", 10) * 1000;
m_AppDomainLoading = m_ScriptConfig.GetBoolean("AppDomainLoading", true);
m_EventLimit = m_ScriptConfig.GetInt("EventLimit", 30);
m_KillTimedOutScripts = m_ScriptConfig.GetBoolean("KillTimedOutScripts", false);
@ -470,6 +473,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
if (engine != ScriptEngineName)
return;
// If we've seen this exact script text before, use that reference instead
if (m_uniqueScripts.ContainsKey(script))
script = m_uniqueScripts[script];
else
m_uniqueScripts[script] = script;
Object[] parms = new Object[]{localID, itemID, script, startParam, postOnRez, (StateSource)stateSource};
if (stateSource == (int)StateSource.ScriptedRez)
@ -590,14 +599,12 @@ namespace OpenSim.Region.ScriptEngine.XEngine
{
lock (m_AddingAssemblies)
{
assembly = (string)m_Compiler.PerformScriptCompile(script,
assetID.ToString(), item.OwnerID);
m_Compiler.PerformScriptCompile(script, assetID.ToString(), item.OwnerID, out assembly, out linemap);
if (!m_AddingAssemblies.ContainsKey(assembly)) {
m_AddingAssemblies[assembly] = 1;
} else {
m_AddingAssemblies[assembly]++;
}
linemap = m_Compiler.LineMap();
}
string[] warnings = m_Compiler.GetWarnings();
@ -696,19 +703,22 @@ namespace OpenSim.Region.ScriptEngine.XEngine
Evidence baseEvidence = AppDomain.CurrentDomain.Evidence;
Evidence evidence = new Evidence(baseEvidence);
AppDomain sandbox =
AppDomain.CreateDomain(
m_Scene.RegionInfo.RegionID.ToString(),
evidence, appSetup);
/*
PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
sandbox.SetAppDomainPolicy(sandboxPolicy);
*/
AppDomain sandbox;
if (m_AppDomainLoading)
sandbox = AppDomain.CreateDomain(
m_Scene.RegionInfo.RegionID.ToString(),
evidence, appSetup);
else
sandbox = AppDomain.CurrentDomain;
/*
PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
PermissionSet sandboxPermissionSet = sandboxPolicy.GetNamedPermissionSet("Internet");
PolicyStatement sandboxPolicyStatement = new PolicyStatement(sandboxPermissionSet);
CodeGroup sandboxCodeGroup = new UnionCodeGroup(sandboxMembershipCondition, sandboxPolicyStatement);
sandboxPolicy.RootCodeGroup = sandboxCodeGroup;
sandbox.SetAppDomainPolicy(sandboxPolicy);
*/
m_AppDomains[appDomain] = sandbox;
m_AppDomains[appDomain].AssemblyResolve +=
@ -905,9 +915,10 @@ namespace OpenSim.Region.ScriptEngine.XEngine
AppDomain domain = m_AppDomains[id];
m_AppDomains.Remove(id);
AppDomain.Unload(domain);
if (domain != AppDomain.CurrentDomain)
AppDomain.Unload(domain);
domain = null;
// m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
// m_log.DebugFormat("[XEngine] Unloaded app domain {0}", id.ToString());
}
}