Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions eng/Version.Details.xml
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
2 changes: 1 addition & 1 deletion eng/Versions.props
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
70 changes: 46 additions & 24 deletions src/Microsoft.Diagnostics.ExtensionCommands/ThreadPoolCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,25 @@ public override void Invoke()
}
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");

Expand All @@ -68,10 +78,14 @@ public override void Invoke()
}
}

// 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);
Expand All @@ -87,28 +101,36 @@ public override void Invoke()

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();
}
Expand Down