VirtualBox

Changeset 10868 in vbox for trunk/src/VBox/Main/win


Ignore:
Timestamp:
Jul 24, 2008 6:34:35 PM (17 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
33686
Message:

PerfAPI: Windows collector re-worked to extract raw counters via WMI. Filtering for queries added. Security initialization is added to svcmain to access perf enumerators.

Location:
trunk/src/VBox/Main/win
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/win/PerformanceWin.cpp

    r10753 r10868  
    2222 */
    2323
    24 #include <pdh.h>
    25 #include <pdhmsg.h>
     24#include <Wbemidl.h>
    2625#include <iprt/err.h>
    2726
     27#include "Logging.h"
    2828#include "Performance.h"
    29 
    30 //#pragma comment(lib, "pdh.lib")
    3129
    3230namespace pm {
     
    4442    virtual int getProcessMemoryUsage(RTPROCESS process, unsigned long *used);
    4543
     44    virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
     45    virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
    4646private:
    47     int         convertPdhStatusToRTErr(PDH_STATUS pdhStatus);
    48     HCOUNTER    addCounter(HQUERY hQuery, LPCTSTR name);
    49     int         getCounterValue(HCOUNTER hCounter, DWORD flags, unsigned long *value);
    50 
    51     HQUERY      mHostCpuLoadQuery;
    52     HCOUNTER    mHostCpuLoadUserCounter;
    53     HCOUNTER    mHostCpuLoadKernelCounter;
    54     HCOUNTER    mHostCpuLoadIdleCounter;
     47    long        getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name);
     48    int         getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned);
     49
     50    IWbemRefresher     *mRefresher;
     51    IWbemServices      *mNameSpace;
     52
     53    IWbemHiPerfEnum    *mEnumProcessor;
     54    long               mEnumProcessorID;
     55    long               mHostCpuLoadNameHandle;
     56    long               mHostCpuLoadUserHandle;
     57    long               mHostCpuLoadKernelHandle;
     58    long               mHostCpuLoadIdleHandle;
     59
     60    IWbemHiPerfEnum    *mEnumProcess;
     61    long               mEnumProcessID;
     62    long               mProcessPIDHandle;
     63    long               mProcessCpuLoadUserHandle;
     64    long               mProcessCpuLoadKernelHandle;
     65    long               mProcessCpuLoadTimestampHandle;
     66    long               mProcessMemoryUsedHandle;
    5567};
    5668
     
    6173}
    6274
    63 CollectorWin::CollectorWin() : mHostCpuLoadQuery(0)
    64 {
    65     PDH_STATUS pdhStatus;
    66 
    67     pdhStatus = PdhOpenQuery(NULL, NULL, &mHostCpuLoadQuery);
    68     if (pdhStatus != ERROR_SUCCESS)
     75CollectorWin::CollectorWin() : mRefresher(0), mNameSpace(0), mEnumProcessor(0), mEnumProcess(0)
     76{
     77    HRESULT                 hr = S_OK;
     78    IWbemConfigureRefresher *pConfig = NULL;
     79    IWbemLocator            *pWbemLocator = NULL;
     80    BSTR                    bstrNameSpace = NULL;
     81
     82    if (SUCCEEDED (hr = CoCreateInstance(
     83        CLSID_WbemLocator,
     84        NULL,
     85        CLSCTX_INPROC_SERVER,
     86        IID_IWbemLocator,
     87        (void**) &pWbemLocator)))
     88    {
     89        // Connect to the desired namespace.
     90        bstrNameSpace = SysAllocString(L"\\\\.\\root\\cimv2");
     91        if (bstrNameSpace)
     92        {
     93            hr = pWbemLocator->ConnectServer(
     94                bstrNameSpace,
     95                NULL, // User name
     96                NULL, // Password
     97                NULL, // Locale
     98                0L,   // Security flags
     99                NULL, // Authority
     100                NULL, // Wbem context
     101                &mNameSpace);
     102        }
     103        pWbemLocator->Release();
     104        SysFreeString(bstrNameSpace);
     105    }
     106
     107    if (FAILED (hr)) {
     108        Log (("Failed to get namespace. HR = %x\n", hr));
    69109        return;
    70 
    71     mHostCpuLoadUserCounter   = addCounter (mHostCpuLoadQuery,
    72                                             L"\\Processor(_Total)\\% User Time");
    73     mHostCpuLoadKernelCounter = addCounter (mHostCpuLoadQuery,
    74                                             L"\\Processor(_Total)\\% Privileged Time");
    75     mHostCpuLoadIdleCounter   = addCounter (mHostCpuLoadQuery,
    76                                             L"\\Processor(_Total)\\% Idle Time");
     110    }
     111
     112    if (SUCCEEDED (hr = CoCreateInstance(
     113        CLSID_WbemRefresher,
     114        NULL,
     115        CLSCTX_INPROC_SERVER,
     116        IID_IWbemRefresher,
     117        (void**) &mRefresher)))
     118    {
     119        if (SUCCEEDED (hr = mRefresher->QueryInterface(
     120            IID_IWbemConfigureRefresher,
     121            (void **)&pConfig)))
     122        {
     123            // Add an enumerator to the refresher.
     124            if (SUCCEEDED (hr = pConfig->AddEnum(
     125                mNameSpace,
     126                L"Win32_PerfRawData_PerfOS_Processor",
     127                0,
     128                NULL,
     129                &mEnumProcessor,
     130                &mEnumProcessorID)))
     131            {
     132                hr = pConfig->AddEnum(
     133                    mNameSpace,
     134                    L"Win32_PerfRawData_PerfProc_Process",
     135                    0,
     136                    NULL,
     137                    &mEnumProcess,
     138                    &mEnumProcessID);
     139            }
     140            pConfig->Release();
     141        }
     142    }
     143
     144
     145    if (FAILED (hr)) {
     146        Log (("Failed to add enumerators. HR = %x\n", hr));
     147        return;
     148    }
     149
     150    // Retrieve property handles
     151
     152    if (FAILED (hr = mRefresher->Refresh(0L)))
     153    {
     154        Log (("Refresher failed. HR = %x\n", hr));
     155        return;
     156    }
     157
     158    IWbemObjectAccess       **apEnumAccess = NULL;
     159    DWORD                   dwNumReturned = 0;
     160
     161    if (RT_FAILURE(getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned)))
     162        return;
     163
     164    mHostCpuLoadNameHandle   = getPropertyHandle(apEnumAccess[0], L"Name");
     165    mHostCpuLoadUserHandle   = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
     166    mHostCpuLoadKernelHandle = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
     167    mHostCpuLoadIdleHandle   = getPropertyHandle(apEnumAccess[0], L"PercentProcessorTime");
     168
     169    delete [] apEnumAccess;
     170
     171    if (RT_FAILURE(getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned)))
     172        return;
     173
     174    mProcessPIDHandle              = getPropertyHandle(apEnumAccess[0], L"IDProcess");
     175    mProcessCpuLoadUserHandle      = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
     176    mProcessCpuLoadKernelHandle    = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
     177    mProcessCpuLoadTimestampHandle = getPropertyHandle(apEnumAccess[0], L"Timestamp_Sys100NS");
     178    mProcessMemoryUsedHandle       = getPropertyHandle(apEnumAccess[0], L"WorkingSet");
     179
     180    delete [] apEnumAccess;
    77181}
    78182
    79183CollectorWin::~CollectorWin()
    80184{
    81     if (mHostCpuLoadQuery)
    82         PdhCloseQuery (mHostCpuLoadQuery);
    83 }
    84 
    85 int CollectorWin::convertPdhStatusToRTErr(PDH_STATUS pdhStatus)
    86 {
    87     switch (pdhStatus)
    88     {
    89         case PDH_INVALID_ARGUMENT:
    90             return VERR_INVALID_PARAMETER;
    91         case PDH_INVALID_HANDLE:
    92             return VERR_INVALID_HANDLE;
    93     }
    94 
    95     return RTErrConvertFromWin32(pdhStatus);
    96 }
    97 
    98 HCOUNTER CollectorWin::addCounter(HQUERY hQuery, LPCTSTR name)
    99 {
    100     PDH_STATUS pdhStatus;
    101     HCOUNTER   hCounter;
    102 
    103     pdhStatus = PdhAddCounter (hQuery, name, 0, &hCounter);
    104     if (pdhStatus != ERROR_SUCCESS)
    105         return 0;
    106     return hCounter;
    107 }
    108 
    109 int CollectorWin::getCounterValue(HCOUNTER hCounter, DWORD flags, unsigned long *value)
    110 {
    111     PDH_STATUS           pdhStatus;
    112     PDH_FMT_COUNTERVALUE fmtValue;
    113 
    114     pdhStatus = PdhGetFormattedCounterValue (hCounter,
    115                                              PDH_FMT_LONG | flags,
    116                                              NULL,
    117                                              &fmtValue);
    118     if (pdhStatus != ERROR_SUCCESS)
    119         return convertPdhStatusToRTErr(pdhStatus);
    120    
    121     *value = fmtValue.longValue;
    122    
     185    if (NULL != mNameSpace)
     186    {
     187        mNameSpace->Release();
     188    }
     189    if (NULL != mEnumProcessor)
     190    {
     191        mEnumProcessor->Release();
     192    }
     193    if (NULL != mEnumProcess)
     194    {
     195        mEnumProcess->Release();
     196    }
     197    if (NULL != mRefresher)
     198    {
     199        mRefresher->Release();
     200    }
     201}
     202
     203long CollectorWin::getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name)
     204{
     205    HRESULT hr;
     206    CIMTYPE tmp;
     207    long    handle;
     208
     209    if (FAILED (hr = objAccess->GetPropertyHandle(
     210        name,
     211        &tmp,
     212        &handle)))
     213    {
     214        Log (("Failed to get property handle for '%ls'. HR = %x\n", name, hr));
     215        return 0;   /// @todo use throw
     216    }
     217
     218    return handle;
     219}
     220
     221int CollectorWin::getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned)
     222{
     223    HRESULT hr;
     224    DWORD   dwNumObjects = 0;
     225
     226    *objArray    = NULL;
     227    *numReturned = 0;
     228    hr = mEnum->GetObjects(0L, dwNumObjects, *objArray, numReturned);
     229
     230    // If the buffer was not big enough,
     231    // allocate a bigger buffer and retry.
     232    if (hr == WBEM_E_BUFFER_TOO_SMALL
     233        && *numReturned > dwNumObjects)
     234    {
     235        *objArray = new IWbemObjectAccess*[*numReturned];
     236        if (NULL == *objArray)
     237        {
     238            Log (("Could not allocate enumerator access objects\n"));
     239            return VERR_NO_MEMORY;
     240        }
     241
     242        SecureZeroMemory(*objArray,
     243            *numReturned*sizeof(IWbemObjectAccess*));
     244        dwNumObjects = *numReturned;
     245
     246        if (FAILED (hr = mEnum->GetObjects(0L,
     247            dwNumObjects, *objArray, numReturned)))
     248        {
     249            delete [] objArray;
     250            Log (("Failed to get objects from enumerator. HR = %x\n", hr));
     251            return VERR_INTERNAL_ERROR;
     252        }
     253    }
     254    else if (FAILED (hr))
     255    {
     256        Log (("Failed to get objects from enumerator. HR = %x\n", hr));
     257        return VERR_INTERNAL_ERROR;
     258    }
     259
    123260    return VINF_SUCCESS;
    124261}
     
    126263int CollectorWin::getHostCpuLoad(unsigned long *user, unsigned long *kernel, unsigned long *idle)
    127264{
    128     int         rc;
    129     PDH_STATUS  pdhStatus;
    130 
    131     pdhStatus = PdhCollectQueryData (mHostCpuLoadQuery);
    132     if (pdhStatus != ERROR_SUCCESS)
    133         return convertPdhStatusToRTErr(pdhStatus);
    134 
    135     rc = getCounterValue (mHostCpuLoadUserCounter, PDH_FMT_1000, user);
    136     AssertRCReturn(rc, rc);
    137 
    138     rc = getCounterValue (mHostCpuLoadKernelCounter, PDH_FMT_1000, kernel);
    139     AssertRCReturn(rc, rc);
    140 
    141     rc = getCounterValue (mHostCpuLoadIdleCounter, PDH_FMT_1000, idle);
    142     AssertRCReturn(rc, rc);
    143 
    144     return VINF_SUCCESS;
     265    return VERR_NOT_IMPLEMENTED;
     266}
     267
     268int CollectorWin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
     269{
     270    HRESULT hr;
     271    IWbemObjectAccess       **apEnumAccess = NULL;
     272    DWORD                   dwNumReturned = 0;
     273
     274    LogFlowThisFuncEnter();
     275
     276    if (FAILED (hr = mRefresher->Refresh(0L)))
     277    {
     278        Log (("Refresher failed. HR = %x\n", hr));
     279        return VERR_INTERNAL_ERROR;
     280    }
     281
     282    int rc = getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned);
     283    if (RT_FAILURE(rc))
     284        return rc;
     285
     286    for (unsigned i = 0; i < dwNumReturned; i++)
     287    {
     288        long  bytesRead = 0;
     289        WCHAR tmpBuf[200];
     290
     291        if (FAILED (hr = apEnumAccess[i]->ReadPropertyValue(
     292            mHostCpuLoadNameHandle,
     293            sizeof(tmpBuf),
     294            &bytesRead,
     295            (byte*)tmpBuf)))
     296        {
     297            Log (("Failed to read 'Name' property. HR = %x\n", hr));
     298            return VERR_INTERNAL_ERROR;
     299        }
     300        if (wcscmp(tmpBuf, L"_Total") == 0)
     301        {
     302            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     303                mHostCpuLoadUserHandle,
     304                user)))
     305            {
     306            Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
     307                return VERR_INTERNAL_ERROR;
     308            }
     309            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     310                mHostCpuLoadKernelHandle,
     311                kernel)))
     312            {
     313            Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
     314                return VERR_INTERNAL_ERROR;
     315            }
     316            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     317                mHostCpuLoadIdleHandle,
     318                idle)))
     319            {
     320            Log (("Failed to read 'PercentProcessorTime' property. HR = %x\n", hr));
     321                return VERR_INTERNAL_ERROR;
     322            }
     323            rc = VINF_SUCCESS;
     324        }
     325        apEnumAccess[i]->Release();
     326        apEnumAccess[i] = NULL;
     327    }
     328    delete [] apEnumAccess;
     329
     330    LogFlowThisFunc(("user=%lu kernel=%lu idle=%lu\n", *user, *kernel, *idle));
     331    LogFlowThisFuncLeave();
     332
     333    return rc;
    145334}
    146335
    147336int CollectorWin::getHostCpuMHz(unsigned long *mhz)
    148337{
    149     return E_NOTIMPL;
     338    return VERR_NOT_IMPLEMENTED;
    150339}
    151340
     
    169358int CollectorWin::getProcessCpuLoad(RTPROCESS process, unsigned long *user, unsigned long *kernel)
    170359{
    171     return E_NOTIMPL;
     360    return VERR_NOT_IMPLEMENTED;
     361}
     362
     363int CollectorWin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
     364{
     365    HRESULT hr;
     366    IWbemObjectAccess       **apEnumAccess = NULL;
     367    DWORD                   dwNumReturned = 0;
     368
     369    LogFlowThisFuncEnter();
     370
     371    if (FAILED (hr = mRefresher->Refresh(0L)))
     372    {
     373        Log (("Refresher failed. HR = %x\n", hr));
     374        return VERR_INTERNAL_ERROR;
     375    }
     376
     377    int rc = getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned);
     378    if (RT_FAILURE(rc))
     379        return rc;
     380
     381    rc = VERR_NOT_FOUND;
     382
     383    for (unsigned i = 0; i < dwNumReturned; i++)
     384    {
     385        DWORD dwIDProcess;
     386
     387        if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
     388            mProcessPIDHandle,
     389            &dwIDProcess)))
     390        {
     391            Log (("Failed to read 'IDProcess' property. HR = %x\n", hr));
     392            return VERR_INTERNAL_ERROR;
     393        }
     394        LogFlowThisFunc (("Matching machine process %x against %x...\n", process, dwIDProcess));
     395        if (dwIDProcess == process)
     396        {
     397            LogFlowThisFunc (("Match found.\n"));
     398            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     399                mProcessCpuLoadUserHandle,
     400                user)))
     401            {
     402            Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
     403                return VERR_INTERNAL_ERROR;
     404            }
     405            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     406                mProcessCpuLoadKernelHandle,
     407                kernel)))
     408            {
     409            Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
     410                return VERR_INTERNAL_ERROR;
     411            }
     412            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     413                mProcessCpuLoadTimestampHandle,
     414                total)))
     415            {
     416            Log (("Failed to read 'Timestamp_Sys100NS' property. HR = %x\n", hr));
     417                return VERR_INTERNAL_ERROR;
     418            }
     419            rc = VINF_SUCCESS;
     420        }
     421        apEnumAccess[i]->Release();
     422        apEnumAccess[i] = NULL;
     423    }
     424    delete [] apEnumAccess;
     425
     426    LogFlowThisFunc(("user=%lu kernel=%lu total=%lu\n", *user, *kernel, *total));
     427    LogFlowThisFuncLeave();
     428
     429    return rc;
    172430}
    173431
    174432int CollectorWin::getProcessMemoryUsage(RTPROCESS process, unsigned long *used)
    175433{
    176     return E_NOTIMPL;
    177 }
    178 
    179 }
     434    HRESULT hr;
     435    IWbemObjectAccess       **apEnumAccess = NULL;
     436    DWORD                   dwNumReturned = 0;
     437
     438    LogFlowThisFuncEnter();
     439
     440    if (FAILED (hr = mRefresher->Refresh(0L)))
     441    {
     442        Log (("Refresher failed. HR = %x\n", hr));
     443        return VERR_INTERNAL_ERROR;
     444    }
     445
     446    int rc = getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned);
     447    if (RT_FAILURE(rc))
     448        return rc;
     449
     450    rc = VERR_NOT_FOUND;
     451
     452    for (unsigned i = 0; i < dwNumReturned; i++)
     453    {
     454        DWORD dwIDProcess;
     455
     456        if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
     457            mProcessPIDHandle,
     458            &dwIDProcess)))
     459        {
     460            Log (("Failed to read 'IDProcess' property. HR = %x\n", hr));
     461            return VERR_INTERNAL_ERROR;
     462        }
     463        if (dwIDProcess == process)
     464        {
     465            uint64_t u64used = 0;
     466
     467            if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
     468                mProcessMemoryUsedHandle,
     469                &u64used)))
     470            {
     471            Log (("Failed to read 'WorkingSet' property. HR = %x\n", hr));
     472                return VERR_INTERNAL_ERROR;
     473            }
     474            *used = (unsigned long)(u64used / 1024);
     475            rc = VINF_SUCCESS;
     476        }
     477        apEnumAccess[i]->Release();
     478        apEnumAccess[i] = NULL;
     479    }
     480    delete [] apEnumAccess;
     481
     482    LogFlowThisFunc(("used=%lu\n", *used));
     483    LogFlowThisFuncLeave();
     484
     485    return rc;
     486}
     487
     488}
  • trunk/src/VBox/Main/win/svcmain.cpp

    r8155 r10868  
    173173#endif
    174174    _ASSERTE(SUCCEEDED(hRes));
     175    /*
     176     * Need to initialize security to access performance enumerators.
     177     */
     178    hRes = CoInitializeSecurity(
     179        NULL,
     180        -1,
     181        NULL,
     182        NULL,
     183        RPC_C_AUTHN_LEVEL_NONE,
     184        RPC_C_IMP_LEVEL_IMPERSONATE,
     185        NULL, EOAC_NONE, 0);
     186    _ASSERTE(SUCCEEDED(hRes));
    175187    _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
    176188    _Module.dwThreadID = GetCurrentThreadId();
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette