About

OpenSim's current behavior is to pause every 100ms between processing events using Thread.Sleep. The patch replaces the entire thread with a timer in order to achieve roughly 50 millisecond resolutions for LSL event handlers such as listen, timer, sensor and dataserver which is measurably similar to what Second Life event handlers achieve.

More precisely, running a script such as:

default
{
    state_entry() {
        llSetTimerEvent(0.0000001);
    }
    timer() {
        llOwnerSay((string)llGetAndResetTime());
    }
}

On Second Life, will yield the output:

[12:03] Object: 0.044691
[12:03] Object: 0.043880

which indicates that the timer event has a minimal resolution of $\approx50ms$. OpenSim, by using Thread.Sleep is only able to process events in $100ms$ intervals. Running the same script on a fresh git clone of OpenSim, we obtain the output:

[15:09] Primitive: 0.502305
[15:09] Primitive: 0.501457

indicating a timer resolution of $\approx500ms$. By applying the patch in the code section, and running the same script on a patched version of OpenSim, we obtain the output:

[01:34]  Primitive: 0.049851
[01:34]  Primitive: 0.050070

which is approximately the same re-entry speed of timer on Second Life.

OpenSim Mantis

Effects

A comparison between OpenSim running with this patch and Second Life running without this patch can be drawn by running the bistable_color_primitive and comparing the time it takes for the primitives to change colors:

Second Life Open Sim

Potential Beneficiaries

All cases below are derived from making OpenSim compliant with Second Life:

  • teleporters that use llSetPos (since llSetRegionPos is not implemented in OpenSim yet).
  • resize scripts that are meant to execute fast and are killed prematurely by OpenSim's implementation of event handlers.
  • scripts that use the following event handlers will now have a resolution of $\approx 50ms$:
    • listen
    • timer
    • dataserver
    • sensor

Benchmark

The plotted data has been sampled from the VIBE OpenSim main hub that is currently running 711 scripts. Contrasted with the Vanilla version, where setting cmdHandlerThreadCycleSleepms to 10ms, the patched version using a timer instead of Thread.Sleep yields 10 times the re-entry speed of event handlers with a mean average CPU cost factor of $\approx 3$.

Thread Sleep vs Timers

In order to demonstrate the benefits of timers we compare a vanilla OpenSim with Thread.Sleep using 10ms delays and the modified XEngine after applying the patch that uses Timers with 10ms delays.

The benchmark is performed by placing a fader script inside a primitive, wired to commute between states, going from red to green and vice-versa. We left the script running and the grid isolated from incoming avatars and measured the CPU load in 5 second intervals.

Code

From a9bda2ee0c50679518bab4e5e7959b4a9059d5db Mon Sep 17 00:00:00 2001
From: Wizardry and Steamworks <office@grimore.org>
Date: Thu, 17 Apr 2014 07:29:53 +0100
Subject: [PATCH] Use a timer instead of a thread for LSL event handlers and
 decrease the delay between updates to 50ms (SecondLife
 standards.
 
---
 .../Api/Implementation/AsyncCommandManager.cs      |   34 ++++++++++++--------
 .../Shared/Api/Implementation/LSL_Api.cs           |    2 +-
 bin/OpenSimDefaults.ini                            |    2 +-
 3 files changed, 22 insertions(+), 16 deletions(-)
 
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
index 998f40b..20a3b1b 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/AsyncCommandManager.cs
@@ -49,8 +49,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
     {
         private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
 
-        private static Thread cmdHandlerThread;
         private static int cmdHandlerThreadCycleSleepms;
+	private static readonly System.Timers.Timer cmdEventTimer = new System.Timers.Timer();
 
         /// <summary>
         /// Lock for reading/writing static components of AsyncCommandManager.
@@ -172,18 +172,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
                 if (!m_XmlRequest.ContainsKey(m_ScriptEngine))
                     m_XmlRequest[m_ScriptEngine] = new XmlRequest(this);
 
-                StartThread();
-            }
-        }
+                if (cmdEventTimer.Enabled.Equals(true)) return;
+
+                // Start the timer
+                cmdEventTimer.Elapsed += (sender, args) =>
+                {
+                    try
+                    {
+                        DoOneCmdHandlerPass();
+                    }
+                    catch (Exception e)
+                    {
+                        m_log.Error("[ASYNC COMMAND MANAGER]: Exception in command handler pass: ", e);
+                    }
+                };
+
+                cmdEventTimer.Interval = cmdHandlerThreadCycleSleepms;
+                cmdEventTimer.Enabled = true;
 
-        private static void StartThread()
-        {
-            if (cmdHandlerThread == null)
-            {
-                // Start the thread that will be doing the work
-                cmdHandlerThread
-                    = Watchdog.StartThread(
-                        CmdHandlerThreadLoop, "AsyncLSLCmdHandlerThread", ThreadPriority.Normal, true, true);
             }
         }
 
@@ -191,7 +197,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
         {
 //            cmdHandlerThreadCycleSleepms = m_ScriptEngine.Config.GetInt("AsyncLLCommandLoopms", 100);
             // TODO: Make this sane again
-            cmdHandlerThreadCycleSleepms = 100;
+            cmdHandlerThreadCycleSleepms = 50;
         }
 
         ~AsyncCommandManager()
@@ -439,4 +445,4 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
index 6afabf9..898646e 100644
--- a/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
+++ b/OpenSim/Region/ScriptEngine/Shared/Api/Implementation/LSL_Api.cs
@@ -107,7 +107,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
         protected AsyncCommandManager AsyncCommands = null;
         protected float m_ScriptDelayFactor = 1.0f;
         protected float m_ScriptDistanceFactor = 1.0f;
-        protected float m_MinTimerInterval = 0.5f;
+        protected float m_MinTimerInterval = 0.05f;
         protected float m_recoilScaleFactor = 0.0f;
 
         protected DateTime m_timer = DateTime.Now;
diff --git a/bin/OpenSimDefaults.ini b/bin/OpenSimDefaults.ini
index 2a92fbc..69a5639 100644
--- a/bin/OpenSimDefaults.ini
+++ b/bin/OpenSimDefaults.ini
@@ -1497,7 +1497,7 @@
 
     ; Minimum settable timer interval. Any timer setting less than this is
     ; rounded up to this minimum interval.
-    ; MinTimerInterval = 0.5
+    ; MinTimerInterval = 0.05
 
     ; Sensor settings
     SensorMaxRange = 96.0
-- 
1.7.10.4

opensim/server_patches/use_timers_for_lsl_events.txt ยท Last modified: 2022/04/19 08:28 by 127.0.0.1

Access website using Tor Access website using i2p Wizardry and Steamworks PGP Key


For the contact, copyright, license, warranty and privacy terms for the usage of this website please see the contact, license, privacy, copyright.