Changed LogThreadPool to have 4 logging levels. Added console command "debug threadpool level" to set the logging level.
Resolves http://opensimulator.org/mantis/view.php?id=69450.8.0.3
parent
b13214af27
commit
84d7227dfd
|
@ -279,6 +279,17 @@ namespace OpenSim.Framework.Servers
|
||||||
"debug threadpool status",
|
"debug threadpool status",
|
||||||
"Show current debug threadpool parameters.",
|
"Show current debug threadpool parameters.",
|
||||||
HandleDebugThreadpoolStatus);
|
HandleDebugThreadpoolStatus);
|
||||||
|
|
||||||
|
m_console.Commands.AddCommand(
|
||||||
|
"Debug", false, "debug threadpool level",
|
||||||
|
"debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL,
|
||||||
|
"Turn on logging of activity in the main thread pool.",
|
||||||
|
"Log levels:\n"
|
||||||
|
+ " 0 = no logging\n"
|
||||||
|
+ " 1 = only first line of stack trace; don't log common threads\n"
|
||||||
|
+ " 2 = full stack trace; don't log common threads\n"
|
||||||
|
+ " 3 = full stack trace, including common threads\n",
|
||||||
|
HandleDebugThreadpoolLevel);
|
||||||
|
|
||||||
m_console.Commands.AddCommand(
|
m_console.Commands.AddCommand(
|
||||||
"Debug", false, "force gc",
|
"Debug", false, "force gc",
|
||||||
|
@ -432,6 +443,33 @@ namespace OpenSim.Framework.Servers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void HandleDebugThreadpoolLevel(string module, string[] cmdparams)
|
||||||
|
{
|
||||||
|
if (cmdparams.Length < 4)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.Output("Usage: debug threadpool level 0.." + Util.MAX_THREADPOOL_LEVEL);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string rawLevel = cmdparams[3];
|
||||||
|
int newLevel;
|
||||||
|
|
||||||
|
if (!int.TryParse(rawLevel, out newLevel))
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("{0} is not a valid debug level", rawLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (newLevel < 0 || newLevel > Util.MAX_THREADPOOL_LEVEL)
|
||||||
|
{
|
||||||
|
MainConsole.Instance.OutputFormat("{0} is outside the valid debug level range of 0.." + Util.MAX_THREADPOOL_LEVEL, newLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Util.LogThreadPool = newLevel;
|
||||||
|
MainConsole.Instance.OutputFormat("LogThreadPool set to {0}", newLevel);
|
||||||
|
}
|
||||||
|
|
||||||
private void HandleForceGc(string module, string[] args)
|
private void HandleForceGc(string module, string[] args)
|
||||||
{
|
{
|
||||||
Notice("Manually invoking runtime garbage collection");
|
Notice("Manually invoking runtime garbage collection");
|
||||||
|
|
|
@ -110,15 +110,6 @@ namespace OpenSim.Framework
|
||||||
public int MaxConcurrentWorkItems { get; set; }
|
public int MaxConcurrentWorkItems { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
[Flags]
|
|
||||||
public enum DebugFlagsEnum : uint
|
|
||||||
{
|
|
||||||
None = 0,
|
|
||||||
|
|
||||||
// Log every invocation of a thread using the threadpool
|
|
||||||
LogThreadPool = 0x01
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Miscellaneous utility functions
|
/// Miscellaneous utility functions
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -127,13 +118,19 @@ namespace OpenSim.Framework
|
||||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Flags that enable additional debugging.
|
/// Log-level for the thread pool:
|
||||||
|
/// 0 = no logging
|
||||||
|
/// 1 = only first line of stack trace; don't log common threads
|
||||||
|
/// 2 = full stack trace; don't log common threads
|
||||||
|
/// 3 = full stack trace, including common threads
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static DebugFlagsEnum DebugFlags { get; set; }
|
public static int LogThreadPool { get; set; }
|
||||||
|
|
||||||
|
public static readonly int MAX_THREADPOOL_LEVEL = 3;
|
||||||
|
|
||||||
static Util()
|
static Util()
|
||||||
{
|
{
|
||||||
DebugFlags = DebugFlagsEnum.None;
|
LogThreadPool = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static uint nextXferID = 5000;
|
private static uint nextXferID = 5000;
|
||||||
|
@ -1921,6 +1918,7 @@ namespace OpenSim.Framework
|
||||||
public long ThreadFuncNum { get; set; }
|
public long ThreadFuncNum { get; set; }
|
||||||
public string StackTrace { get; set; }
|
public string StackTrace { get; set; }
|
||||||
private string context;
|
private string context;
|
||||||
|
public bool LogThread { get; set; }
|
||||||
|
|
||||||
public IWorkItemResult WorkItem { get; set; }
|
public IWorkItemResult WorkItem { get; set; }
|
||||||
public Thread Thread { get; set; }
|
public Thread Thread { get; set; }
|
||||||
|
@ -1932,6 +1930,7 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
ThreadFuncNum = threadFuncNum;
|
ThreadFuncNum = threadFuncNum;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
LogThread = true;
|
||||||
Thread = null;
|
Thread = null;
|
||||||
Running = false;
|
Running = false;
|
||||||
Aborted = false;
|
Aborted = false;
|
||||||
|
@ -2027,7 +2026,7 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
WaitCallback realCallback;
|
WaitCallback realCallback;
|
||||||
|
|
||||||
bool loggingEnabled = (DebugFlags & DebugFlagsEnum.LogThreadPool) != 0;
|
bool loggingEnabled = LogThreadPool > 0;
|
||||||
|
|
||||||
long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
|
long threadFuncNum = Interlocked.Increment(ref nextThreadFuncNum);
|
||||||
ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context);
|
ThreadInfo threadInfo = new ThreadInfo(threadFuncNum, context);
|
||||||
|
@ -2051,7 +2050,7 @@ namespace OpenSim.Framework
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (loggingEnabled || (threadFuncOverloadMode == 1))
|
if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
|
||||||
m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1);
|
m_log.DebugFormat("Run threadfunc {0} (Queued {1}, Running {2})", threadFuncNum, numQueued1, numRunning1);
|
||||||
|
|
||||||
Culture.SetCurrentCulture();
|
Culture.SetCurrentCulture();
|
||||||
|
@ -2072,7 +2071,7 @@ namespace OpenSim.Framework
|
||||||
threadInfo.Ended();
|
threadInfo.Ended();
|
||||||
ThreadInfo dummy;
|
ThreadInfo dummy;
|
||||||
activeThreads.TryRemove(threadFuncNum, out dummy);
|
activeThreads.TryRemove(threadFuncNum, out dummy);
|
||||||
if (loggingEnabled || (threadFuncOverloadMode == 1))
|
if ((loggingEnabled || (threadFuncOverloadMode == 1)) && threadInfo.LogThread)
|
||||||
m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed()));
|
m_log.DebugFormat("Exit threadfunc {0} ({1})", threadFuncNum, FormatDuration(threadInfo.Elapsed()));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -2097,11 +2096,16 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
string full, partial;
|
string full, partial;
|
||||||
GetFireAndForgetStackTrace(out full, out partial);
|
GetFireAndForgetStackTrace(out full, out partial);
|
||||||
m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}",
|
|
||||||
threadFuncNum, numQueued, numRunningThreadFuncs,
|
|
||||||
(context == null) ? "" : ("(" + context + ") "),
|
|
||||||
loggingEnabled ? full : partial);
|
|
||||||
threadInfo.StackTrace = full;
|
threadInfo.StackTrace = full;
|
||||||
|
threadInfo.LogThread = ShouldLogThread(partial);
|
||||||
|
|
||||||
|
if (threadInfo.LogThread)
|
||||||
|
{
|
||||||
|
m_log.DebugFormat("Queue threadfunc {0} (Queued {1}, Running {2}) {3}{4}",
|
||||||
|
threadFuncNum, numQueued, numRunningThreadFuncs,
|
||||||
|
(context == null) ? "" : ("(" + context + ") "),
|
||||||
|
(LogThreadPool >= 2) ? full : partial);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (FireAndForgetMethod)
|
switch (FireAndForgetMethod)
|
||||||
|
@ -2142,6 +2146,23 @@ namespace OpenSim.Framework
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns whether the thread should be logged. Some very common threads aren't logged,
|
||||||
|
/// to avoid filling up the log.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stackTrace">A partial stack trace of where the thread was queued</param>
|
||||||
|
/// <returns>Whether to log this thread</returns>
|
||||||
|
private static bool ShouldLogThread(string stackTrace)
|
||||||
|
{
|
||||||
|
if (LogThreadPool < 3)
|
||||||
|
{
|
||||||
|
if (stackTrace.Contains("BeginFireQueueEmpty"))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a stack trace for a thread added using FireAndForget().
|
/// Returns a stack trace for a thread added using FireAndForget().
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
Loading…
Reference in New Issue