From: Eduardo Velarde <32459232+eduardo-vp@users.noreply.github.com> Date: Sat, 30 Sep 2023 18:30:11 +0000 (-0700) Subject: Update SOS to show the relevant information for the !ThreadPool command when using... X-Git-Tag: accepted/tizen/unified/riscv/20231226.055542~35^2~1^2~72 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=81c0bcb6592d9d41eceafb922f4078d855bf6c7c;p=platform%2Fcore%2Fdotnet%2Fdiagnostics.git Update SOS to show the relevant information for the !ThreadPool command when using the Windows thread pool (#4160) 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 --- diff --git a/eng/Version.Details.xml b/eng/Version.Details.xml index baed3b5b2..0a8ec9334 100644 --- a/eng/Version.Details.xml +++ b/eng/Version.Details.xml @@ -4,13 +4,13 @@ https://github.com/dotnet/symstore 8cc6f03fdbd9c79f0bf9ffbe0a788dca1a81348a - + https://github.com/microsoft/clrmd - 10e87fb192d41e22d5fd0fd54f02ed011726e991 + 547545a301475a7cfd23ce8c2f6e24eddf55d83e - + https://github.com/microsoft/clrmd - 10e87fb192d41e22d5fd0fd54f02ed011726e991 + 547545a301475a7cfd23ce8c2f6e24eddf55d83e diff --git a/eng/Versions.props b/eng/Versions.props index 79d83bccd..e6fb2b5f8 100644 --- a/eng/Versions.props +++ b/eng/Versions.props @@ -45,7 +45,7 @@ 5.0.0 6.0.0 - 3.0.447801 + 3.0.447901 16.11.27-beta1.23180.1 3.0.7 6.0.0 diff --git a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs index 85f7c4d97..621b6a501 100644 --- a/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs +++ b/src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs @@ -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(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(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(), 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(), 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(); }