From 80a8a9c4a7c9f1f0351f70f944a69650e9eca930 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Fri, 16 Oct 2009 14:34:42 -0700
Subject: Converted FireAndForget methods to use a singleton pattern to attempt
to work around a Mono bug with nested delegates
---
OpenSim/Framework/Util.cs | 23 +++++++++++++++++++++--
1 file changed, 21 insertions(+), 2 deletions(-)
(limited to 'OpenSim/Framework/Util.cs')
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 38729c6..3203fc1 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -44,6 +44,7 @@ using System.Xml;
using log4net;
using Nini.Config;
using Nwc.XmlRpc;
+using BclExtras;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
@@ -1269,14 +1270,32 @@ namespace OpenSim.Framework
#region FireAndForget Threading Pattern
+ ///
+ /// Created to work around a limitation in Mono with nested delegates
+ ///
+ private class FireAndForgetWrapper
+ {
+ public void FireAndForget(System.Threading.WaitCallback callback)
+ {
+ callback.BeginInvoke(null, EndFireAndForget, callback);
+ }
+
+ public void FireAndForget(System.Threading.WaitCallback callback, object obj)
+ {
+ callback.BeginInvoke(obj, EndFireAndForget, callback);
+ }
+ }
+
public static void FireAndForget(System.Threading.WaitCallback callback)
{
- callback.BeginInvoke(null, EndFireAndForget, callback);
+ FireAndForgetWrapper wrapper = Singleton.GetInstance();
+ wrapper.FireAndForget(callback);
}
public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
{
- callback.BeginInvoke(obj, EndFireAndForget, callback);
+ FireAndForgetWrapper wrapper = Singleton.GetInstance();
+ wrapper.FireAndForget(callback, obj);
}
private static void EndFireAndForget(IAsyncResult ar)
--
cgit v1.1
From 142008121e2e9c5ca5fca5de07b8a14e37279800 Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Mon, 19 Oct 2009 15:19:09 -0700
Subject: * Change Util.FireAndForget to use
ThreadPool.UnsafeQueueUserWorkItem(). This avoids .NET remoting and a
managed->unmanaged->managed jump. Overall, a night and day performance
difference * Initialize the LLClientView prim full update queue to the number
of prims in the scene for a big performance boost * Reordered some
comparisons on hot code paths for a minor speed boost * Removed an
unnecessary call to the expensive DateTime.Now function (if you *have* to get
the current time as opposed to Environment.TickCount, always use
DateTime.UtcNow) * Don't fire the queue empty callback for the Resend
category * Run the outgoing packet handler thread loop for each client
synchronously. It seems like more time was being spent doing the execution
asynchronously, and it made deadlocks very difficult to track down * Rewrote
some expensive math in LandObject.cs * Optimized EntityManager to only lock
on operations that need locking, and use TryGetValue() where possible * Only
update the attachment database when an object is attached or detached * Other
small misc. performance improvements
---
OpenSim/Framework/Util.cs | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
(limited to 'OpenSim/Framework/Util.cs')
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 3203fc1..d5ae3b7 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1273,7 +1273,7 @@ namespace OpenSim.Framework
///
/// Created to work around a limitation in Mono with nested delegates
///
- private class FireAndForgetWrapper
+ /*private class FireAndForgetWrapper
{
public void FireAndForget(System.Threading.WaitCallback callback)
{
@@ -1284,21 +1284,23 @@ namespace OpenSim.Framework
{
callback.BeginInvoke(obj, EndFireAndForget, callback);
}
- }
+ }*/
public static void FireAndForget(System.Threading.WaitCallback callback)
{
- FireAndForgetWrapper wrapper = Singleton.GetInstance();
- wrapper.FireAndForget(callback);
+ //FireAndForgetWrapper wrapper = Singleton.GetInstance();
+ //wrapper.FireAndForget(callback);
+ System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null);
}
public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
{
- FireAndForgetWrapper wrapper = Singleton.GetInstance();
- wrapper.FireAndForget(callback, obj);
+ //FireAndForgetWrapper wrapper = Singleton.GetInstance();
+ //wrapper.FireAndForget(callback, obj);
+ System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj);
}
- private static void EndFireAndForget(IAsyncResult ar)
+ /*private static void EndFireAndForget(IAsyncResult ar)
{
System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
@@ -1306,7 +1308,7 @@ namespace OpenSim.Framework
catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
ar.AsyncWaitHandle.Close();
- }
+ }*/
#endregion FireAndForget Threading Pattern
}
--
cgit v1.1
From 8a336c6860d66b9fbba6922c32e7a57fd355c57e Mon Sep 17 00:00:00 2001
From: Melanie
Date: Thu, 22 Oct 2009 02:28:53 +0100
Subject: Add MaxPoolThreads in startup to limit the size of the thread pool
used for FireAndForget. This lets us limit concurrency to make OpenSim play
nice
---
OpenSim/Framework/Util.cs | 34 ++++++++++++++++++++++------------
1 file changed, 22 insertions(+), 12 deletions(-)
(limited to 'OpenSim/Framework/Util.cs')
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index d5ae3b7..9dfb75e 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -41,12 +41,14 @@ using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Xml;
+using System.Threading;
using log4net;
using Nini.Config;
using Nwc.XmlRpc;
using BclExtras;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
+using Amib.Threading;
namespace OpenSim.Framework
{
@@ -55,6 +57,8 @@ namespace OpenSim.Framework
///
public class Util
{
+ private static SmartThreadPool m_ThreadPool = null;
+
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static uint nextXferID = 5000;
@@ -1293,22 +1297,28 @@ namespace OpenSim.Framework
System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null);
}
- public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
+ public static void SetMaxThreads(int maxThreads)
{
- //FireAndForgetWrapper wrapper = Singleton.GetInstance();
- //wrapper.FireAndForget(callback, obj);
- System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj);
- }
+ STPStartInfo startInfo = new STPStartInfo();
+ startInfo.IdleTimeout = 2000; // 2 seconds
+ startInfo.MaxWorkerThreads = maxThreads;
+ startInfo.MinWorkerThreads = 5;
+ startInfo.StackSize = 524288;
+ startInfo.ThreadPriority = ThreadPriority.Normal;
- /*private static void EndFireAndForget(IAsyncResult ar)
- {
- System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
+ startInfo.StartSuspended = false;
- try { callback.EndInvoke(ar); }
- catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
+ m_ThreadPool = new SmartThreadPool(startInfo);
+ }
- ar.AsyncWaitHandle.Close();
- }*/
+ public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
+ {
+ m_ThreadPool.QueueWorkItem(new WorkItemCallback(delegate(object o)
+ {
+ callback(o);
+ return null;
+ }), obj);
+ }
#endregion FireAndForget Threading Pattern
}
--
cgit v1.1
From 8ce4fd7234bd460652f6159a3b7a21d2bebee05d Mon Sep 17 00:00:00 2001
From: Melanie
Date: Thu, 22 Oct 2009 04:02:26 +0100
Subject: Reduce the default pool threads to 15 (from 30) and the minimum from
5 to 2
---
OpenSim/Framework/Util.cs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
(limited to 'OpenSim/Framework/Util.cs')
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 9dfb75e..7dde6dd 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -1302,7 +1302,7 @@ namespace OpenSim.Framework
STPStartInfo startInfo = new STPStartInfo();
startInfo.IdleTimeout = 2000; // 2 seconds
startInfo.MaxWorkerThreads = maxThreads;
- startInfo.MinWorkerThreads = 5;
+ startInfo.MinWorkerThreads = 2;
startInfo.StackSize = 524288;
startInfo.ThreadPriority = ThreadPriority.Normal;
--
cgit v1.1
From 32ccd5bb40447ea4d96f1181cf73edff3645a55a Mon Sep 17 00:00:00 2001
From: John Hurliman
Date: Wed, 21 Oct 2009 23:03:18 -0700
Subject: * Changed the misc. methods calling
ThreadPool.UnsafeQueueUserWorkItem() to Util.FireAndForget() * Changed
Util.FireAndForget() to use any of five different methods set with
async_call_method in the [Startup] section of OpenSim.ini. Look at the
example config for possible values
---
OpenSim/Framework/Util.cs | 70 ++++++++++++++++++++++++++++++++++-------------
1 file changed, 51 insertions(+), 19 deletions(-)
(limited to 'OpenSim/Framework/Util.cs')
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index d5ae3b7..02f6d12 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -51,6 +51,18 @@ using OpenMetaverse.StructuredData;
namespace OpenSim.Framework
{
///
+ /// The method used by Util.FireAndForget for asynchronously firing events
+ ///
+ public enum FireAndForgetMethod
+ {
+ UnsafeQueueUserWorkItem,
+ QueueUserWorkItem,
+ BeginInvoke,
+ SmartThreadPool,
+ Thread,
+ }
+
+ ///
/// Miscellaneous utility functions
///
public class Util
@@ -70,7 +82,9 @@ namespace OpenSim.Framework
public static readonly Regex UUIDPattern
= new Regex("^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$");
-
+
+ public static FireAndForgetMethod FireAndForgetMethod = FireAndForgetMethod.UnsafeQueueUserWorkItem;
+
///
/// Linear interpolates B<->C using percent A
///
@@ -1273,7 +1287,7 @@ namespace OpenSim.Framework
///
/// Created to work around a limitation in Mono with nested delegates
///
- /*private class FireAndForgetWrapper
+ private class FireAndForgetWrapper
{
public void FireAndForget(System.Threading.WaitCallback callback)
{
@@ -1284,32 +1298,50 @@ namespace OpenSim.Framework
{
callback.BeginInvoke(obj, EndFireAndForget, callback);
}
- }*/
+
+ private static void EndFireAndForget(IAsyncResult ar)
+ {
+ System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
+
+ try { callback.EndInvoke(ar); }
+ catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
+
+ ar.AsyncWaitHandle.Close();
+ }
+ }
public static void FireAndForget(System.Threading.WaitCallback callback)
{
- //FireAndForgetWrapper wrapper = Singleton.GetInstance();
- //wrapper.FireAndForget(callback);
- System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, null);
+ FireAndForget(callback, null);
}
public static void FireAndForget(System.Threading.WaitCallback callback, object obj)
{
- //FireAndForgetWrapper wrapper = Singleton.GetInstance();
- //wrapper.FireAndForget(callback, obj);
- System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj);
+ switch (FireAndForgetMethod)
+ {
+ case FireAndForgetMethod.UnsafeQueueUserWorkItem:
+ System.Threading.ThreadPool.UnsafeQueueUserWorkItem(callback, obj);
+ break;
+ case FireAndForgetMethod.QueueUserWorkItem:
+ System.Threading.ThreadPool.QueueUserWorkItem(callback, obj);
+ break;
+ case FireAndForgetMethod.BeginInvoke:
+ FireAndForgetWrapper wrapper = Singleton.GetInstance();
+ wrapper.FireAndForget(callback, obj);
+ break;
+ case FireAndForgetMethod.SmartThreadPool:
+ Amib.Threading.SmartThreadPool stp = Singleton.GetInstance();
+ stp.QueueWorkItem(delegate(object o) { callback(o); return null; }, obj);
+ break;
+ case FireAndForgetMethod.Thread:
+ System.Threading.Thread thread = new System.Threading.Thread(delegate(object o) { callback(o); });
+ thread.Start(obj);
+ break;
+ default:
+ throw new NotImplementedException();
+ }
}
- /*private static void EndFireAndForget(IAsyncResult ar)
- {
- System.Threading.WaitCallback callback = (System.Threading.WaitCallback)ar.AsyncState;
-
- try { callback.EndInvoke(ar); }
- catch (Exception ex) { m_log.Error("[UTIL]: Asynchronous method threw an exception: " + ex.Message, ex); }
-
- ar.AsyncWaitHandle.Close();
- }*/
-
#endregion FireAndForget Threading Pattern
}
}
--
cgit v1.1