2

I've looked at WMI, negative CPU usage value and Timestamp_Sys100NS in past but I am not doing anything with boot time only delta time between two readings.

When CPU usage is very low i.e. System Idle Process shows as 99% I get Negative CPU usage readings.

I've adapted the code and formula from an MSDN article but can't tell why it might be wrong.

http://msdn.microsoft.com/en-us/library/aa392397%28VS.85%29.aspx

The commented out line at the bottom was only giving me results of 0 or 100, I assume this was because of Integer rounding or something similar so I broke it out into separate parts as doubles before dividing.

        ulong N1 = 0;
        ulong D1 = 0;
        ulong N2 = 0;
        ulong D2 = 0;

        ManagementScope scope = new ManagementScope("\\\\" + Machine + "\\root\\cimv2");
        scope.Connect();

        WqlObjectQuery wqlQuery = new WqlObjectQuery("SELECT PercentProcessorTime, TimeStamp_Sys100NS FROM Win32_PerfRawData_PerfOS_Processor Where Name = '_Total'");
        ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, wqlQuery);

        foreach (ManagementObject proc in searcher.Get())
        {
            N1 = ulong.Parse(proc.Properties["PercentProcessorTime"].Value.ToString());
            D1 = ulong.Parse(proc.Properties["TimeStamp_Sys100NS"].Value.ToString());
        }

        System.Threading.Thread.Sleep(500);

        foreach (ManagementObject proc in searcher.Get())
        {
            N2 = ulong.Parse(proc.Properties["PercentProcessorTime"].Value.ToString());
            D2 = ulong.Parse(proc.Properties["TimeStamp_Sys100NS"].Value.ToString());
        }


        double cpu = N2 - N1;
        double time = D2 - D1;
        var x = (1 - (cpu / time)) * 100;
        //var x = (1 - ((N2 - N1) / (D2 - D1))) * 100;
        context.Response.Write(x);
Community
  • 1
  • 1
Matt
  • 1,436
  • 12
  • 24

1 Answers1

1

I had the exact same problem, I am working with Perl in the example but the logic as you can see below is the same, I used the formula described on that Microsoft document.

$average = (1 - ( ($n2-$n1) / ($d2-$d1) ) ) * 100;

I tried to solve this for days but in the end I just went for the most obvious solution:

if ($average <0) { $average = 0; }

In the end if the CPU is very low no one really cares. In my case I was looking for load spikes and long-range loads. Maybe you are interested in small changes I don't know, to me 1% or 0% is exactly the same.

raz3r
  • 3,071
  • 8
  • 44
  • 66
  • I was just more concerned that if it was wrong there was it wrong else where and by how much. I managed to get -2.3% CPU usage at one point, fair enough it's not much but I want to do some long term averaging to see the load change over time and an increase of 2% a month (every month) can be significant if you need to plan to scale something out before it maxes out a server. However I wouldn't be able to tell if it's just jitter. I've decided to use the .Net Performance Monitor object instead as that seems accurate and I don't have to calculate it myself. – Matt Jul 24 '12 at 11:36
  • Well from my tests I got negative values only few times and only when the CPU was almost idle. In that case instead of taking 0 as a value you can just drop the value and wait for the next one. Beside if you can change architecture there are better ways to calculate CPU usage (you mentioned .Net Performance Monitor for example). Unfortunately I couldn't since I was retrieving those information from a remote server and WMI and SNMP are the only possible way. – raz3r Jul 24 '12 at 12:37