0

I'm trying to roll my own system performance monitor, in order to delay executing parts of my server code in case of overload (running some web services under IIS). The first thing I'm trying to address is the CPU overload.

I know about the PerformanceCounter issues with having to initialize it with the first call to NextValue() (see this question, among others), so I implemented a very simple static class that caches the data for a second, and only actually accesses the PerformanceCounter object once a second or less. I know it's currently not thread-safe, but I'm not concerned with that in the current prototyping phase.

So, having said all that, here's my current code:

public static class SystemPerformance
{
    private static PerformanceCounter TotalProcessorTimeCounter =
        new PerformanceCounter("Process", "% Processor Time", "_Total");
    private static DateTime CacheRefreshed;
    private static float CachedValue = 0f;
    private const float MIN_DELTA_SECONDS = 1f;

    public static float ReadCPU()
    {
        if ((DateTime.Now - CacheRefreshed).TotalSeconds > MIN_DELTA_SECONDS)
            // Stale cache
            return ReadFromCounter();

        // Good cache
        return CachedValue;
    }

    private static float ReadFromCounter()
    {
        CachedValue = TotalProcessorTimeCounter.NextValue();
        CacheRefreshed = DateTime.Now;
        return CachedValue;
    }
}

... which is all nice and dandy, until I execute it. I tried running it on a Windows 10 x64 VM with 4 cores, and on Windows 7 x64 iron with 4 cores – and in both cases, the returned value hovers around 400, no matter what I do.

The typical values I get are in the range 395–401, with the occasional dip to 365 or a jump to 405. The values I read are in no way correlated to the actual CPU load on either of the machines I tested, as shown by Task Manager, Performance Monitor, or indeed common sense.

The testing methodology is simple: SystemPerformance.ReadCPU() is triggered by a button press in a simple Windows form, and the output is shown in a textbox in the same form. I'm pressing that button while the CPU is quasi-idle, and I also press it while other processes are doing stuff and loading the CPU.

What am I doing wrong? Is this supposed to only return the CPU usage by my application's threads? Am I misinterpreting the data?

Community
  • 1
  • 1
Bogdan Stăncescu
  • 5,320
  • 3
  • 24
  • 25

1 Answers1

2
   new PerformanceCounter("Process", "% Processor Time", "_Total");

Yes, the processor time taken by the _Total number of processes, including the fake "System Idle Process" you see back in Task Manager, will always add up to 400% on a 4 core machine.

You'll probably like the number better if you change "Process" to "Processor". If you want to match the value that Task Manager displays then you need to change "Process" to "Processor Information". A new category that tries to generate a more realistic number that's compensated for a processor with turbo boost, machines with NUMA nodes and the lower perf you get from hyper-threads. You'll want to read this blog post for the nitty-gritty.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • Grrrr! Thank you, I wouldn't have noticed that! For bonus points (that I can't actually grant), is there anything similar to the Unix concept of "load"? Since my final goal is to delay executing stuff when the CPU is overloaded, I obviously rather have something that tells me when it's *overused*, rather than simply a 0-100% indicator that's more useful for underuse... – Bogdan Stăncescu Sep 29 '15 at 10:14