Solved

PDH query for counter "\Processor(0)\% Processor Time" always returns 99

Posted on 2008-06-13
6
2,015 Views
Last Modified: 2013-12-10
I am trying to use the PDH library to retreive the CPU load for each CPU on a multi-processor PC but the query always returns 99.  It does not matter what processor I query for, even non-existent processors return 99.
HQUERY hQuery;

HCOUNTER hCounterCPU0, hCounterCPU1, hCounterCPU2;

PDH_FMT_COUNTERVALUE ppdhValue0, ppdhValue1, ppdhValue2;

long lCPU0Util, lCPU1Util, lCPU2Util;

 

wchar_t* szProcess0Time = _T("\\Processor(0)\\% Processor Time");

wchar_t* szProcess1Time = _T("\\Processor(1)\\% Processor Time");

wchar_t* szProcess2Time = _T("\\Processor(1000)\\% Processor Time");

 

if (PdhOpenQuery(NULL, 1, &hQuery) != ERROR_SUCCESS)

{

   ASSERT(false);

   return;

}

 

if ((PdhAddCounter(hQuery, szProcess0Time, NULL, &hCounterCPU0) !=

     ERROR_SUCCESS) ||

    (PdhAddCounter(hQuery, szProcess0Time, NULL, &hCounterCPU1) !=  

     ERROR_SUCCESS) ||

    (PdhAddCounter(hQuery, szProcess1Time, NULL, &hCounterCPU2) != 

    ERROR_SUCCESS))

{

   ASSERT(false);

   return;

}

 

if (PdhCollectQueryData(hQuery) != ERROR_SUCCESS)

{

   ASSERT(false);

   return;

}

 

lCPU0Util = 0;

lCPU1Util = 0;

lCPU2Util = 0;

 

if (PdhGetFormattedCounterValue(hCounterCPU0, 

                                PDH_FMT_LONG, NULL, 

                                &ppdhValue0) == ERROR_SUCCESS)

{

   lCPU0Util = ppdhValue0.longValue;

}

 

if (PdhGetFormattedCounterValue(hCounterCPU1, 

                                PDH_FMT_LONG, NULL, 

                                &ppdhValue1) == ERROR_SUCCESS)

{

   lCPU1Util = ppdhValue1.longValue;

}

 

if (PdhGetFormattedCounterValue(hCounterCPU2, 

                                PDH_FMT_LONG, NULL, 

                                &ppdhValue2) == ERROR_SUCCESS)

{

   lCPU2Util = ppdhValue2.longValue;

}

Open in new window

0
Comment
Question by:Eigel
  • 3
  • 2
6 Comments
 
LVL 13

Accepted Solution

by:
josgood earned 400 total points
Comment Utility
Issue an initial
   PdhCollectQueryData(hQuery);
and just throw it away.  Then sleep briefly, such as
   ::Sleep(1000);
and then issue the
   PdhCollectQueryData(hQuery);
that you really care about.

PDH often requires two snapshots in order to create valid data, and that seems to be true on my Core Duo.

I suggest writing a loop to check this, since the actual CPU usage may round down to zero in any one second.  Writing the values several times to sd::cout will show what you're getting.  You might also start some other process while running this test, so you can see some actual CPU time being consumed.

The test loop might look something like
   PdhCollectQueryData(hQuery);
   for (int i = 0; i < 25; i++) {
      ::Sleep(1000);
      if (PdhCollectQueryData(hQuery) != ERROR_SUCCESS) {
      ...your code here
   }
0
 

Author Comment

by:Eigel
Comment Utility
josgood,  thanks for the Sleep()/re-query idea - that did in fact help but did not completely solve my problem.  Let me give you some more details about the test that I am running.  I am running the test PC on a network with a very high traffic load, around 900Mbps.  When I run the task manager performance monitor (with no applications running) I see one core (obviously running the NIC driver) running at 25%-35% of its utilization while the other core hangs out around 0%.  The overall CPU usage is reported as anywhere from 12% to 18%, clearly the average of the two cores.  After I added your Sleep() and re-query, I now get the overall CPU usage (i.e., something between 12% and 18%, and exactly the same value reported for both processors for each query) but not the individual core values that I can see on the graph.  Any ideas on how to get those individual core utilization values?  Thanks in advance, Vickie.
0
 
LVL 13

Assisted Solution

by:josgood
josgood earned 400 total points
Comment Utility
I'm sorry, but I don't have an answer.  I spent over an hour on this last night, but came up dry.

I wrote a quick application, using the PdhBrowseCounters API to see what counters are available on my core Duo with WinXP.  I didn't find anything applicable other than ProcessorTime -- nothing for cores or logical processors.  I think your Processor(0), etc. must be the way to do it.

Yet I get the same results as you and am currently baffled.

Do anyone at work have an MSDN subscription?  Could you open an incident with Microsoft technical support (costs money)?

That's all I have at the moment.
0
 

Author Comment

by:Eigel
Comment Utility
Here is the code that I got from Microsoft Technical Support (for $99) that works correctly.
// GetPerformanceCounter.cpp : Defines the entry point for the console application.

//
 

#include "stdafx.h"

#include <windows.h>

#include <pdh.h>

#include <stdio.h>
 

BOOL WINAPI GetCounterValues(LPTSTR serverName);
 

void main(int argc, char *argv[])

{

    //if (argc > 1)

    //{

        // argv[1] - Server Name
 

        GetCounterValues(".");
 

}
 

BOOL WINAPI GetCounterValues(LPTSTR serverName)

{

    PDH_STATUS s;
 

    HQUERY hQuery;
 

    // Array to specify the performance object, counter and instance for

    // which performance data should be collected.
 

    // typedef struct _PDH_COUNTER_PATH_ELEMENTS {

    //   LPTSTR  szMachineName;

    //   LPTSTR  szObjectName;

    //   LPTSTR  szInstanceName;

    //   LPTSTR  szParentInstance;

    //   DWORD   dwInstanceIndex;

    //   LPTSTR  szCounterName;

    // } PDH_COUNTER_PATH_ELEMENTS, *PPDH_COUNTER_PATH_ELEMENTS;
 

    // Each element in the array is a PDH_COUNTER_PATH_ELEMENTS structure.

    PDH_COUNTER_PATH_ELEMENTS cpe[] =

    {

        { NULL, "Processor", "0", NULL, -1, "% Processor Time" },

        { NULL, "Processor", "1", NULL, -1, "% Processor Time" },

        { NULL, "Processor", "_Total", NULL, -1, "% Processor Time" }

    };
 

    HCOUNTER hCounter[sizeof(cpe)/sizeof(cpe[0])];
 

    char szFullPath[MAX_PATH];

    DWORD cbPathSize;

    int   i, j;
 

    BOOL  ret = FALSE;
 

    PDH_FMT_COUNTERVALUE counterValue;
 

    // Only do this setup once.

    if ((s = PdhOpenQuery(NULL, 0, &hQuery)) != ERROR_SUCCESS)

    {

        fprintf(stderr, "POQ failed %08x\n", s);

        return ret;

    }
 

    for (i = 0; i < sizeof(hCounter)/sizeof(hCounter[0]); i++)

    {

        cbPathSize = sizeof(szFullPath);
 

        cpe[i].szMachineName = serverName;
 

        if ((s = PdhMakeCounterPath(&cpe[i],

            szFullPath, &cbPathSize, 0)) != ERROR_SUCCESS)

        {

            fprintf(stderr,"MCP failed %08x\n", s);

            return ret;

        }
 

        if (cpe[i].szInstanceName)

        {

            printf("Adding [%s\\%s\\%s]\n",

                    cpe[i].szObjectName,

                    cpe[i].szCounterName,

                    cpe[i].szInstanceName);

        }

        else

            printf("Adding [%s\\%s]\n",

                    cpe[i].szObjectName,

                    cpe[i].szCounterName);
 

        if ((s = PdhAddCounter(hQuery, szFullPath, 0, &hCounter[i]))

            != ERROR_SUCCESS)

        {

            fprintf(stderr, "PAC failed %08x\n", s);

            return ret;

        }

    }
 

    for (i = 0; i < 20; i++)

    {

        Sleep(100);
 

        // Collect data as often as you need to.

        if ((s = PdhCollectQueryData(hQuery)) != ERROR_SUCCESS)

        {

            fprintf(stderr, "PCQD failed %08x\n", s);

            return ret;

        }
 

        if (i == 0) continue;
 

        // Extract the calculated performance counter value for each counter or

        // instance.

        for (j = 0; j < sizeof(hCounter)/sizeof(hCounter[0]); j++)

        {

            if ((s = PdhGetFormattedCounterValue(hCounter[j], PDH_FMT_DOUBLE,

                NULL, &counterValue)) != ERROR_SUCCESS)

            {

                fprintf(stderr, "PGFCV failed %08x\n", s);

                continue;

            }

            if (cpe[j].szInstanceName)

            {

                printf("%s\\%s\\%s\t\t : [%3.3f]\n",

                    cpe[j].szObjectName,

                    cpe[j].szCounterName,

                    cpe[j].szInstanceName,

                    counterValue.doubleValue);

            }

            else

                printf("%s\\%s\t\t : [%3.3f]\n",

                    cpe[j].szObjectName,

                    cpe[j].szCounterName,

                    counterValue.doubleValue);

        }

    }
 

    // Remove all the counters from the query.

    for (i = 0; i < sizeof(hCounter)/sizeof(hCounter[0]); i++)

    {

        PdhRemoveCounter(hCounter[i]);

    }
 

    // Only do this cleanup once.

    PdhCloseQuery(hQuery);
 

    return TRUE;

}

Open in new window

0
 
LVL 13

Assisted Solution

by:josgood
josgood earned 400 total points
Comment Utility
I believe I should get credit for answering the original question.  The Asker acknowledged that my answer helped and I believe it was complete for the original question.

I concede I did not have an answer for the follow-up question.
0

Featured Post

Get up to 2TB FREE CLOUD per backup license!

An exclusive Black Friday offer just for Expert Exchange audience! Buy any of our top-rated backup solutions & get up to 2TB free cloud per system! Perform local & cloud backup in the same step, and restore instantly—anytime, anywhere. Grab this deal now before it disappears!

Join & Write a Comment

We have adopted the strategy to use Computers in Student Labs as the bulletin boards. The same target can be achieved by using a Login Notice feature in Group policy but it’s not as attractive as graphical wallpapers with message which grabs the att…
It is only natural that we all want our PCs to be in good working order, improved system performance, so that is exactly how programs are advertised to entice. They say things like:            •      PC crashes? Get registry cleaner to repair it!    …
The viewer will learn how to pass data into a function in C++. This is one step further in using functions. Instead of only printing text onto the console, the function will be able to perform calculations with argumentents given by the user.
The viewer will learn how to user default arguments when defining functions. This method of defining functions will be contrasted with the non-default-argument of defining functions.

772 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now