-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Description
Description
On Mac OS X, with Apple Silicon, the System.Diagnostics.Process class returns incorrect (substantially underreported - ms when it should be seconds) CPU usage times for the process (and probably for the thread-level stats too).
I discovered this while writing a function to tune the max # of worker threads in the ThreadPool as it reduces CPU usage from 700% to 120% while increasing throughput for my project (pwrdrvr/lambda-dispatch#109). I was always computing that 0 threads would be needed because CPU usage was only going up by 20 ms per 5 seconds despite using 700% CPU.
Reproduction Steps
- Obtain Apple Silicon Mac
- Run example
Buildable example repo:
https://github.com/huntharo/dotnet-macos-apple-silicon-cpu-time
using System.Diagnostics;
// Initial CPU usage:
var initialCpuUsageMs = Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds;
Console.WriteLine($"Initial CPU usage: {Process.GetCurrentProcess().TotalProcessorTime}");
// Burn 5 seconds of CPU time
var sw = Stopwatch.StartNew();
while (sw.ElapsedMilliseconds < 5000) { }
// Final CPU usage:
Console.WriteLine($"Final CPU usage: {Process.GetCurrentProcess().TotalProcessorTime}");
// Delta:
Console.WriteLine($"Delta CPU usage (ms): {Process.GetCurrentProcess().TotalProcessorTime.TotalMilliseconds - initialCpuUsageMs}");
// Wall time:
Console.WriteLine($"Wall time (ms): {sw.ElapsedMilliseconds}");Expected behavior
CPU time for burning 5 seconds of CPU in a tight loop should be ~5 seconds as reported in top, activity monitor, etc.
Actual behavior
CPU time is reported as 120 ms
Regression?
This does not appear to be a regression but rather a missing multiplier that "just worked" until Apple Silicon was released and the multiplier changed from 1.
Known Workarounds
None, other than obtaining the multiplier and applying it to the TimeSpan which makes no sense because the TimeSpan should be a duration not a value to be multiplied to then become a duration.
Configuration
- ARM64
- Mac OS X Sonoma 14.0
- .NET 8.0.101
- This is specific to Apple Silicon as far as I can tell
Other information
Raw Mach Time API In general prefer to use the <time.h> API clock_gettime_nsec_np(3), which deals in the same clocks (and more) in ns units. Conversion of ns to (resp. from) tick units as returned by the mach time APIs is performed by division (resp. multiplication) with the fraction returned by mach_timebase_info().
https://developer.apple.com/documentation/driverkit/mach_timebase_info_data_t
This stackoverflow post contains a very small sliver of info about the API that needs to be called:
https://stackoverflow.com/a/72915413/878903