From a4b01ef38a735ffe70b402061871a9c99f2757ed Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 00:34:30 +0000 Subject: [PATCH 1/9] Replace script-lines-per-second with the script execution time scaled by its measurement period and an idealised frame time. The previous lines-per-second measurement used for top scripts report was inaccurate, since lines executed does not reflect time taken to execute. Also, every fetch of the report would reset all the numbers limiting its usefulness and we weren't even guaranteed to see the top 100. The actual measurement value should be script execution time per frame but XEngine does not work this way. Therefore, we use actual script execution time scaled by the measurement period and an idealised frame time. This is still not ideal but gives reasonable results and allows scripts to be compared. This commit moves script execution time calculations from SceneGraph into IScriptModule implementations. --- .../World/Estate/EstateManagementModule.cs | 77 +++++++++++-------- .../Framework/Interfaces/IScriptModule.cs | 9 ++- OpenSim/Region/Framework/Scenes/SceneGraph.cs | 31 +------- .../Framework/Scenes/SceneObjectGroup.cs | 9 +-- .../Interfaces/IScriptInstance.cs | 15 ++++ .../Shared/Instance/ScriptInstance.cs | 21 ++++- .../Region/ScriptEngine/XEngine/XEngine.cs | 53 +++++++++++++ 7 files changed, 145 insertions(+), 70 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index c303d6db1c..d363b15c01 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -26,8 +26,10 @@ */ using System; +using System.Collections; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Reflection; using System.Security; using log4net; @@ -876,52 +878,67 @@ namespace OpenSim.Region.CoreModules.World.Estate if (!Scene.Permissions.CanIssueEstateCommand(remoteClient.AgentId, false)) return; - Dictionary SceneData = new Dictionary(); + Dictionary sceneData = null; List uuidNameLookupList = new List(); if (reportType == 1) { - SceneData = Scene.PhysicsScene.GetTopColliders(); + sceneData = Scene.PhysicsScene.GetTopColliders(); } else if (reportType == 0) { - SceneData = Scene.SceneGraph.GetTopScripts(); + IScriptModule scriptModule = Scene.RequestModuleInterface(); + + if (scriptModule != null) + sceneData = scriptModule.GetObjectScriptsExecutionTimes(); } List SceneReport = new List(); - lock (SceneData) + if (sceneData != null) { - foreach (uint obj in SceneData.Keys) + var sortedSceneData + = sceneData.Select( + item => new { Measurement = item.Value, Part = Scene.GetSceneObjectPart(item.Key) }); + + sortedSceneData.OrderBy(item => item.Measurement); + + int items = 0; + + foreach (var entry in sortedSceneData) { - SceneObjectPart prt = Scene.GetSceneObjectPart(obj); - if (prt != null) + if (entry.Part == null) + continue; + + items++; + SceneObjectGroup so = entry.Part.ParentGroup; + + LandStatReportItem lsri = new LandStatReportItem(); + lsri.LocationX = so.AbsolutePosition.X; + lsri.LocationY = so.AbsolutePosition.Y; + lsri.LocationZ = so.AbsolutePosition.Z; + lsri.Score = entry.Measurement; + lsri.TaskID = so.UUID; + lsri.TaskLocalID = so.LocalId; + lsri.TaskName = entry.Part.Name; + lsri.OwnerName = "waiting"; + lock (uuidNameLookupList) + uuidNameLookupList.Add(so.OwnerID); + + if (filter.Length != 0) { - SceneObjectGroup sog = prt.ParentGroup; - LandStatReportItem lsri = new LandStatReportItem(); - lsri.LocationX = sog.AbsolutePosition.X; - lsri.LocationY = sog.AbsolutePosition.Y; - lsri.LocationZ = sog.AbsolutePosition.Z; - lsri.Score = SceneData[obj]; - lsri.TaskID = sog.UUID; - lsri.TaskLocalID = sog.LocalId; - lsri.TaskName = sog.GetPartName(obj); - lsri.OwnerName = "waiting"; - lock (uuidNameLookupList) - uuidNameLookupList.Add(sog.OwnerID); - - if (filter.Length != 0) + if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) { - if ((lsri.OwnerName.Contains(filter) || lsri.TaskName.Contains(filter))) - { - } - else - { - continue; - } } - - SceneReport.Add(lsri); + else + { + continue; + } } + + SceneReport.Add(lsri); + + if (items >= 100) + break; } } diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 18c45dde6e..9fb4a25009 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -27,6 +27,7 @@ using System; using System.Collections; +using System.Collections.Generic; using OpenMetaverse; namespace OpenSim.Region.Framework.Interfaces @@ -74,5 +75,11 @@ namespace OpenSim.Region.Framework.Interfaces /// Starts the processing threads. /// void StartProcessing(); + + /// + /// Get the execution times of all scripts in each object. + /// + /// A dictionary where the key is a local object ID and the value is an execution time in milliseconds. + Dictionary GetObjectScriptsExecutionTimes(); } -} +} \ No newline at end of file diff --git a/OpenSim/Region/Framework/Scenes/SceneGraph.cs b/OpenSim/Region/Framework/Scenes/SceneGraph.cs index bc3400a7a5..5c542d65a2 100644 --- a/OpenSim/Region/Framework/Scenes/SceneGraph.cs +++ b/OpenSim/Region/Framework/Scenes/SceneGraph.cs @@ -733,6 +733,7 @@ namespace OpenSim.Region.Framework.Scenes #endregion #region Get Methods + /// /// Get the controlling client for the given avatar, if there is one. /// @@ -1074,36 +1075,6 @@ namespace OpenSim.Region.Framework.Scenes return Entities.GetEntities(); } - public Dictionary GetTopScripts() - { - Dictionary topScripts = new Dictionary(); - - EntityBase[] EntityList = GetEntities(); - int limit = 0; - foreach (EntityBase ent in EntityList) - { - if (ent is SceneObjectGroup) - { - SceneObjectGroup grp = (SceneObjectGroup)ent; - if ((grp.RootPart.GetEffectiveObjectFlags() & (uint)PrimFlags.Scripted) != 0) - { - if (grp.scriptScore >= 0.01) - { - topScripts.Add(grp.LocalId, grp.scriptScore); - limit++; - if (limit >= 100) - { - break; - } - } - grp.scriptScore = 0; - } - } - } - - return topScripts; - } - #endregion #region Other Methods diff --git a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs index 878476e5c9..afb5ccfae5 100644 --- a/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs +++ b/OpenSim/Region/Framework/Scenes/SceneObjectGroup.cs @@ -229,8 +229,6 @@ namespace OpenSim.Region.Framework.Scenes get { return RootPart.VolumeDetectActive; } } - public float scriptScore; - private Vector3 lastPhysGroupPos; private Quaternion lastPhysGroupRot; @@ -1184,12 +1182,7 @@ namespace OpenSim.Region.Framework.Scenes public void AddScriptLPS(int count) { - if (scriptScore + count >= float.MaxValue - count) - scriptScore = 0; - - scriptScore += (float)count; - SceneGraph d = m_scene.SceneGraph; - d.AddToScriptLPS(count); + m_scene.SceneGraph.AddToScriptLPS(count); } public void AddActiveScriptCount(int count) diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 8762642903..11f54a267c 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -78,6 +78,21 @@ namespace OpenSim.Region.ScriptEngine.Interfaces /// string State { get; set; } + /// + /// Time the script was last started + /// + DateTime TimeStarted { get; } + + /// + /// Tick the last measurement period was started. + /// + long MeasurementPeriodTickStart { get; } + + /// + /// Ticks spent executing in the last measurement period. + /// + long MeasurementPeriodExecutionTime { get; } + IScriptEngine Engine { get; } UUID AppDomain { get; set; } string PrimName { get; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index 968351b450..b17728758a 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -172,6 +172,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public TaskInventoryItem ScriptTask { get; private set; } + public DateTime TimeStarted { get; private set; } + + public long MeasurementPeriodTickStart { get; private set; } + + public long MeasurementPeriodExecutionTime { get; private set; } + + public static readonly long MaxMeasurementPeriod = 30 * TimeSpan.TicksPerMinute; + public void ClearQueue() { m_TimerQueued = false; @@ -458,6 +466,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Running = true; + TimeStarted = DateTime.Now; + MeasurementPeriodTickStart = Util.EnvironmentTickCount(); + MeasurementPeriodExecutionTime = 0; + if (EventQueue.Count > 0) { if (m_CurrentWorkItem == null) @@ -710,8 +722,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance m_EventStart = DateTime.Now; m_InEvent = true; + int start = Util.EnvironmentTickCount(); + + // Reset the measurement period when we reach the end of the current one. + if (start - MeasurementPeriodTickStart > MaxMeasurementPeriod) + MeasurementPeriodTickStart = start; + m_Script.ExecuteEvent(State, data.EventName, data.Params); + MeasurementPeriodExecutionTime += Util.EnvironmentTickCount() - start; + m_InEvent = false; m_CurrentEvent = String.Empty; @@ -720,7 +740,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance // This will be the very first event we deliver // (state_entry) in default state // - SaveState(m_Assembly); m_SaveState = false; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index 105d97da47..bddb1b96fc 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1891,6 +1891,59 @@ namespace OpenSim.Region.ScriptEngine.XEngine } } + public Dictionary GetObjectScriptsExecutionTimes() + { + long tickNow = Util.EnvironmentTickCount(); + Dictionary topScripts = new Dictionary(); + + lock (m_Scripts) + { + foreach (IScriptInstance si in m_Scripts.Values) + { + if (!topScripts.ContainsKey(si.LocalID)) + topScripts[si.LocalID] = 0; + +// long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; +// float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); + + // Execution time of the script adjusted by it's measurement period to make scripts started at + // different times comparable. +// float adjustedExecutionTime +// = (float)si.MeasurementPeriodExecutionTime +// / ((float)(tickNow - si.MeasurementPeriodTickStart) / ScriptInstance.MaxMeasurementPeriod) +// / TimeSpan.TicksPerMillisecond; + + long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; + + // Avoid divide by zerp + if (ticksElapsed == 0) + ticksElapsed = 1; + + // Scale execution time to the ideal 55 fps frame time for these reasons. + // + // 1) XEngine does not execute scripts per frame, unlike other script engines. Hence, there is no + // 'script execution time per frame', which is the original purpose of this value. + // + // 2) Giving the raw execution times is misleading since scripts start at different times, making + // it impossible to compare scripts. + // + // 3) Scaling the raw execution time to the time that the script has been running is better but + // is still misleading since a script that has just been rezzed may appear to have been running + // for much longer. + // + // 4) Hence, we scale execution time to an idealised frame time (55 fps). This is also not perfect + // since the figure does not represent actual execution time and very hard running scripts will + // never exceed 18ms (though this is a very high number for script execution so is a warning sign). + float adjustedExecutionTime + = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; + + topScripts[si.LocalID] += adjustedExecutionTime; + } + } + + return topScripts; + } + public void SuspendScript(UUID itemID) { // m_log.DebugFormat("[XEngine]: Received request to suspend script with ID {0}", itemID); From 7df4a544fecb336d6f4b9cbc0faea98daf0b9edf Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 00:53:36 +0000 Subject: [PATCH 2/9] Fix owner name display in "Top Colliders" and "Top Script" region reports. --- .../World/Estate/EstateManagementModule.cs | 46 +------------------ 1 file changed, 1 insertion(+), 45 deletions(-) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index d363b15c01..1492861c11 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -47,8 +47,6 @@ namespace OpenSim.Region.CoreModules.World.Estate { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); - private delegate void LookupUUIDS(List uuidLst); - public Scene Scene { get; private set; } public IUserManagement UserManager { get; private set; } @@ -920,9 +918,7 @@ namespace OpenSim.Region.CoreModules.World.Estate lsri.TaskID = so.UUID; lsri.TaskLocalID = so.LocalId; lsri.TaskName = entry.Part.Name; - lsri.OwnerName = "waiting"; - lock (uuidNameLookupList) - uuidNameLookupList.Add(so.OwnerID); + lsri.OwnerName = UserManager.GetUserName(so.OwnerID); if (filter.Length != 0) { @@ -943,48 +939,8 @@ namespace OpenSim.Region.CoreModules.World.Estate } remoteClient.SendLandStatReply(reportType, requestFlags, (uint)SceneReport.Count,SceneReport.ToArray()); - - if (uuidNameLookupList.Count > 0) - LookupUUID(uuidNameLookupList); } - private static void LookupUUIDSCompleted(IAsyncResult iar) - { - LookupUUIDS icon = (LookupUUIDS)iar.AsyncState; - icon.EndInvoke(iar); - } - - private void LookupUUID(List uuidLst) - { - LookupUUIDS d = LookupUUIDsAsync; - - d.BeginInvoke(uuidLst, - LookupUUIDSCompleted, - d); - } - - private void LookupUUIDsAsync(List uuidLst) - { - UUID[] uuidarr; - - lock (uuidLst) - { - uuidarr = uuidLst.ToArray(); - } - - for (int i = 0; i < uuidarr.Length; i++) - { - // string lookupname = m_scene.CommsManager.UUIDNameRequestString(uuidarr[i]); - - IUserManagement userManager = Scene.RequestModuleInterface(); - if (userManager != null) - userManager.GetUserName(uuidarr[i]); - - // we drop it. It gets cached though... so we're ready for the next request. - // diva commnent 11/21/2010: uh?!? wft? - // justincc comment 21/01/2011: A side effect of userManager.GetUserName() I presume. - } - } #endregion #region Outgoing Packets From c386b68373d0f4c46811423a2ba9ffbb486a1d9f Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 01:31:53 +0000 Subject: [PATCH 3/9] Aggregate script execution times by linksets rather than individual prims. This is for the top scripts report. --- OpenSim/Region/Framework/Interfaces/IScriptModule.cs | 5 ++++- .../Region/ScriptEngine/Interfaces/IScriptInstance.cs | 11 +++++++++++ .../ScriptEngine/Shared/Instance/ScriptInstance.cs | 6 ++++++ OpenSim/Region/ScriptEngine/XEngine/XEngine.cs | 5 ++--- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs index 9fb4a25009..9cab2e185b 100644 --- a/OpenSim/Region/Framework/Interfaces/IScriptModule.cs +++ b/OpenSim/Region/Framework/Interfaces/IScriptModule.cs @@ -79,7 +79,10 @@ namespace OpenSim.Region.Framework.Interfaces /// /// Get the execution times of all scripts in each object. /// - /// A dictionary where the key is a local object ID and the value is an execution time in milliseconds. + /// + /// A dictionary where the key is the root object ID of a linkset + /// and the value is a representative execution time in milliseconds of all scripts in that linkset. + /// Dictionary GetObjectScriptsExecutionTimes(); } } \ No newline at end of file diff --git a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs index 11f54a267c..b04f6b6624 100644 --- a/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Interfaces/IScriptInstance.cs @@ -99,6 +99,17 @@ namespace OpenSim.Region.ScriptEngine.Interfaces string ScriptName { get; } UUID ItemID { get; } UUID ObjectID { get; } + + /// + /// UUID of the root object for the linkset that the script is in. + /// + UUID RootObjectID { get; } + + /// + /// Local id of the root object for the linkset that the script is in. + /// + uint RootLocalID { get; } + uint LocalID { get; } UUID AssetID { get; } Queue EventQueue { get; } diff --git a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs index b17728758a..6e367421c0 100644 --- a/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs +++ b/OpenSim/Region/ScriptEngine/Shared/Instance/ScriptInstance.cs @@ -164,6 +164,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance public uint LocalID { get; private set; } + public UUID RootObjectID { get; private set; } + + public uint RootLocalID { get; private set; } + public UUID AssetID { get; private set; } public Queue EventQueue { get; private set; } @@ -198,6 +202,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Instance Engine = engine; LocalID = part.LocalId; ObjectID = part.UUID; + RootLocalID = part.ParentGroup.LocalId; + RootObjectID = part.ParentGroup.UUID; ItemID = itemID; AssetID = assetID; PrimName = primName; diff --git a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs index bddb1b96fc..3697f78c83 100644 --- a/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs +++ b/OpenSim/Region/ScriptEngine/XEngine/XEngine.cs @@ -1083,7 +1083,6 @@ namespace OpenSim.Region.ScriptEngine.XEngine if (!m_PrimObjects[localID].Contains(itemID)) m_PrimObjects[localID].Add(itemID); - } if (!m_Assemblies.ContainsKey(assetID)) @@ -1901,7 +1900,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine foreach (IScriptInstance si in m_Scripts.Values) { if (!topScripts.ContainsKey(si.LocalID)) - topScripts[si.LocalID] = 0; + topScripts[si.RootLocalID] = 0; // long ticksElapsed = tickNow - si.MeasurementPeriodTickStart; // float framesElapsed = ticksElapsed / (18.1818 * TimeSpan.TicksPerMillisecond); @@ -1937,7 +1936,7 @@ namespace OpenSim.Region.ScriptEngine.XEngine float adjustedExecutionTime = ((float)si.MeasurementPeriodExecutionTime / ticksElapsed) * 18.1818f; - topScripts[si.LocalID] += adjustedExecutionTime; + topScripts[si.RootLocalID] += adjustedExecutionTime; } } From 8550a4a07eb581ada9a5dca08b558344d87eebfc Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 01:46:21 +0000 Subject: [PATCH 4/9] In Top Scripts report, don't show scripts with no or less than 1 microsecond of execution time. This is to make the report clearer and less confusing. --- .../CoreModules/World/Estate/EstateManagementModule.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs index 1492861c11..61d604ff3d 100644 --- a/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs +++ b/OpenSim/Region/CoreModules/World/Estate/EstateManagementModule.cs @@ -904,9 +904,15 @@ namespace OpenSim.Region.CoreModules.World.Estate foreach (var entry in sortedSceneData) { + // The object may have been deleted since we received the data. if (entry.Part == null) continue; + // Don't show scripts that haven't executed or where execution time is below one microsecond in + // order to produce a more readable report. + if (entry.Measurement < 0.001) + continue; + items++; SceneObjectGroup so = entry.Part.ParentGroup; From 34f6f87b6cbea176805b5802804af9be89284f99 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 01:51:16 +0000 Subject: [PATCH 5/9] Remove unused bin/ScriptEngines/Default.lsl It would certainly be nice to change the default script on disk, but this is currently unused and isn't a suitable default. At this location it would also stop an easy manual deletion of script engine compiles and state. --- bin/ScriptEngines/Default.lsl | 104 ---------------------------------- 1 file changed, 104 deletions(-) delete mode 100644 bin/ScriptEngines/Default.lsl diff --git a/bin/ScriptEngines/Default.lsl b/bin/ScriptEngines/Default.lsl deleted file mode 100644 index ade855d98f..0000000000 --- a/bin/ScriptEngines/Default.lsl +++ /dev/null @@ -1,104 +0,0 @@ -// autogenerated by generate_default_lsl.rb -integer touch_count = 0; - -default { - touch_start(integer total_number) { - float angle45 = PI/4.0; // 45 degrees - float angle30 = PI/6.0; // 30 degrees - float sqrt2 = llSqrt(2.0); - if((llFabs(-1.5) != 1.5) || (llFabs(10.4) != 10.4)) { - llShout(0, "Houston, we have a big problem! llFabs() does not work! Need it for other tests!"); - } - llSetText("This is a text by llSetText", <1,0,0>, 1); - llWhisper(0, "llWhispering a few random numbers between 0 and 100: " + llFrand(100) + "," + llFrand(100) + "," + llFrand(100) + "," + llFrand(100)); - llShout(0, "llShouting the unix time: " + llGetUnixTime() + ", and region corner: " + llGetRegionCorner()); - llShout(1, "Shouting a random number between 0 and 100 on the channel#1: " + llFrand(100)); - if (llAbs(-1) != 1) { - llSay(0, "Assert failed: llAbs(-1) != 1"); - } - if (llAbs(10) != 10) { - llSay(0, "Assert failed: llAbs(10) != 10"); - } - if (llFabs((llCos(angle45) - sqrt2/2.0) - 0) > 0.000001) { - llSay(0, "Assert failed: (llCos(angle45) - sqrt2/2.0) differs from 0 by more than 0.000001"); - llSay(0, " --> The actual result: " + (llCos(angle45) - sqrt2/2.0)); - } - if (llFabs((llSin(angle30) - 0.5) - 0) > 0.000001) { - llSay(0, "Assert failed: (llSin(angle30) - 0.5) differs from 0 by more than 0.000001"); - llSay(0, " --> The actual result: " + (llSin(angle30) - 0.5)); - } - if (llFabs((llAtan2(1, 1)*4 - PI) - 0) > 0.000001) { - llSay(0, "Assert failed: (llAtan2(1, 1)*4 - PI) differs from 0 by more than 0.000001"); - llSay(0, " --> The actual result: " + (llAtan2(1, 1)*4 - PI)); - } - if (llFabs((llTan(PI)) - 0) > 0.000001) { - llSay(0, "Assert failed: (llTan(PI)) differs from 0 by more than 0.000001"); - llSay(0, " --> The actual result: " + (llTan(PI))); - } - if (llFloor(2.4) != 2) { - llSay(0, "Assert failed: llFloor(2.4) != 2"); - } - if (llCeil(2.4) != 3) { - llSay(0, "Assert failed: llCeil(2.4) != 3"); - } - if (llRound(2.4) != 2) { - llSay(0, "Assert failed: llRound(2.4) != 2"); - } - if (llFloor(2.5) != 2) { - llSay(0, "Assert failed: llFloor(2.5) != 2"); - } - if (llCeil(2.5) != 3) { - llSay(0, "Assert failed: llCeil(2.5) != 3"); - } - if (llRound(2.5) != 3) { - llSay(0, "Assert failed: llRound(2.5) != 3"); - } - if (llFloor(2.51) != 2) { - llSay(0, "Assert failed: llFloor(2.51) != 2"); - } - if (llCeil(2.51) != 3) { - llSay(0, "Assert failed: llCeil(2.51) != 3"); - } - if (llRound(2.51) != 3) { - llSay(0, "Assert failed: llRound(2.51) != 3"); - } - if (llFloor(3.49) != 3) { - llSay(0, "Assert failed: llFloor(3.49) != 3"); - } - if (llCeil(3.49) != 4) { - llSay(0, "Assert failed: llCeil(3.49) != 4"); - } - if (llRound(3.49) != 3) { - llSay(0, "Assert failed: llRound(3.49) != 3"); - } - if (llFloor(3.5000001) != 3) { - llSay(0, "Assert failed: llFloor(3.5000001) != 3"); - } - if (llCeil(3.5000001) != 4) { - llSay(0, "Assert failed: llCeil(3.5000001) != 4"); - } - if (llRound(3.5000001) != 4) { - llSay(0, "Assert failed: llRound(3.5000001) != 4"); - } - if (llFloor(3.51) != 3) { - llSay(0, "Assert failed: llFloor(3.51) != 3"); - } - if (llCeil(3.51) != 4) { - llSay(0, "Assert failed: llCeil(3.51) != 4"); - } - if (llRound(3.51) != 4) { - llSay(0, "Assert failed: llRound(3.51) != 4"); - } - if ((llFabs(0-llPow(2, 16))) != 65536) { - llSay(0, "Assert failed: (llFabs(0-llPow(2, 16))) != 65536"); - } - if (llMD5String("Hello, Avatar!",0) != "112abd47ceaae1c05a826828650434a6") { - llSay(0, "Assert failed: llMD5String('Hello, Avatar!',0) != '112abd47ceaae1c05a826828650434a6'"); - } - if (llModPow(2, 16, 37) != 9) { - llSay(0, "Assert failed: llModPow(2, 16, 37) != 9"); - } - touch_count++; - llSay(0, "Object was touched. Touch count: " + touch_count); - } -} From aa881e80652aa9feebbb6a4c4783322be44b7574 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 02:07:26 +0000 Subject: [PATCH 6/9] Allow comments to appear in command scripts (e.g. shutdown_commands.txt). These can start with ; # or // --- OpenSim/Region/Application/OpenSim.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs index 6fba2493d4..e955a58527 100644 --- a/OpenSim/Region/Application/OpenSim.cs +++ b/OpenSim/Region/Application/OpenSim.cs @@ -503,7 +503,11 @@ namespace OpenSim string currentCommand; while ((currentCommand = readFile.ReadLine()) != null) { - if (currentCommand != String.Empty) + currentCommand = currentCommand.Trim(); + if (!(currentCommand == "" + || currentCommand.StartsWith(";") + || currentCommand.StartsWith("//") + || currentCommand.StartsWith("#"))) { m_log.Info("[COMMANDFILE]: Running '" + currentCommand + "'"); m_console.RunCommand(currentCommand); From b19be657b6e032321fe4b55b8751d609d9921384 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 02:10:59 +0000 Subject: [PATCH 7/9] Remove unnecessary "backup" command in shutdown_commands.txt The simulator is already doing this internally. --- bin/shutdown_commands.txt | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/shutdown_commands.txt b/bin/shutdown_commands.txt index ec76ec276d..640c41a0bc 100644 --- a/bin/shutdown_commands.txt +++ b/bin/shutdown_commands.txt @@ -1 +1,2 @@ -backup +; You can place simulator console commands here to execute when the simulator is shut down +; e.g. show stats From 78e992dbd0bbc0b99dd01b1c6c303098d99aac55 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 02:13:45 +0000 Subject: [PATCH 8/9] Move startup_commands.txt.example to startup_commands.txt for consistency with the existing shutdown_commands.txt. Add comments to both files saying what they are (files that can contain console commands to execute on sim startup/shutdown) with an example. --- bin/shutdown_commands.txt | 1 + bin/startup_commands.txt | 3 +++ bin/startup_commands.txt.example | 4 ---- 3 files changed, 4 insertions(+), 4 deletions(-) create mode 100644 bin/startup_commands.txt delete mode 100644 bin/startup_commands.txt.example diff --git a/bin/shutdown_commands.txt b/bin/shutdown_commands.txt index 640c41a0bc..4397749d23 100644 --- a/bin/shutdown_commands.txt +++ b/bin/shutdown_commands.txt @@ -1,2 +1,3 @@ ; You can place simulator console commands here to execute when the simulator is shut down ; e.g. show stats +; Lines starting with ; are comments diff --git a/bin/startup_commands.txt b/bin/startup_commands.txt new file mode 100644 index 0000000000..1abfa64c87 --- /dev/null +++ b/bin/startup_commands.txt @@ -0,0 +1,3 @@ +; You can place region console commands here to execute once the simulator has finished starting up +; e.g. show stats +; Lines start with ; are comments. diff --git a/bin/startup_commands.txt.example b/bin/startup_commands.txt.example deleted file mode 100644 index 3dba4b378d..0000000000 --- a/bin/startup_commands.txt.example +++ /dev/null @@ -1,4 +0,0 @@ -terrain load-tile f32 islandterrain_1024x512.raw 512 1024 1000 1000 -terrain multiply 0.1 -terrain add 5 - From 421b562a045c69c5d507ee33e0283613d133e376 Mon Sep 17 00:00:00 2001 From: "Justin Clark-Casey (justincc)" Date: Fri, 16 Mar 2012 02:43:33 +0000 Subject: [PATCH 9/9] Add process working memory to "show stats" memory statistics. This shows the actual amount of RAM being taken up by OpenSimulator (objects + vm overhead) --- OpenSim/Framework/Statistics/BaseStatsCollector.cs | 8 ++++++-- OpenSim/Framework/Util.cs | 7 +++++-- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/OpenSim/Framework/Statistics/BaseStatsCollector.cs b/OpenSim/Framework/Statistics/BaseStatsCollector.cs index a1841c568a..c9e57ce7b3 100644 --- a/OpenSim/Framework/Statistics/BaseStatsCollector.cs +++ b/OpenSim/Framework/Statistics/BaseStatsCollector.cs @@ -26,8 +26,8 @@ */ using System; +using System.Diagnostics; using System.Text; - using OpenMetaverse; using OpenMetaverse.StructuredData; @@ -46,8 +46,12 @@ namespace OpenSim.Framework.Statistics sb.Append(Environment.NewLine); sb.Append( string.Format( - "Allocated to OpenSim : {0} MB" + Environment.NewLine, + "Allocated to OpenSim objects: {0} MB\n", Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0))); + sb.Append( + string.Format( + "Process memory : {0} MB\n", + Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0))); return sb.ToString(); } diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs index efa4a7ba87..31fa101e50 100644 --- a/OpenSim/Framework/Util.cs +++ b/OpenSim/Framework/Util.cs @@ -81,12 +81,15 @@ namespace OpenSim.Framework private static uint nextXferID = 5000; private static Random randomClass = new Random(); + // Get a list of invalid file characters (OS dependent) private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]"; private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]"; private static object XferLock = new object(); - /// Thread pool used for Util.FireAndForget if - /// FireAndForgetMethod.SmartThreadPool is used + + /// + /// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used + /// private static SmartThreadPool m_ThreadPool; // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.