aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/ScriptEngine/XEngine/XEngine.cs')
-rw-r--r--OpenSim/Region/ScriptEngine/XEngine/XEngine.cs355
1 files changed, 229 insertions, 126 deletions
diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
index 1e0f01f..79d1944 100644
--- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
+++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs
@@ -63,6 +63,14 @@ namespace OpenSim.Region.ScriptEngine.XEngine
63 { 63 {
64 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 64 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
65 65
66 /// <summary>
67 /// Control the printing of certain debug messages.
68 /// </summary>
69 /// <remarks>
70 /// If DebugLevel >= 1, then we log every time that a script is started.
71 /// </remarks>
72// public int DebugLevel { get; set; }
73
66 private SmartThreadPool m_ThreadPool; 74 private SmartThreadPool m_ThreadPool;
67 private int m_MaxScriptQueue; 75 private int m_MaxScriptQueue;
68 private Scene m_Scene; 76 private Scene m_Scene;
@@ -284,9 +292,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
284 AppDomain.CurrentDomain.AssemblyResolve += 292 AppDomain.CurrentDomain.AssemblyResolve +=
285 OnAssemblyResolve; 293 OnAssemblyResolve;
286 294
287 m_log.InfoFormat("[XEngine] Initializing scripts in region {0}",
288 scene.RegionInfo.RegionName);
289 m_Scene = scene; 295 m_Scene = scene;
296 m_log.InfoFormat("[XEngine]: Initializing scripts in region {0}", m_Scene.RegionInfo.RegionName);
290 297
291 m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2); 298 m_MinThreads = m_ScriptConfig.GetInt("MinThreads", 2);
292 m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100); 299 m_MaxThreads = m_ScriptConfig.GetInt("MaxThreads", 100);
@@ -389,9 +396,42 @@ namespace OpenSim.Region.ScriptEngine.XEngine
389 "Starts all stopped scripts." 396 "Starts all stopped scripts."
390 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.", 397 + "If a <script-item-uuid> is given then only that script will be started. Otherwise, all suitable scripts are started.",
391 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript)); 398 (module, cmdparams) => HandleScriptsAction(cmdparams, HandleStartScript));
399
400// MainConsole.Instance.Commands.AddCommand(
401// "Debug", false, "debug xengine", "debug xengine [<level>]",
402// "Turn on detailed xengine debugging.",
403// "If level <= 0, then no extra logging is done.\n"
404// + "If level >= 1, then we log every time that a script is started.",
405// HandleDebugLevelCommand);
392 } 406 }
393 407
394 /// <summary> 408 /// <summary>
409 /// Change debug level
410 /// </summary>
411 /// <param name="module"></param>
412 /// <param name="args"></param>
413// private void HandleDebugLevelCommand(string module, string[] args)
414// {
415// if (args.Length == 3)
416// {
417// int newDebug;
418// if (int.TryParse(args[2], out newDebug))
419// {
420// DebugLevel = newDebug;
421// MainConsole.Instance.OutputFormat("Debug level set to {0}", newDebug);
422// }
423// }
424// else if (args.Length == 2)
425// {
426// MainConsole.Instance.OutputFormat("Current debug level is {0}", DebugLevel);
427// }
428// else
429// {
430// MainConsole.Instance.Output("Usage: debug xengine 0..1");
431// }
432// }
433
434 /// <summary>
395 /// Parse the raw item id into a script instance from the command params if it's present. 435 /// Parse the raw item id into a script instance from the command params if it's present.
396 /// </summary> 436 /// </summary>
397 /// <param name="cmdparams"></param> 437 /// <param name="cmdparams"></param>
@@ -795,35 +835,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine
795 int colon = firstline.IndexOf(':'); 835 int colon = firstline.IndexOf(':');
796 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1) 836 if (firstline.Length > 2 && firstline.Substring(0, 2) == "//" && colon != -1)
797 { 837 {
798 string engineName = firstline.Substring(2, colon-2); 838 string engineName = firstline.Substring(2, colon - 2);
799 839
800 if (names.Contains(engineName)) 840 if (names.Contains(engineName))
801 { 841 {
802 engine = engineName; 842 engine = engineName;
803 script = "//" + script.Substring(script.IndexOf(':')+1); 843 script = "//" + script.Substring(colon + 1);
804 } 844 }
805 else 845 else
806 { 846 {
807 if (engine == ScriptEngineName) 847 if (engine == ScriptEngineName)
808 { 848 {
809 SceneObjectPart part = 849 // If we are falling back on XEngine as the default engine, then only complain to the user
810 m_Scene.GetSceneObjectPart( 850 // if a script language has been explicitly set and it's one that we recognize. If it's
811 localID); 851 // explicitly not allowed or the script is not in LSL then the user will be informed by a later compiler message.
812 852 //
813 TaskInventoryItem item = 853 // This avoids the overwhelming number of false positives where we're in this code because
814 part.Inventory.GetInventoryItem(itemID); 854 // there's a colon in a comment in the first line of a script for entirely
815 855 // unrelated reasons (e.g. vim settings).
816 ScenePresence presence = 856 //
817 m_Scene.GetScenePresence( 857 // TODO: A better fix would be to deprecate simple : detection and look for some less likely
818 item.OwnerID); 858 // string to begin the comment (like #! in unix shell scripts).
819 859 bool scriptExplicitlyInXEngineLanguage = false;
820 if (presence != null) 860 string restOfScript = script.Substring(colon + 1);
861
862 // FIXME: These are hardcoded because they are currently hardcoded in Compiler.cs
863 if (restOfScript.StartsWith("c#")
864 || restOfScript.StartsWith("vb")
865 || restOfScript.StartsWith("lsl")
866 || restOfScript.StartsWith("js")
867 || restOfScript.StartsWith("yp"))
868 scriptExplicitlyInXEngineLanguage = true;
869
870 if (scriptExplicitlyInXEngineLanguage)
821 { 871 {
822 presence.ControllingClient.SendAgentAlertMessage( 872 SceneObjectPart part =
823 "Selected engine unavailable. "+ 873 m_Scene.GetSceneObjectPart(
824 "Running script on "+ 874 localID);
825 ScriptEngineName, 875
826 false); 876 TaskInventoryItem item =
877 part.Inventory.GetInventoryItem(itemID);
878
879 ScenePresence presence =
880 m_Scene.GetScenePresence(
881 item.OwnerID);
882
883 if (presence != null)
884 {
885 presence.ControllingClient.SendAgentAlertMessage(
886 "Selected engine unavailable. "+
887 "Running script on "+
888 ScriptEngineName,
889 false);
890 }
827 } 891 }
828 } 892 }
829 } 893 }
@@ -880,20 +944,31 @@ namespace OpenSim.Region.ScriptEngine.XEngine
880 { 944 {
881 if (m_InitialStartup) 945 if (m_InitialStartup)
882 { 946 {
883 m_InitialStartup = false; 947 // This delay exists to stop mono problems where script compilation and startup would stop the sim
948 // working properly for the session.
884 System.Threading.Thread.Sleep(15000); 949 System.Threading.Thread.Sleep(15000);
950 }
951
952 object[] o;
953
954 int scriptsStarted = 0;
885 955
886 if (m_CompileQueue.Count == 0) 956 while (m_CompileQueue.Dequeue(out o))
957 {
958 if (DoOnRezScript(o))
887 { 959 {
888 // No scripts on region, so won't get triggered later 960 scriptsStarted++;
889 // by the queue becoming empty so we trigger it here 961
890 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(0, String.Empty); 962 if (m_InitialStartup)
963 if (scriptsStarted % 50 == 0)
964 m_log.InfoFormat(
965 "[XEngine]: Started {0} scripts in {1}", scriptsStarted, m_Scene.RegionInfo.RegionName);
891 } 966 }
892 } 967 }
893 968
894 object[] o; 969 if (m_InitialStartup)
895 while (m_CompileQueue.Dequeue(out o)) 970 m_log.InfoFormat(
896 DoOnRezScript(o); 971 "[XEngine]: Completed starting {0} scripts on {1}", scriptsStarted, m_Scene.RegionInfo.RegionName);
897 972
898 // NOTE: Despite having a lockless queue, this lock is required 973 // NOTE: Despite having a lockless queue, this lock is required
899 // to make sure there is never no compile thread while there 974 // to make sure there is never no compile thread while there
@@ -901,12 +976,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine
901 // due to a race condition 976 // due to a race condition
902 // 977 //
903 lock (m_CompileQueue) 978 lock (m_CompileQueue)
904 {
905 m_CurrentCompile = null; 979 m_CurrentCompile = null;
906 } 980
907 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount, 981 m_Scene.EventManager.TriggerEmptyScriptCompileQueue(m_ScriptFailCount,
908 m_ScriptErrorMessage); 982 m_ScriptErrorMessage);
983
909 m_ScriptFailCount = 0; 984 m_ScriptFailCount = 0;
985 m_InitialStartup = false;
910 986
911 return null; 987 return null;
912 } 988 }
@@ -1089,11 +1165,18 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1089 1165
1090 AppDomain sandbox; 1166 AppDomain sandbox;
1091 if (m_AppDomainLoading) 1167 if (m_AppDomainLoading)
1168 {
1092 sandbox = AppDomain.CreateDomain( 1169 sandbox = AppDomain.CreateDomain(
1093 m_Scene.RegionInfo.RegionID.ToString(), 1170 m_Scene.RegionInfo.RegionID.ToString(),
1094 evidence, appSetup); 1171 evidence, appSetup);
1172 m_AppDomains[appDomain].AssemblyResolve +=
1173 new ResolveEventHandler(
1174 AssemblyResolver.OnAssemblyResolve);
1175 }
1095 else 1176 else
1177 {
1096 sandbox = AppDomain.CurrentDomain; 1178 sandbox = AppDomain.CurrentDomain;
1179 }
1097 1180
1098 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel(); 1181 //PolicyLevel sandboxPolicy = PolicyLevel.CreateAppDomainLevel();
1099 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition(); 1182 //AllMembershipCondition sandboxMembershipCondition = new AllMembershipCondition();
@@ -1105,9 +1188,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1105 1188
1106 m_AppDomains[appDomain] = sandbox; 1189 m_AppDomains[appDomain] = sandbox;
1107 1190
1108 m_AppDomains[appDomain].AssemblyResolve +=
1109 new ResolveEventHandler(
1110 AssemblyResolver.OnAssemblyResolve);
1111 m_DomainScripts[appDomain] = new List<UUID>(); 1191 m_DomainScripts[appDomain] = new List<UUID>();
1112 } 1192 }
1113 catch (Exception e) 1193 catch (Exception e)
@@ -1392,25 +1472,24 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1392 return false; 1472 return false;
1393 1473
1394 uuids = m_PrimObjects[localID]; 1474 uuids = m_PrimObjects[localID];
1395
1396 1475
1397 foreach (UUID itemID in uuids) 1476 foreach (UUID itemID in uuids)
1398 {
1399 IScriptInstance instance = null;
1400 try
1401 {
1402 if (m_Scripts.ContainsKey(itemID))
1403 instance = m_Scripts[itemID];
1404 }
1405 catch { /* ignore race conditions */ }
1406
1407 if (instance != null)
1408 { 1477 {
1409 instance.PostEvent(p); 1478 IScriptInstance instance = null;
1410 result = true; 1479 try
1480 {
1481 if (m_Scripts.ContainsKey(itemID))
1482 instance = m_Scripts[itemID];
1483 }
1484 catch { /* ignore race conditions */ }
1485
1486 if (instance != null)
1487 {
1488 instance.PostEvent(p);
1489 result = true;
1490 }
1411 } 1491 }
1412 } 1492 }
1413 }
1414 1493
1415 return result; 1494 return result;
1416 } 1495 }
@@ -1535,6 +1614,13 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1535 } 1614 }
1536 } 1615 }
1537 1616
1617 public void SetRunEnable(UUID instanceID, bool enable)
1618 {
1619 IScriptInstance instance = GetInstance(instanceID);
1620 if (instance != null)
1621 instance.Run = enable;
1622 }
1623
1538 public bool GetScriptState(UUID itemID) 1624 public bool GetScriptState(UUID itemID)
1539 { 1625 {
1540 IScriptInstance instance = GetInstance(itemID); 1626 IScriptInstance instance = GetInstance(itemID);
@@ -1745,14 +1831,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1745 FileMode.Open, FileAccess.Read)) 1831 FileMode.Open, FileAccess.Read))
1746 { 1832 {
1747 tfs.Read(tdata, 0, tdata.Length); 1833 tfs.Read(tdata, 0, tdata.Length);
1748 tfs.Close();
1749 } 1834 }
1750 1835
1751 assem = new System.Text.ASCIIEncoding().GetString(tdata); 1836 assem = new System.Text.ASCIIEncoding().GetString(tdata);
1752 } 1837 }
1753 catch (Exception e) 1838 catch (Exception e)
1754 { 1839 {
1755 m_log.DebugFormat("[XEngine]: Unable to open script textfile {0}, reason: {1}", assemName+".text", e.Message); 1840 m_log.ErrorFormat(
1841 "[XEngine]: Unable to open script textfile {0}{1}, reason: {2}",
1842 assemName, ".text", e.Message);
1756 } 1843 }
1757 } 1844 }
1758 } 1845 }
@@ -1769,16 +1856,15 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1769 using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read)) 1856 using (FileStream fs = File.Open(assemName, FileMode.Open, FileAccess.Read))
1770 { 1857 {
1771 fs.Read(data, 0, data.Length); 1858 fs.Read(data, 0, data.Length);
1772 fs.Close();
1773 } 1859 }
1774 1860
1775 assem = System.Convert.ToBase64String(data); 1861 assem = System.Convert.ToBase64String(data);
1776 } 1862 }
1777 catch (Exception e) 1863 catch (Exception e)
1778 { 1864 {
1779 m_log.DebugFormat("[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message); 1865 m_log.ErrorFormat(
1866 "[XEngine]: Unable to open script assembly {0}, reason: {1}", assemName, e.Message);
1780 } 1867 }
1781
1782 } 1868 }
1783 } 1869 }
1784 1870
@@ -1791,9 +1877,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1791 using (StreamReader msr = new StreamReader(mfs)) 1877 using (StreamReader msr = new StreamReader(mfs))
1792 { 1878 {
1793 map = msr.ReadToEnd(); 1879 map = msr.ReadToEnd();
1794 msr.Close();
1795 } 1880 }
1796 mfs.Close();
1797 } 1881 }
1798 } 1882 }
1799 1883
@@ -1829,6 +1913,8 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1829 1913
1830 public bool SetXMLState(UUID itemID, string xml) 1914 public bool SetXMLState(UUID itemID, string xml)
1831 { 1915 {
1916// m_log.DebugFormat("[XEngine]: Writing state for script item with ID {0}", itemID);
1917
1832 if (xml == String.Empty) 1918 if (xml == String.Empty)
1833 return false; 1919 return false;
1834 1920
@@ -1889,31 +1975,61 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1889 { 1975 {
1890 using (FileStream fs = File.Create(path)) 1976 using (FileStream fs = File.Create(path))
1891 { 1977 {
1978// m_log.DebugFormat("[XEngine]: Writing assembly file {0}", path);
1979
1892 fs.Write(filedata, 0, filedata.Length); 1980 fs.Write(filedata, 0, filedata.Length);
1893 fs.Close();
1894 } 1981 }
1895 } 1982 }
1896 catch (IOException ex) 1983 catch (IOException ex)
1897 { 1984 {
1898 // if there already exists a file at that location, it may be locked. 1985 // if there already exists a file at that location, it may be locked.
1899 m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); 1986 m_log.ErrorFormat("[XEngine]: Error whilst writing assembly file {0}, {1}", path, ex.Message);
1900 } 1987 }
1988
1989 string textpath = path + ".text";
1901 try 1990 try
1902 { 1991 {
1903 using (FileStream fs = File.Create(path + ".text")) 1992 using (FileStream fs = File.Create(textpath))
1904 { 1993 {
1905 using (StreamWriter sw = new StreamWriter(fs)) 1994 using (StreamWriter sw = new StreamWriter(fs))
1906 { 1995 {
1996// m_log.DebugFormat("[XEngine]: Writing .text file {0}", textpath);
1997
1907 sw.Write(base64); 1998 sw.Write(base64);
1908 sw.Close();
1909 } 1999 }
1910 fs.Close();
1911 } 2000 }
1912 } 2001 }
1913 catch (IOException ex) 2002 catch (IOException ex)
1914 { 2003 {
1915 // if there already exists a file at that location, it may be locked. 2004 // if there already exists a file at that location, it may be locked.
1916 m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", path, ex.Message); 2005 m_log.ErrorFormat("[XEngine]: Error whilst writing .text file {0}, {1}", textpath, ex.Message);
2006 }
2007 }
2008
2009 XmlNodeList mapL = rootE.GetElementsByTagName("LineMap");
2010 if (mapL.Count > 0)
2011 {
2012 XmlElement mapE = (XmlElement)mapL[0];
2013
2014 string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
2015 mappath = Path.Combine(mappath, mapE.GetAttribute("Filename"));
2016
2017 try
2018 {
2019 using (FileStream mfs = File.Create(mappath))
2020 {
2021 using (StreamWriter msw = new StreamWriter(mfs))
2022 {
2023 // m_log.DebugFormat("[XEngine]: Writing linemap file {0}", mappath);
2024
2025 msw.Write(mapE.InnerText);
2026 }
2027 }
2028 }
2029 catch (IOException ex)
2030 {
2031 // if there already exists a file at that location, it may be locked.
2032 m_log.ErrorFormat("[XEngine]: Linemap file {0} already exists! {1}", mappath, ex.Message);
1917 } 2033 }
1918 } 2034 }
1919 } 2035 }
@@ -1927,43 +2043,16 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1927 { 2043 {
1928 using (StreamWriter ssw = new StreamWriter(sfs)) 2044 using (StreamWriter ssw = new StreamWriter(sfs))
1929 { 2045 {
2046// m_log.DebugFormat("[XEngine]: Writing state file {0}", statepath);
2047
1930 ssw.Write(stateE.OuterXml); 2048 ssw.Write(stateE.OuterXml);
1931 ssw.Close();
1932 } 2049 }
1933 sfs.Close();
1934 } 2050 }
1935 } 2051 }
1936 catch (IOException ex) 2052 catch (IOException ex)
1937 { 2053 {
1938 // if there already exists a file at that location, it may be locked. 2054 // if there already exists a file at that location, it may be locked.
1939 m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message); 2055 m_log.ErrorFormat("[XEngine]: Error whilst writing state file {0}, {1}", statepath, ex.Message);
1940 }
1941
1942 XmlNodeList mapL = rootE.GetElementsByTagName("LineMap");
1943 if (mapL.Count > 0)
1944 {
1945 XmlElement mapE = (XmlElement)mapL[0];
1946
1947 string mappath = Path.Combine(m_ScriptEnginesPath, World.RegionInfo.RegionID.ToString());
1948 mappath = Path.Combine(mappath, mapE.GetAttribute("Filename"));
1949
1950 try
1951 {
1952 using (FileStream mfs = File.Create(mappath))
1953 {
1954 using (StreamWriter msw = new StreamWriter(mfs))
1955 {
1956 msw.Write(mapE.InnerText);
1957 msw.Close();
1958 }
1959 mfs.Close();
1960 }
1961 }
1962 catch (IOException ex)
1963 {
1964 // if there already exists a file at that location, it may be locked.
1965 m_log.ErrorFormat("[XEngine]: File {0} already exists! {1}", statepath, ex.Message);
1966 }
1967 } 2056 }
1968 2057
1969 return true; 2058 return true;
@@ -1997,45 +2086,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine
1997 if (!topScripts.ContainsKey(si.LocalID)) 2086 if (!topScripts.ContainsKey(si.LocalID))
1998 topScripts[si.RootLocalID] = 0; 2087 topScripts[si.RootLocalID] = 0;
1999 2088
2000// long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; 2089 topScripts[si.RootLocalID] += CalculateAdjustedExectionTime(si, tickNow);
2001// float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); 2090 }
2002 2091 }
2003 // Execution time of the script adjusted by it's measurement period to make scripts started at
2004 // different times comparable.
2005// float adjustedExecutionTime
2006// = (float)si.MeasurementPeriodExecutionTime
2007// / ((float)(tickNow - si.MeasurementPeriodTickStart) / ScriptInstance.MaxMeasurementPeriod)
2008// / TimeSpan.TicksPerMillisecond;
2009
2010 long ticksElapsed = tickNow - si.MeasurementPeriodTickStart;
2011
2012 // Avoid divide by zerp
2013 if (ticksElapsed == 0)
2014 ticksElapsed = 1;
2015 2092
2016 // Scale execution time to the ideal 55 fps frame time for these reasons. 2093 return topScripts;
2017 // 2094 }
2018 // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no
2019 // 'script execution time per frame', which is the original purpose of this value.
2020 //
2021 // 2) Giving the raw execution times is misleading since scripts start at different times, making
2022 // it impossible to compare scripts.
2023 //
2024 // 3) Scaling the raw execution time to the time that the script has been running is better but
2025 // is still misleading since a script that has just been rezzed may appear to have been running
2026 // for much longer.
2027 //
2028 // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect
2029 // since the figure does not represent actual execution time and very hard running scripts will
2030 // never exceed 18ms (though this is a very high number for script execution so is a warning sign).
2031 float adjustedExecutionTime
2032 = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f;
2033 2095
2034 topScripts[si.RootLocalID] += adjustedExecutionTime; 2096 public float GetScriptExecutionTime(List<UUID> itemIDs)
2097 {
2098 if (itemIDs == null|| itemIDs.Count == 0)
2099 {
2100 return 0.0f;
2101 }
2102 float time = 0.0f;
2103 long tickNow = Util.EnvironmentTickCount();
2104 IScriptInstance si;
2105 // Calculate the time for all scripts that this engine is executing
2106 // Ignore any others
2107 foreach (UUID id in itemIDs)
2108 {
2109 si = GetInstance(id);
2110 if (si != null && si.Running)
2111 {
2112 time += CalculateAdjustedExectionTime(si, tickNow);
2035 } 2113 }
2036 } 2114 }
2115 return time;
2116 }
2037 2117
2038 return topScripts; 2118 private float CalculateAdjustedExectionTime(IScriptInstance si, long tickNow)
2119 {
2120 long ticksElapsed = tickNow - si.MeasurementPeriodTickStart;
2121
2122 // Avoid divide by zero
2123 if (ticksElapsed == 0)
2124 ticksElapsed = 1;
2125
2126 // Scale execution time to the ideal 55 fps frame time for these reasons.
2127 //
2128 // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no
2129 // 'script execution time per frame', which is the original purpose of this value.
2130 //
2131 // 2) Giving the raw execution times is misleading since scripts start at different times, making
2132 // it impossible to compare scripts.
2133 //
2134 // 3) Scaling the raw execution time to the time that the script has been running is better but
2135 // is still misleading since a script that has just been rezzed may appear to have been running
2136 // for much longer.
2137 //
2138 // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect
2139 // since the figure does not represent actual execution time and very hard running scripts will
2140 // never exceed 18ms (though this is a very high number for script execution so is a warning sign).
2141 return ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f;
2039 } 2142 }
2040 2143
2041 public void SuspendScript(UUID itemID) 2144 public void SuspendScript(UUID itemID)