VirtualBox

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


Ignore:
Timestamp:
Sep 16, 2008 7:11:15 PM (16 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
36654
Message:

PerfAPI: Windows collector re-done: WMI replaced with kernel and psapi calls.

File:
1 edited

Legend:

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

    r12460 r12513  
    2222 */
    2323
    24 #include <Wbemidl.h>
     24/* @todo Replace the following _WIN32_WINNT override with proper diagnostic:
     25#if (_WIN32_WINNT < 0x0501)
     26#error Win XP or later required!
     27#endif
     28*/
     29#ifdef _WIN32_WINNT
     30#if (_WIN32_WINNT < 0x0501)
     31#undef _WIN32_WINNT
     32#define _WIN32_WINNT 0x0501
     33#endif
     34#else
     35#define _WIN32_WINNT 0x0501
     36#endif
     37#include <windows.h>
     38
     39#include <psapi.h>
    2540extern "C" {
    2641#include <powrprof.h>
     
    5267    virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
    5368private:
    54     long        getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name);
    55     int         getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned);
    56 
    57     IWbemRefresher     *mRefresher;
    58     IWbemServices      *mNameSpace;
    59 
    60     IWbemHiPerfEnum    *mEnumProcessor;
    61     long               mEnumProcessorID;
    62     long               mHostCpuLoadNameHandle;
    63     long               mHostCpuLoadUserHandle;
    64     long               mHostCpuLoadKernelHandle;
    65     long               mHostCpuLoadIdleHandle;
    66 
    67     IWbemHiPerfEnum    *mEnumProcess;
    68     long               mEnumProcessID;
    69     long               mProcessPIDHandle;
    70     long               mProcessCpuLoadUserHandle;
    71     long               mProcessCpuLoadKernelHandle;
    72     long               mProcessCpuLoadTimestampHandle;
    73     long               mProcessMemoryUsedHandle;
    74 
    7569    struct VMProcessStats
    7670    {
     
    9185}
    9286
    93 CollectorWin::CollectorWin() : mRefresher(0), mNameSpace(0), mEnumProcessor(0), mEnumProcess(0)
    94 {
    95     HRESULT                 hr = S_OK;
    96     IWbemConfigureRefresher *pConfig = NULL;
    97     IWbemLocator            *pWbemLocator = NULL;
    98     BSTR                    bstrNameSpace = NULL;
    99 
    100     if (SUCCEEDED (hr = CoCreateInstance(
    101         CLSID_WbemLocator,
    102         NULL,
    103         CLSCTX_INPROC_SERVER,
    104         IID_IWbemLocator,
    105         (void**) &pWbemLocator)))
    106     {
    107         // Connect to the desired namespace.
    108         bstrNameSpace = SysAllocString(L"\\\\.\\root\\cimv2");
    109         if (bstrNameSpace)
    110         {
    111             hr = pWbemLocator->ConnectServer(
    112                 bstrNameSpace,
    113                 NULL, // User name
    114                 NULL, // Password
    115                 NULL, // Locale
    116                 0L,   // Security flags
    117                 NULL, // Authority
    118                 NULL, // Wbem context
    119                 &mNameSpace);
    120         }
    121         pWbemLocator->Release();
    122         SysFreeString(bstrNameSpace);
    123     }
    124 
    125     if (FAILED (hr)) {
    126         Log (("Failed to get namespace. HR = %x\n", hr));
    127         return;
    128     }
    129 
    130     if (SUCCEEDED (hr = CoCreateInstance(
    131         CLSID_WbemRefresher,
    132         NULL,
    133         CLSCTX_INPROC_SERVER,
    134         IID_IWbemRefresher,
    135         (void**) &mRefresher)))
    136     {
    137         if (SUCCEEDED (hr = mRefresher->QueryInterface(
    138             IID_IWbemConfigureRefresher,
    139             (void **)&pConfig)))
    140         {
    141             // Add an enumerator to the refresher.
    142             if (SUCCEEDED (hr = pConfig->AddEnum(
    143                 mNameSpace,
    144                 L"Win32_PerfRawData_PerfOS_Processor",
    145                 0,
    146                 NULL,
    147                 &mEnumProcessor,
    148                 &mEnumProcessorID)))
    149             {
    150                 hr = pConfig->AddEnum(
    151                     mNameSpace,
    152                     L"Win32_PerfRawData_PerfProc_Process",
    153                     0,
    154                     NULL,
    155                     &mEnumProcess,
    156                     &mEnumProcessID);
    157             }
    158             pConfig->Release();
    159         }
    160     }
    161 
    162 
    163     if (FAILED (hr)) {
    164         Log (("Failed to add enumerators. HR = %x\n", hr));
    165         return;
    166     }
    167 
    168     // Retrieve property handles (Returned handles work across all instances of a class!)
    169 
    170     if (FAILED (hr = mRefresher->Refresh(0L)))
    171     {
    172         Log (("Refresher failed. HR = %x\n", hr));
    173         return;
    174     }
    175 
    176     IWbemObjectAccess       **apEnumAccess = NULL;
    177     DWORD                   dwNumReturned = 0;
    178 
    179     if (RT_FAILURE(getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned)))
    180         return;
    181 
    182     mHostCpuLoadNameHandle   = getPropertyHandle(apEnumAccess[0], L"Name");
    183     mHostCpuLoadUserHandle   = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
    184     mHostCpuLoadKernelHandle = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
    185     mHostCpuLoadIdleHandle   = getPropertyHandle(apEnumAccess[0], L"PercentProcessorTime");
    186 
    187     for (unsigned i=0;i<dwNumReturned;i++)
    188         apEnumAccess[i]->Release();
    189 
    190     delete [] apEnumAccess;
    191 
    192     if (RT_FAILURE(getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned)))
    193         return;
    194 
    195     mProcessPIDHandle              = getPropertyHandle(apEnumAccess[0], L"IDProcess");
    196     mProcessCpuLoadUserHandle      = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
    197     mProcessCpuLoadKernelHandle    = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
    198     mProcessCpuLoadTimestampHandle = getPropertyHandle(apEnumAccess[0], L"Timestamp_Sys100NS");
    199     mProcessMemoryUsedHandle       = getPropertyHandle(apEnumAccess[0], L"WorkingSet");
    200 
    201     for (unsigned i=0;i<dwNumReturned;i++)
    202         apEnumAccess[i]->Release();
    203 
    204     delete [] apEnumAccess;
     87CollectorWin::CollectorWin()
     88{
    20589}
    20690
    20791CollectorWin::~CollectorWin()
    20892{
    209     IWbemConfigureRefresher *pConfig = NULL;
    210     HRESULT                 hr = S_OK;
    211 
    212     if (NULL != mNameSpace)
    213     {
    214         mNameSpace->Release();
    215     }
    216     if (NULL != mRefresher)
    217     {
    218         if (SUCCEEDED (hr = mRefresher->QueryInterface(
    219             IID_IWbemConfigureRefresher,
    220             (void **)&pConfig)))
    221         {
    222             // Remove the enumerators from the refresher.
    223             hr = pConfig->Remove(mEnumProcessorID, 0);
    224             Assert(SUCCEEDED(hr));
    225             hr = pConfig->Remove(mEnumProcessID, 0);
    226             Assert(SUCCEEDED(hr));
    227 
    228             pConfig->Release();
    229         }
    230     }
    231     if (NULL != mEnumProcessor)
    232     {
    233         mEnumProcessor->Release();
    234     }
    235     if (NULL != mEnumProcess)
    236     {
    237         mEnumProcess->Release();
    238     }
    239     if (NULL != mRefresher)
    240     {
    241         mRefresher->Release();
    242     }
    243 }
    244 
    245 long CollectorWin::getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name)
    246 {
    247     HRESULT hr;
    248     CIMTYPE tmp;
    249     long    handle;
    250 
    251     if (FAILED (hr = objAccess->GetPropertyHandle(
    252         name,
    253         &tmp,
    254         &handle)))
    255     {
    256         Log (("Failed to get property handle for '%ls'. HR = %x\n", name, hr));
    257         return 0;   /// @todo use throw
    258     }
    259 
    260     return handle;
    261 }
    262 
    263 int CollectorWin::getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned)
    264 {
    265     /*
    266      * Get the number of objects.
    267      * Note that the caller ASSUMES that at least one object is returned, so fail if there are none.
    268      */
    269     *objArray    = NULL;
    270     *numReturned = 0;
    271     HRESULT hr = mEnum->GetObjects(0L, 0, *objArray, numReturned);
    272     if (hr != WBEM_E_BUFFER_TOO_SMALL)
    273     {
    274         Log (("Failed to get the object count from the enumerator. HR = %x *numReturned=%d\n", hr, *numReturned));
    275         return VERR_INTERNAL_ERROR;
    276     }
    277 
    278     /*
    279      * Allocate an array with the right lenght and get the actual objects.
    280      */
    281     DWORD cObjects = *numReturned;
    282     *objArray = new IWbemObjectAccess*[cObjects];
    283     if (!*objArray)
    284     {
    285         Log (("Could not allocate enumerator access objects\n"));
    286         return VERR_NO_MEMORY;
    287     }
    288     SecureZeroMemory(*objArray, cObjects * sizeof(IWbemObjectAccess*));
    289     hr = mEnum->GetObjects(0L, cObjects, *objArray, numReturned);
    290     if (FAILED(hr) || *numReturned == 0)
    291     {
    292         delete [] *objArray;
    293         *objArray = NULL;
    294         Log (("Failed to get the objects from the enumerator. HR = %x *numReturned=%d cObjects=%d\n", hr, *numReturned, cObjects));
    295         return VERR_INTERNAL_ERROR;
    296     }
    297 
    298     return VINF_SUCCESS;
    299 }
     93
     94}
     95
     96
     97#define FILETTIME_TO_100NS(ft) (((uint64_t)ft.dwHighDateTime << 32) + ft.dwLowDateTime)
    30098
    30199int CollectorWin::preCollect(const CollectorHints& hints)
    302100{
    303 
    304     std::vector<RTPROCESS> processes;
    305     hints.getProcesses(processes);
    306 
    307     HRESULT hr;
    308     IWbemObjectAccess       **apEnumAccess = NULL;
    309     DWORD                   dwNumReturned = 0;
    310 
    311101    LogFlowThisFuncEnter();
    312102
    313     if (FAILED (hr = mRefresher->Refresh(0L)))
    314     {
    315         Log (("Refresher failed. HR = %x\n", hr));
    316         return VERR_INTERNAL_ERROR;
    317     }
    318 
    319     int rc = getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned);
     103    uint64_t user, kernel, idle, total;
     104    int rc = getRawHostCpuLoad(&user, &kernel, &idle);
    320105    if (RT_FAILURE(rc))
    321106        return rc;
    322 
    323     rc = VERR_NOT_FOUND;
    324 
    325     for (unsigned i = 0; i < dwNumReturned; i++)
    326     {
    327         DWORD dwIDProcess;
    328 
    329         if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
    330             mProcessPIDHandle,
    331             &dwIDProcess)))
     107    total = user + kernel + idle;
     108
     109    DWORD dwError;
     110    const CollectorHints::ProcessList& processes = hints.getProcessFlags();
     111    CollectorHints::ProcessList::const_iterator it;
     112
     113    mProcessStats.clear();
     114
     115    for (it = processes.begin(); it != processes.end() && RT_SUCCESS(rc); it++)
     116    {
     117        RTPROCESS process = it->first;
     118        HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
     119                               FALSE, process);
     120
     121        if (!h)
    332122        {
    333             Log (("Failed to read 'IDProcess' property. HR = %x\n", hr));
    334             rc = VERR_INTERNAL_ERROR;
     123            dwError = GetLastError();
     124            Log (("OpenProcess() -> 0x%x\n", dwError));
     125            rc = RTErrConvertFromWin32(dwError);
    335126            break;
    336127        }
    337         LogFlowThisFunc (("Matching process %x against the list of machines...\n", dwIDProcess));
    338         if (std::find(processes.begin(), processes.end(), dwIDProcess) != processes.end())
     128
     129        VMProcessStats vmStats;
     130        if ((it->second & COLLECT_CPU_LOAD) != 0)
    339131        {
    340             VMProcessStats vmStats;
    341 
    342             LogFlowThisFunc (("Match found.\n"));
    343             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    344                 mProcessCpuLoadUserHandle,
    345                 &vmStats.cpuUser)))
     132            FILETIME ftCreate, ftExit, ftKernel, ftUser;
     133            if (!GetProcessTimes(h, &ftCreate, &ftExit, &ftKernel, &ftUser))
    346134            {
    347                 Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
    348                 rc = VERR_INTERNAL_ERROR;
    349                 break;
     135                dwError = GetLastError();
     136                Log (("GetProcessTimes() -> 0x%x\n", dwError));
     137                rc = RTErrConvertFromWin32(dwError);
    350138            }
    351             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    352                 mProcessCpuLoadKernelHandle,
    353                 &vmStats.cpuKernel)))
     139            else
    354140            {
    355                 Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
    356                 rc = VERR_INTERNAL_ERROR;
    357                 break;
     141                vmStats.cpuKernel = FILETTIME_TO_100NS(ftKernel);
     142                vmStats.cpuUser   = FILETTIME_TO_100NS(ftUser);
     143                vmStats.cpuTotal  = total;
    358144            }
    359             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    360                 mProcessCpuLoadTimestampHandle,
    361                 &vmStats.cpuTotal)))
     145        }
     146        if (RT_SUCCESS(rc) && (it->second & COLLECT_RAM_USAGE) != 0)
     147        {
     148            PROCESS_MEMORY_COUNTERS pmc;
     149            if (!GetProcessMemoryInfo(h, &pmc, sizeof(pmc)))
    362150            {
    363                 Log (("Failed to read 'Timestamp_Sys100NS' property. HR = %x\n", hr));
    364                 rc = VERR_INTERNAL_ERROR;
    365                 break;
     151                dwError = GetLastError();
     152                Log (("GetProcessMemoryInfo() -> 0x%x\n", dwError));
     153                rc = RTErrConvertFromWin32(dwError);
    366154            }
    367             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    368                 mProcessMemoryUsedHandle,
    369                 &vmStats.ramUsed)))
    370             {
    371                 Log (("Failed to read 'WorkingSet' property. HR = %x\n", hr));
    372                 rc = VERR_INTERNAL_ERROR;
    373                 break;
    374             }
    375 
    376             mProcessStats[dwIDProcess] = vmStats;
    377             LogFlowThisFunc(("process=%x user=%lu kernel=%lu total=%lu\n", dwIDProcess, vmStats.cpuUser, vmStats.cpuKernel, vmStats.cpuTotal));
    378             rc = VINF_SUCCESS;
     155            else
     156                vmStats.ramUsed = pmc.WorkingSetSize;
    379157        }
    380     }
    381 
    382     for (unsigned i = 0; i < dwNumReturned; i++)
    383     {
    384         apEnumAccess[i]->Release();
    385         apEnumAccess[i] = NULL;
    386     }
    387     delete [] apEnumAccess;
     158        CloseHandle(h);
     159        mProcessStats[process] = vmStats;
     160    }
    388161
    389162    LogFlowThisFuncLeave();
     
    399172int CollectorWin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
    400173{
    401     HRESULT hr;
    402     IWbemObjectAccess       **apEnumAccess = NULL;
    403     DWORD                   dwNumReturned = 0;
    404 
    405174    LogFlowThisFuncEnter();
    406175
    407     int rc = getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned);
    408     if (RT_FAILURE(rc))
    409         return rc;
    410 
    411     for (unsigned i = 0; i < dwNumReturned; i++)
    412     {
    413         long  bytesRead = 0;
    414         WCHAR tmpBuf[200];
    415 
    416         if (FAILED (hr = apEnumAccess[i]->ReadPropertyValue(
    417             mHostCpuLoadNameHandle,
    418             sizeof(tmpBuf),
    419             &bytesRead,
    420             (byte*)tmpBuf)))
    421         {
    422             Log (("Failed to read 'Name' property. HR = %x\n", hr));
    423             rc = VERR_INTERNAL_ERROR;
    424             break;
    425         }
    426         if (wcscmp(tmpBuf, L"_Total") == 0)
    427         {
    428             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    429                 mHostCpuLoadUserHandle,
    430                 user)))
    431             {
    432                 Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
    433                 rc = VERR_INTERNAL_ERROR;
    434                 break;
    435             }
    436             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    437                 mHostCpuLoadKernelHandle,
    438                 kernel)))
    439             {
    440                 Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
    441                 rc = VERR_INTERNAL_ERROR;
    442                 break;
    443             }
    444             if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
    445                 mHostCpuLoadIdleHandle,
    446                 idle)))
    447             {
    448                 Log (("Failed to read 'PercentProcessorTime' property. HR = %x\n", hr));
    449                 rc = VERR_INTERNAL_ERROR;
    450                 break;
    451             }
    452             rc = VINF_SUCCESS;
    453         }
    454     }
    455     for (unsigned i = 0; i < dwNumReturned; i++)
    456     {
    457         apEnumAccess[i]->Release();
    458         apEnumAccess[i] = NULL;
    459     }
    460     delete [] apEnumAccess;
     176    FILETIME ftIdle, ftKernel, ftUser;
     177
     178    if (!GetSystemTimes(&ftIdle, &ftKernel, &ftUser))
     179    {
     180        DWORD dwError = GetLastError();
     181        Log (("GetSystemTimes() -> 0x%x\n", dwError));
     182        return RTErrConvertFromWin32(dwError);
     183    }
     184
     185    *user   = FILETTIME_TO_100NS(ftUser);
     186    *idle   = FILETTIME_TO_100NS(ftIdle);
     187    *kernel = FILETTIME_TO_100NS(ftKernel) - *idle;
    461188
    462189    LogFlowThisFunc(("user=%lu kernel=%lu idle=%lu\n", *user, *kernel, *idle));
    463190    LogFlowThisFuncLeave();
    464191
    465     return rc;
     192    return VINF_SUCCESS;
    466193}
    467194
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