Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Getting CPU Usage in a Multiprocessor Machine

0.00/5 (No votes)
30 May 2005 1  
Getting CPU usage in a multiprocessor machine.

Introduction

Ever since I saw 'Performance' application on Windows 2000, I wondered if there is a way / Windows API to programmatically determine CPU usage for each of the individual CPUs in a multi-processor machine. Though there are many articles for getting the CPU usage, none helped when it came to multi-processor machines.

After some digging in MSDN, I could find WMI (Windows Management and Instrumentation) has a few performance counter classes. I chose to use the Win32_PerfRawData_PerfOS_Processor class in this case as it is supported on Windows 2000 onwards.

How to use it?

Follow these seven steps:

Step 1: Initialize COM:

CoInitializeEx(0, COINIT_MULTITHREADED);

Step 2: Set COM security levels:

CoInitializeSecurity(
        NULL, 
        -1,                          // COM authentication

        NULL,                        // Authentication services

        NULL,                        // Reserved

        RPC_C_AUTHN_LEVEL_DEFAULT,   // Default authentication 

        RPC_C_IMP_LEVEL_IMPERSONATE, // Default Impersonation  

        NULL,                        // Authentication info

        EOAC_NONE,                   // Additional capabilities 

        NULL                         // Reserved

        );

Step 3: Obtain the initial locator to WMI:

   IWbemLocator *pLoc = NULL;

   hres = CoCreateInstance(
        CLSID_WbemLocator,             
        0, 
        CLSCTX_INPROC_SERVER, 
        IID_IWbemLocator, (LPVOID *) &pLoc);

Step 4: Connect to WMI through the IWbemLocator::ConnectServer method:

    IWbemServices *pSvc = NULL;
 
    // Connect to the root\cimv2 namespace with

    // the current user and obtain pointer pSvc

    // to make IWbemServices calls.

    hres = pLoc->ConnectServer(
         _bstr_t(L"ROOT\\CIMV2"), // Object path of WMI namespace

         NULL,                    // User name. NULL = current user

         NULL,                    // User password. NULL = current

         0,                       // Locale. NULL indicates current

         NULL,                    // Security flags.

         0,                       // Authority (e.g. Kerberos)

         0,                       // Context object 

         &pSvc                    // pointer to IWbemServices proxy

         );

Step 5: Set security levels on the proxy:

CoSetProxyBlanket(
       pSvc,                        // Indicates the proxy to set

       RPC_C_AUTHN_WINNT,           // RPC_C_AUTHN_xxx

       RPC_C_AUTHZ_NONE,            // RPC_C_AUTHZ_xxx

       NULL,                        // Server principal name 

       RPC_C_AUTHN_LEVEL_CALL,      // RPC_C_AUTHN_LEVEL_xxx 

       RPC_C_IMP_LEVEL_IMPERSONATE, // RPC_C_IMP_LEVEL_xxx

       NULL,                        // client identity

       EOAC_NONE                    // proxy capabilities 

    );

Step 6: Use the IWbemServices pointer to make requests of WMI:

    IEnumWbemClassObject* pEnumerator = NULL;
    HRESULT hres = pSvc->ExecQuery(
        bstr_t("WQL"), 
        bstr_t("SELECT * FROM Win32_PerfRawData_PerfOS_Processor"),
        WBEM_FLAG_FORWARD_ONLY | WBEM_FLAG_RETURN_IMMEDIATELY, 
        NULL,
        &pEnumerator);

Step 7: Get data from the query in step 6.

    IWbemClassObject *pclsObj;
    while (1)
    {
        HRESULT hr = pEnumerator->Next(WBEM_INFINITE, 1, &pclsObj, &uReturn);

        if(0 == uReturn)
        {
            break;
        }

          VARIANT vtProp;
          VariantInit(&vtProp);

          hr = pclsObj->Get(L"PercentProcessorTime", 0, &vtProp, 0, 0);

          // Use it


           hr = pclsObj->Get(L"TimeStamp_Sys100NS", 0, &vtProp, 0, 0);

          // Use it

    }

Note

I have tried to keep the source code in the attached project simple. So I have taken the number of processors as the input though you may like to programmatically get the number of processors using GetSystemInfo Win32 API.

I have tested it on Microsoft Windows 2000 Professional OS running on a dual processor machine. It should work on Windows XP/ Windows 2003 Server as well.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here