VirtualBox

source: vbox/trunk/src/VBox/Main/win/PerformanceWin.cpp@ 10868

Last change on this file since 10868 was 10868, checked in by vboxsync, 16 years ago

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.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 14.3 KB
Line 
1/* $Id: PerformanceWin.cpp 10868 2008-07-24 18:34:35Z vboxsync $ */
2
3/** @file
4 *
5 * VBox Windows-specific Performance Classes implementation.
6 */
7
8/*
9 * Copyright (C) 2008 Sun Microsystems, Inc.
10 *
11 * This file is part of VirtualBox Open Source Edition (OSE), as
12 * available from http://www.virtualbox.org. This file is free software;
13 * you can redistribute it and/or modify it under the terms of the GNU
14 * General Public License (GPL) as published by the Free Software
15 * Foundation, in version 2 as it comes in the "COPYING" file of the
16 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
17 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
18 *
19 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
20 * Clara, CA 95054 USA or visit http://www.sun.com if you need
21 * additional information or have any questions.
22 */
23
24#include <Wbemidl.h>
25#include <iprt/err.h>
26
27#include "Logging.h"
28#include "Performance.h"
29
30namespace pm {
31
32class CollectorWin : public CollectorHAL
33{
34public:
35 CollectorWin();
36 ~CollectorWin();
37
38 virtual int getHostCpuLoad(unsigned long *user, unsigned long *kernel, unsigned long *idle);
39 virtual int getHostCpuMHz(unsigned long *mhz);
40 virtual int getHostMemoryUsage(unsigned long *total, unsigned long *used, unsigned long *available);
41 virtual int getProcessCpuLoad(RTPROCESS process, unsigned long *user, unsigned long *kernel);
42 virtual int getProcessMemoryUsage(RTPROCESS process, unsigned long *used);
43
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);
46private:
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;
67};
68
69MetricFactoryWin::MetricFactoryWin()
70{
71 mHAL = new CollectorWin();
72 Assert(mHAL);
73}
74
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));
109 return;
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;
181}
182
183CollectorWin::~CollectorWin()
184{
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
260 return VINF_SUCCESS;
261}
262
263int CollectorWin::getHostCpuLoad(unsigned long *user, unsigned long *kernel, unsigned long *idle)
264{
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;
334}
335
336int CollectorWin::getHostCpuMHz(unsigned long *mhz)
337{
338 return VERR_NOT_IMPLEMENTED;
339}
340
341int CollectorWin::getHostMemoryUsage(unsigned long *total, unsigned long *used, unsigned long *available)
342{
343 MEMORYSTATUSEX mstat;
344
345 mstat.dwLength = sizeof(mstat);
346 if (GlobalMemoryStatusEx(&mstat))
347 {
348 *total = (unsigned long)( mstat.ullTotalPhys / 1000 );
349 *available = (unsigned long)( mstat.ullAvailPhys / 1000 );
350 *used = *total - *available;
351 }
352 else
353 return RTErrConvertFromWin32(GetLastError());
354
355 return VINF_SUCCESS;
356}
357
358int CollectorWin::getProcessCpuLoad(RTPROCESS process, unsigned long *user, unsigned long *kernel)
359{
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;
430}
431
432int CollectorWin::getProcessMemoryUsage(RTPROCESS process, unsigned long *used)
433{
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}
Note: See TracBrowser for help on using the repository browser.

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