Update SOS to show the relevant information for the !ThreadPool command when using...
authorEduardo Velarde <32459232+eduardo-vp@users.noreply.github.com>
Sat, 30 Sep 2023 18:30:11 +0000 (11:30 -0700)
committerGitHub <noreply@github.com>
Sat, 30 Sep 2023 18:30:11 +0000 (11:30 -0700)
Uses the properties exposed in
https://github.com/microsoft/clrmd/pull/1175 to show relevant Windows
thread pool information if it's enabled

---------

Co-authored-by: Mike McLaughlin <mikem@microsoft.com>
eng/Version.Details.xml
eng/Versions.props
src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs

index baed3b5b21c2eb52e360157fb580629414b58d31..0a8ec93343fef0bf93897f1f5e0c64e09359bcc7 100644 (file)
@@ -4,13 +4,13 @@
       <Uri>https://github.com/dotnet/symstore</Uri>
       <Sha>8cc6f03fdbd9c79f0bf9ffbe0a788dca1a81348a</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.447801">
+    <Dependency Name="Microsoft.Diagnostics.Runtime" Version="3.0.447901">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>10e87fb192d41e22d5fd0fd54f02ed011726e991</Sha>
+      <Sha>547545a301475a7cfd23ce8c2f6e24eddf55d83e</Sha>
     </Dependency>
-    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.447801">
+    <Dependency Name="Microsoft.Diagnostics.Runtime.Utilities" Version="3.0.447901">
       <Uri>https://github.com/microsoft/clrmd</Uri>
-      <Sha>10e87fb192d41e22d5fd0fd54f02ed011726e991</Sha>
+      <Sha>547545a301475a7cfd23ce8c2f6e24eddf55d83e</Sha>
     </Dependency>
   </ProductDependencies>
   <ToolsetDependencies>
index 79d83bccd7da561ae3a5e91af986821bfde5e092..e6fb2b5f86b6636a474790d64bc1d98e60569351 100644 (file)
@@ -45,7 +45,7 @@
     <SystemReflectionMetadataVersion>5.0.0</SystemReflectionMetadataVersion>
     <!-- Other libs -->
     <MicrosoftBclAsyncInterfacesVersion>6.0.0</MicrosoftBclAsyncInterfacesVersion>
-    <MicrosoftDiagnosticsRuntimeVersion>3.0.447801</MicrosoftDiagnosticsRuntimeVersion>
+    <MicrosoftDiagnosticsRuntimeVersion>3.0.447901</MicrosoftDiagnosticsRuntimeVersion>
     <MicrosoftDiaSymReaderNativeVersion>16.11.27-beta1.23180.1</MicrosoftDiaSymReaderNativeVersion>
     <MicrosoftDiagnosticsTracingTraceEventVersion>3.0.7</MicrosoftDiagnosticsTracingTraceEventVersion>
     <MicrosoftExtensionsLoggingVersion>6.0.0</MicrosoftExtensionsLoggingVersion>
index 85f7c4d973906034f69a860c19ebe27058afbdfb..621b6a501c5358194a086b59a79d7d79a8fbd70e 100644 (file)
@@ -33,15 +33,25 @@ namespace Microsoft.Diagnostics.ExtensionCommands
             }
             else
             {
-                Table output = new(Console, Text.WithWidth(17), Text);
-                output.WriteRow("CPU utilization:", $"{threadPool.CpuUtilization}%");
-                output.WriteRow("Workers Total:", threadPool.ActiveWorkerThreads + threadPool.IdleWorkerThreads + threadPool.RetiredWorkerThreads);
-                output.WriteRow("Workers Running:", threadPool.ActiveWorkerThreads);
-                output.WriteRow("Workers Idle:", threadPool.IdleWorkerThreads);
-                output.WriteRow("Worker Min Limit:", threadPool.MinThreads);
-                output.WriteRow("Worker Max Limit:", threadPool.MaxThreads);
+                string threadpoolType = threadPool.UsingWindowsThreadPool ? "Windows" : "Portable";
+                Console.WriteLine($"Using the {threadpoolType} thread pool.");
                 Console.WriteLine();
 
+                Table output = new(Console, Text.WithWidth(17), Text);
+                if (threadPool.UsingWindowsThreadPool)
+                {
+                    output.WriteRow("Thread count:", threadPool.WindowsThreadPoolThreadCount);
+                }
+                else
+                {
+                    output.WriteRow("CPU utilization:", $"{threadPool.CpuUtilization}%");
+                    output.WriteRow("Workers Total:", threadPool.ActiveWorkerThreads + threadPool.IdleWorkerThreads + threadPool.RetiredWorkerThreads);
+                    output.WriteRow("Workers Running:", threadPool.ActiveWorkerThreads);
+                    output.WriteRow("Workers Idle:", threadPool.IdleWorkerThreads);
+                    output.WriteRow("Worker Min Limit:", threadPool.MinThreads);
+                    output.WriteRow("Worker Max Limit:", threadPool.MaxThreads);
+                }
+                Console.WriteLine();
                 ClrType threadPoolType = Runtime.BaseClassLibrary.GetTypeByName("System.Threading.ThreadPool");
                 ClrStaticField usePortableIOField = threadPoolType?.GetStaticFieldByName("UsePortableThreadPoolForIO");
 
@@ -68,10 +78,14 @@ namespace Microsoft.Diagnostics.ExtensionCommands
                     }
                 }
 
-                // We will assume that if UsePortableThreadPoolForIO field is deleted from ThreadPool then we are always
-                // using C# version.
-                bool usingPortableCompletionPorts = threadPool.Portable && (usePortableIOField is null || usePortableIOField.Read<bool>(usePortableIOField.Type.Module.AppDomain));
-                if (!usingPortableCompletionPorts)
+                /*
+                The IO completion thread pool exists in .NET 7 and earlier
+                It is the only option in .NET 6 and below. The UsePortableThreadPoolForIO field doesn't exist.
+                In .NET 7, the UsePortableThreadPoolForIO field exists and is true by default, in which case the IO completion thread pool is not used, but that can be changed through config
+                In .NET 8, the UsePortableThreadPoolForIO field doesn't exist and the IO completion thread pool doesn't exist. However, in .NET 8, GetThreadpoolData returns E_NOTIMPL.
+                */
+                bool usingIOCompletionThreadPool = threadPool.HasLegacyData && (usePortableIOField is null || !usePortableIOField.Read<bool>(usePortableIOField.Type.Module.AppDomain));
+                if (usingIOCompletionThreadPool)
                 {
                     output.Columns[0] = output.Columns[0].WithWidth(19);
                     output.WriteRow("Completion Total:", threadPool.TotalCompletionPorts);
@@ -87,28 +101,36 @@ namespace Microsoft.Diagnostics.ExtensionCommands
 
                 if (PrintHillClimbingLog)
                 {
-                    HillClimbingLogEntry[] hcl = threadPool.EnumerateHillClimbingLog().ToArray();
-                    if (hcl.Length > 0)
+                    if (threadPool.UsingWindowsThreadPool)
+                    {
+                        Console.WriteLine("Hill Climbing Log is not supported by the Windows thread pool.");
+                        Console.WriteLine();
+                    }
+                    else
                     {
-                        output = new(Console, Text.WithWidth(10).WithAlignment(Align.Right), Column.ForEnum<HillClimbingTransition>(), Integer, Integer, Text.WithAlignment(Align.Right));
+                        HillClimbingLogEntry[] hcl = threadPool.EnumerateHillClimbingLog().ToArray();
+                        if (hcl.Length > 0)
+                        {
+                            output = new(Console, Text.WithWidth(10).WithAlignment(Align.Right), Column.ForEnum<HillClimbingTransition>(), Integer, Integer, Text.WithAlignment(Align.Right));
 
-                        Console.WriteLine("Hill Climbing Log:");
-                        output.WriteHeader("Time", "Transition", "#New Threads", "#Samples", "Throughput");
+                            Console.WriteLine("Hill Climbing Log:");
+                            output.WriteHeader("Time", "Transition", "#New Threads", "#Samples", "Throughput");
 
-                        int end = hcl.Last().TickCount;
-                        foreach (HillClimbingLogEntry entry in hcl)
-                        {
-                            Console.CancellationToken.ThrowIfCancellationRequested();
-                            output.WriteRow($"{(entry.TickCount - end)/1000.0:0.00}", entry.StateOrTransition, entry.NewThreadCount, entry.SampleCount, $"{entry.Throughput:0.00}");
-                        }
+                            int end = hcl.Last().TickCount;
+                            foreach (HillClimbingLogEntry entry in hcl)
+                            {
+                                Console.CancellationToken.ThrowIfCancellationRequested();
+                                output.WriteRow($"{(entry.TickCount - end) / 1000.0:0.00}", entry.StateOrTransition, entry.NewThreadCount, entry.SampleCount, $"{entry.Throughput:0.00}");
+                            }
 
-                        Console.WriteLine();
+                            Console.WriteLine();
+                        }
                     }
                 }
             }
 
             // We can print managed work items even if we failed to request the ThreadPool.
-            if (PrintWorkItems && (threadPool is null || threadPool.Portable))
+            if (PrintWorkItems && (threadPool is null || threadPool.UsingPortableThreadPool || threadPool.UsingWindowsThreadPool))
             {
                 DumpWorkItems();
             }