views:

105

answers:

1

Hi.

I have a C# application, where I have to get the processor load. According to the accepted answer for this question, my options are to either use performance counters from either WMI or the System.Diagnostics namespace. I have a problem with the System.Diagnostics performance counter (as documented here), so my only option is to use WMI. The following code shows how I read the processor load using WMI:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;

namespace ProcessorUtilizationSpike
{
    class Program
    {
        private static ManagementObject processor;

        static void Main(string[] args)
        {
            processor = new ManagementObject("Win32_PerfFormattedData_PerfOS_Processor.Name='_Total'");

            while(true)
            {
                PrintTimedMeasure();
            }
        }

        static void PrintTimedMeasure()
        {
            DateTime start = DateTime.Now;
            UInt64 wmi = WMIMeasure();
            DateTime stop = DateTime.Now;
            Console.WriteLine("wmi : " + wmi + ", time: " + (stop - start));
        }

        static UInt64 WMIMeasure()
        {
            processor.Get();
            return ((UInt64)processor.Properties["PercentProcessorTime"].Value); // this property corresponds to a UInt64, see the Type property.
        }
    }
}

My problem is, that it takes around half a second to retrieve the processor utilization, as can be seen from this typical snippet of output:

wmi : 6, time: 00:00:00.5156250
wmi : 3, time: 00:00:00.5156250
wmi : 4, time: 00:00:00.5000000
wmi : 3, time: 00:00:00.5156250
wmi : 3, time: 00:00:00.5000000

My guess is that at least part of the reason, that it takes so long to sample the load, is that the Get method call also updates other properties of the ManagementObject object. So my question is: How can I make the Get method call update faster? I would guess, that the solution is to somehow tell the ManagementObject object to only update the processor load property, but I don't know how to do that.

As an aside, it is curious that the sample times of the output are so stable around half a second, but I am not sure if that can give any hints toward the solution.

+1  A: 

It has to be slow, there's no other way. The CPU core is either running at full bore or it is turned off by a HALT instruction. From which it is woken up again by an interrupt. The effective CPU load is an average calculated over a period, typically one second. The amount of time it was running divided by the period.

If you make the period shorter then the calculated value gets less accurate. Make it too short and the number will just jump between 0 and 100.

You cannot change the sample rate in the WMI query afaik. You can get quicker (and noisier) updates by reading the performance counter directly. You'll find sample code in my answer in this thread.

Hans Passant
Ok, thanks. If I don't mind some inaccuracy, do you know of any ways of reducing the sampling time?
Boris
Not with WMI, you can do it by using the PerformanceCounter directly.
Hans Passant
Post updated with link to sample code.
Hans Passant
Thanks. Based on my experiments with PerformanceCounter, I get exactly the behaviour you described: If I read countinously from PerformanceCounter, it will quickly spit out either 0 or 50 percent utilization (I have dual core), but if I wait half a second, the values will be similar to those from WMI. So waiting half a second essentially yields an asynchronous version of the WMI method.
Boris
Unfortunately, I cannot use the PerformanceCounter, since it somehow locks my thread-level processor affinity (which I need to change), but I think I can use the WMI sampling time to do other stuff, so I will just have to use WMI asynchronously. Thanks for your clear and fast answer.
Boris
The Timer in that sample code is essential.
Hans Passant