Solved

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

Posted on 2008-06-13
6
2,220 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 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

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

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

Introduction: When experiencing some peculiar problem with the functioning of your PC, how many times has it happened that you look for a solution and even google can’t help? It could be that you are one of the only few people on earth who ma…
This article provides a convenient collection of links to Microsoft provided Security Patches for operating systems that have reached their End of Life support cycle. Included operating systems covered by this article are Windows XP,  Windows Server…
The viewer will learn additional member functions of the vector class. Specifically, the capacity and swap member functions will be introduced.
Two types of users will appreciate AOMEI Backupper Pro: 1 - Those with PCIe drives (and haven't found cloning software that works on them). 2 - Those who want a fast clone of their boot drive (no re-boots needed) and it can clone your drive wh…

632 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