Solved

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

Posted on 2008-06-13
6
2,046 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
ID: 21783454
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
ID: 21795151
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
ID: 21803046
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
ID: 21901103
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
ID: 21904699
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

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Step by step guide to Clean and Sort your windows registry! Introduction: Always remember: A Clean registry = Better performance = Save your invaluable time In this article we're going to clear our registry manually! Yes, manually! The e…
Go is an acronym of golang, is a programming language developed Google in 2007. Go is a new language that is mostly in the C family, with significant input from Pascal/Modula/Oberon family. Hence Go arisen as low-level language with fast compilation…
The goal of the video will be to teach the user the difference and consequence of passing data by value vs passing data by reference in C++. An example of passing data by value as well as an example of passing data by reference will be be given. Bot…
The viewer will be introduced to the technique of using vectors in C++. The video will cover how to define a vector, store values in the vector and retrieve data from the values stored in the vector.

862 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

27 Experts available now in Live!

Get 1:1 Help Now