private static void OnTpRunning(ClrRuntime runtime, string args) { // Use ClrMD as normal, but ONLY cache the copy of ClrRuntime (this.Runtime). All other // types you get out of ClrMD (such as ClrHeap, ClrTypes, etc) should be discarded and // reobtained every run. ClrThreadPool threadPool = runtime.ThreadPool; ClrHeap heap = runtime.Heap; // Console.WriteLine now writes to the debugger. ClrMDHelper helper = new ClrMDHelper(runtime); try { Console.WriteLine(string.Format( "\r\nCPU = {0}%% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})", threadPool.CpuUtilization.ToString(), threadPool.TotalThreads.ToString(), threadPool.IdleThreads.ToString(), threadPool.RunningThreads.ToString(), runtime.Threads.Count(t => t.IsThreadpoolWorker && !t.IsThreadpoolCompletionPort && !t.IsAlive && !t.IsThreadpoolGate && !t.IsThreadpoolTimer && !t.IsThreadpoolWait).ToString(), threadPool.MaxThreads.ToString() )); // show the running worker threads DumpRunningThreadpoolThreads(runtime, helper); } catch (Exception x) { Console.WriteLine(x.Message); } }
public static string CreateMarkup(this ClrThreadPool threadpool) { var html = new StringBuilder(); html.Append($"<div>idle: {threadpool.IdleThreads}</div>"); html.Append($"<div>running: {threadpool.RunningThreads}</div>"); html.Append($"<div>total: {threadpool.TotalThreads}</div>"); return(html.ToString()); }
/// <summary> /// Initializes a new instance of the <see cref="ClrThreadPoolAdapter" /> class. /// </summary> /// <param name="threadPool">The thread pool.</param> /// <exception cref="ArgumentNullException">threadPool</exception> /// <inheritdoc /> public ClrThreadPoolAdapter(IConverter converter, ClrThreadPool threadPool) : base(converter) { ThreadPool = threadPool ?? throw new ArgumentNullException(nameof(threadPool)); CpuUtilization = ThreadPool.CpuUtilization; FreeCompletionPortCount = ThreadPool.FreeCompletionPortCount; IdleThreads = ThreadPool.IdleThreads; MaxCompletionPorts = ThreadPool.MaxCompletionPorts; MaxFreeCompletionPorts = ThreadPool.MaxFreeCompletionPorts; MaxThreads = ThreadPool.MaxThreads; MinCompletionPorts = ThreadPool.MinCompletionPorts; MinThreads = ThreadPool.MinThreads; RunningThreads = ThreadPool.RunningThreads; TotalThreads = ThreadPool.TotalThreads; }
private void PrintThreadPoolInfo() { if (context.Runtime != null) { ClrThreadPool threadPool = this.context.Runtime.GetThreadPool(); if (threadPool != null) { context.WriteLine("Total threads: {0}", threadPool.TotalThreads); context.WriteLine("Running threads: {0}", threadPool.RunningThreads); context.WriteLine("Max threads: {0}", threadPool.MaxThreads); context.WriteLine("Min threads: {0}", threadPool.MinThreads); context.WriteLine("Idle threads: {0}", threadPool.IdleThreads); context.WriteLine("CPU utilization {0}% (estimated)", threadPool.CpuUtilization); } } }
private static void OnTpRunning(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args) { // Must be the first thing in our extension. if (!InitApi(client)) { return; } // Use ClrMD as normal, but ONLY cache the copy of ClrRuntime (this.Runtime). All other // types you get out of ClrMD (such as ClrHeap, ClrTypes, etc) should be discarded and // reobtained every run. ClrThreadPool threadPool = Runtime.GetThreadPool(); ClrHeap heap = Runtime.GetHeap(); // Console.WriteLine now writes to the debugger. ClrMDHelper helper = new ClrMDHelper(Runtime); try { Console.WriteLine(string.Format( "\r\nCPU = {0}%% for {1} threads (#idle = {2} + #running = {3} | #dead = {4} | #max = {5})", threadPool.CpuUtilization.ToString(), threadPool.TotalThreads.ToString(), threadPool.IdleThreads.ToString(), threadPool.RunningThreads.ToString(), Runtime.Threads.Count(t => t.IsThreadpoolWorker && !t.IsThreadpoolCompletionPort && !t.IsAlive && !t.IsThreadpoolGate && !t.IsThreadpoolTimer && !t.IsThreadpoolWait).ToString(), threadPool.MaxThreads.ToString() )); // show the running worker threads DumpRunningThreadpoolThreads(helper); } catch (Exception x) { Console.WriteLine(x.Message); } }
public static void OnTpQueues(IntPtr client, [MarshalAs(UnmanagedType.LPStr)] string args) { // Must be the first thing in our extension. if (!InitApi(client)) { return; } Dictionary <string, WorkInfo> _workItems = new Dictionary <string, WorkInfo>(); int _workItemCount = 0; Dictionary <string, WorkInfo> _tasks = new Dictionary <string, WorkInfo>(); int _taskCount = 0; // Use ClrMD as normal, but ONLY cache the copy of ClrRuntime (this.Runtime). All other // types you get out of ClrMD (such as ClrHeap, ClrTypes, etc) should be discarded and // reobtained every run. ClrThreadPool threadPool = Runtime.GetThreadPool(); ClrHeap heap = Runtime.GetHeap(); // Console.WriteLine now writes to the debugger. ClrMDHelper helper = new ClrMDHelper(Runtime); // The ThreadPool is keeping track of the pending work items into two different areas: // - a global queue: stored by ThreadPoolWorkQueue instances of the ThreadPoolGlobals.workQueue static field // - several per thread (TLS) local queues: stored in SparseArray<ThreadPoolWorkQueue+WorkStealingQueue> linked from ThreadPoolWorkQueue.allThreadQueues static fields // both are using arrays of Task or QueueUserWorkItemCallback // // NOTE: don't show other thread pool related topics such as timer callbacks or wait objects // try { Console.WriteLine("global work item queue________________________________"); foreach (var item in helper.EnumerateGlobalThreadPoolItems()) { switch (item.Type) { case ThreadRoot.Task: Console.Write(string.Format("<link cmd=\"!do {0:X16}\">0x{0:X16}</link> Task", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_tasks, item.MethodName, ref _taskCount); break; case ThreadRoot.WorkItem: Console.Write(string.Format("<link cmd=\"!do {0}\">0x{0:X16}</link> Work", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_workItems, item.MethodName, ref _workItemCount); break; default: Console.WriteLine(string.Format("<link cmd=\"!do {0}\">0x{0:X16}</link> {1}", item.Address, item.MethodName)); break; } } // look into the local stealing queues in each thread TLS // hopefully, they are all stored in static (one per app domain) instance // of ThreadPoolWorkQueue.SparseArray<ThreadPoolWorkQueue.WorkStealingQueue> // Console.WriteLine("\r\nlocal per thread work items_____________________________________"); try { foreach (var item in helper.EnumerateLocalThreadPoolItems()) { switch (item.Type) { case ThreadRoot.Task: Console.Write(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> Task", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_tasks, item.MethodName, ref _taskCount); break; case ThreadRoot.WorkItem: Console.Write(string.Format("<link cmd=\"!do {0}\">0x{0:X16}</link> Work", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_workItems, item.MethodName, ref _workItemCount); break; default: Console.WriteLine(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> {1}", item.Address, item.MethodName)); break; } } } finally { Console.WriteLine(""); // provide a summary sorted by count // tasks first if any if (_tasks.Values.Count > 0) { foreach (var item in _tasks.Values.OrderBy(wi => wi.Count)) { Console.WriteLine(string.Format(" {0,4} Task {1}", item.Count.ToString(), item.Name)); } Console.WriteLine(" ----"); Console.WriteLine(string.Format(" {0,4}\r\n", _taskCount.ToString())); } // then QueueUserWorkItem next if any if (_workItems.Values.Count > 0) { foreach (var item in _workItems.Values.OrderBy(wi => wi.Count)) { Console.WriteLine(string.Format(" {0,4} Work {1}", item.Count.ToString(), item.Name)); } Console.WriteLine(" ----"); Console.WriteLine(string.Format(" {0,4}\r\n", _workItemCount.ToString())); } } } catch (Exception x) { Console.WriteLine(x.Message); } }
public ThreadPoolInformation(ClrDump clrDump, ClrThreadPool threadPool) { ClrDump = clrDump; ThreadPool = threadPool; }
public static void OnTpQueues(ClrRuntime runtime, string args) { Dictionary <string, WorkInfo> _workItems = new Dictionary <string, WorkInfo>(); int _workItemCount = 0; Dictionary <string, WorkInfo> _tasks = new Dictionary <string, WorkInfo>(); int _taskCount = 0; // Use ClrMD as normal, but ONLY cache the copy of ClrRuntime (this.Runtime). All other // types you get out of ClrMD (such as ClrHeap, ClrTypes, etc) should be discarded and // reobtained every run. ClrThreadPool threadPool = runtime.ThreadPool; ClrHeap heap = runtime.Heap; // Console.WriteLine now writes to the debugger. ClrMDHelper helper = new ClrMDHelper(runtime); // The ThreadPool is keeping track of the pending work items into two different areas: // - a global queue // - several per thread (TLS) local queues // // NOTE: don't show other thread pool related topics such as timer callbacks or wait objects // try { Console.WriteLine("global work item queue________________________________"); foreach (var item in helper.EnumerateGlobalThreadPoolItems()) { switch (item.Type) { case ThreadRoot.Task: Console.Write(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> Task", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_tasks, item.MethodName, ref _taskCount); break; case ThreadRoot.WorkItem: Console.Write(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> Work", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_workItems, item.MethodName, ref _workItemCount); break; default: Console.WriteLine(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> {1}", item.Address, item.MethodName)); break; } } Console.WriteLine("\r\nlocal per thread work items_____________________________________"); try { foreach (var item in helper.EnumerateLocalThreadPoolItems()) { switch (item.Type) { case ThreadRoot.Task: Console.Write(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> Task", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_tasks, item.MethodName, ref _taskCount); break; case ThreadRoot.WorkItem: Console.Write(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> Work", item.Address)); Console.WriteLine(" | " + item.MethodName); UpdateStats(_workItems, item.MethodName, ref _workItemCount); break; default: Console.WriteLine(string.Format("<link cmd=\"!do {0:X}\">0x{0:X16}</link> {1}", item.Address, item.MethodName)); break; } } } finally { Console.WriteLine(""); // provide a summary sorted by count // tasks first if any if (_tasks.Values.Count > 0) { foreach (var item in _tasks.Values.OrderBy(wi => wi.Count)) { Console.WriteLine(string.Format(" {0,4} Task {1}", item.Count.ToString(), item.Name)); } Console.WriteLine(" ----"); Console.WriteLine(string.Format(" {0,4}\r\n", _taskCount.ToString())); } // then QueueUserWorkItem next if any if (_workItems.Values.Count > 0) { foreach (var item in _workItems.Values.OrderBy(wi => wi.Count)) { Console.WriteLine(string.Format(" {0,4} Work {1}", item.Count.ToString(), item.Name)); } Console.WriteLine(" ----"); Console.WriteLine(string.Format(" {0,4}\r\n", _workItemCount.ToString())); } } } catch (Exception x) { Console.WriteLine(x.Message); } }