VirtualBox

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

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

Perf API: CPU/MHz counter re-introduced (Win implementation).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 15.0 KB
Line 
1/* $Id: PerformanceWin.cpp 11467 2008-08-18 14:52:12Z 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>
25extern "C" {
26#include <powrprof.h>
27}
28#include <iprt/err.h>
29#include <iprt/mp.h>
30
31#include "Logging.h"
32#include "Performance.h"
33
34namespace pm {
35
36class CollectorWin : public CollectorHAL
37{
38public:
39 CollectorWin();
40 ~CollectorWin();
41
42 virtual int getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle);
43 virtual int getHostCpuMHz(ULONG *mhz);
44 virtual int getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available);
45 virtual int getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel);
46 virtual int getProcessMemoryUsage(RTPROCESS process, ULONG *used);
47
48 virtual int getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle);
49 virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total);
50private:
51 long getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name);
52 int getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned);
53
54 IWbemRefresher *mRefresher;
55 IWbemServices *mNameSpace;
56
57 IWbemHiPerfEnum *mEnumProcessor;
58 long mEnumProcessorID;
59 long mHostCpuLoadNameHandle;
60 long mHostCpuLoadUserHandle;
61 long mHostCpuLoadKernelHandle;
62 long mHostCpuLoadIdleHandle;
63
64 IWbemHiPerfEnum *mEnumProcess;
65 long mEnumProcessID;
66 long mProcessPIDHandle;
67 long mProcessCpuLoadUserHandle;
68 long mProcessCpuLoadKernelHandle;
69 long mProcessCpuLoadTimestampHandle;
70 long mProcessMemoryUsedHandle;
71};
72
73MetricFactoryWin::MetricFactoryWin()
74{
75 mHAL = new CollectorWin();
76 Assert(mHAL);
77}
78
79CollectorWin::CollectorWin() : mRefresher(0), mNameSpace(0), mEnumProcessor(0), mEnumProcess(0)
80{
81 HRESULT hr = S_OK;
82 IWbemConfigureRefresher *pConfig = NULL;
83 IWbemLocator *pWbemLocator = NULL;
84 BSTR bstrNameSpace = NULL;
85
86 if (SUCCEEDED (hr = CoCreateInstance(
87 CLSID_WbemLocator,
88 NULL,
89 CLSCTX_INPROC_SERVER,
90 IID_IWbemLocator,
91 (void**) &pWbemLocator)))
92 {
93 // Connect to the desired namespace.
94 bstrNameSpace = SysAllocString(L"\\\\.\\root\\cimv2");
95 if (bstrNameSpace)
96 {
97 hr = pWbemLocator->ConnectServer(
98 bstrNameSpace,
99 NULL, // User name
100 NULL, // Password
101 NULL, // Locale
102 0L, // Security flags
103 NULL, // Authority
104 NULL, // Wbem context
105 &mNameSpace);
106 }
107 pWbemLocator->Release();
108 SysFreeString(bstrNameSpace);
109 }
110
111 if (FAILED (hr)) {
112 Log (("Failed to get namespace. HR = %x\n", hr));
113 return;
114 }
115
116 if (SUCCEEDED (hr = CoCreateInstance(
117 CLSID_WbemRefresher,
118 NULL,
119 CLSCTX_INPROC_SERVER,
120 IID_IWbemRefresher,
121 (void**) &mRefresher)))
122 {
123 if (SUCCEEDED (hr = mRefresher->QueryInterface(
124 IID_IWbemConfigureRefresher,
125 (void **)&pConfig)))
126 {
127 // Add an enumerator to the refresher.
128 if (SUCCEEDED (hr = pConfig->AddEnum(
129 mNameSpace,
130 L"Win32_PerfRawData_PerfOS_Processor",
131 0,
132 NULL,
133 &mEnumProcessor,
134 &mEnumProcessorID)))
135 {
136 hr = pConfig->AddEnum(
137 mNameSpace,
138 L"Win32_PerfRawData_PerfProc_Process",
139 0,
140 NULL,
141 &mEnumProcess,
142 &mEnumProcessID);
143 }
144 pConfig->Release();
145 }
146 }
147
148
149 if (FAILED (hr)) {
150 Log (("Failed to add enumerators. HR = %x\n", hr));
151 return;
152 }
153
154 // Retrieve property handles
155
156 if (FAILED (hr = mRefresher->Refresh(0L)))
157 {
158 Log (("Refresher failed. HR = %x\n", hr));
159 return;
160 }
161
162 IWbemObjectAccess **apEnumAccess = NULL;
163 DWORD dwNumReturned = 0;
164
165 if (RT_FAILURE(getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned)))
166 return;
167
168 mHostCpuLoadNameHandle = getPropertyHandle(apEnumAccess[0], L"Name");
169 mHostCpuLoadUserHandle = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
170 mHostCpuLoadKernelHandle = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
171 mHostCpuLoadIdleHandle = getPropertyHandle(apEnumAccess[0], L"PercentProcessorTime");
172
173 delete [] apEnumAccess;
174
175 if (RT_FAILURE(getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned)))
176 return;
177
178 mProcessPIDHandle = getPropertyHandle(apEnumAccess[0], L"IDProcess");
179 mProcessCpuLoadUserHandle = getPropertyHandle(apEnumAccess[0], L"PercentUserTime");
180 mProcessCpuLoadKernelHandle = getPropertyHandle(apEnumAccess[0], L"PercentPrivilegedTime");
181 mProcessCpuLoadTimestampHandle = getPropertyHandle(apEnumAccess[0], L"Timestamp_Sys100NS");
182 mProcessMemoryUsedHandle = getPropertyHandle(apEnumAccess[0], L"WorkingSet");
183
184 delete [] apEnumAccess;
185}
186
187CollectorWin::~CollectorWin()
188{
189 if (NULL != mNameSpace)
190 {
191 mNameSpace->Release();
192 }
193 if (NULL != mEnumProcessor)
194 {
195 mEnumProcessor->Release();
196 }
197 if (NULL != mEnumProcess)
198 {
199 mEnumProcess->Release();
200 }
201 if (NULL != mRefresher)
202 {
203 mRefresher->Release();
204 }
205}
206
207long CollectorWin::getPropertyHandle(IWbemObjectAccess *objAccess, LPCWSTR name)
208{
209 HRESULT hr;
210 CIMTYPE tmp;
211 long handle;
212
213 if (FAILED (hr = objAccess->GetPropertyHandle(
214 name,
215 &tmp,
216 &handle)))
217 {
218 Log (("Failed to get property handle for '%ls'. HR = %x\n", name, hr));
219 return 0; /// @todo use throw
220 }
221
222 return handle;
223}
224
225int CollectorWin::getObjects(IWbemHiPerfEnum *mEnum, IWbemObjectAccess ***objArray, DWORD *numReturned)
226{
227 HRESULT hr;
228 DWORD dwNumObjects = 0;
229
230 *objArray = NULL;
231 *numReturned = 0;
232 hr = mEnum->GetObjects(0L, dwNumObjects, *objArray, numReturned);
233
234 // If the buffer was not big enough,
235 // allocate a bigger buffer and retry.
236 if (hr == WBEM_E_BUFFER_TOO_SMALL
237 && *numReturned > dwNumObjects)
238 {
239 *objArray = new IWbemObjectAccess*[*numReturned];
240 if (NULL == *objArray)
241 {
242 Log (("Could not allocate enumerator access objects\n"));
243 return VERR_NO_MEMORY;
244 }
245
246 SecureZeroMemory(*objArray,
247 *numReturned*sizeof(IWbemObjectAccess*));
248 dwNumObjects = *numReturned;
249
250 if (FAILED (hr = mEnum->GetObjects(0L,
251 dwNumObjects, *objArray, numReturned)))
252 {
253 delete [] objArray;
254 Log (("Failed to get objects from enumerator. HR = %x\n", hr));
255 return VERR_INTERNAL_ERROR;
256 }
257 }
258 else if (FAILED (hr))
259 {
260 Log (("Failed to get objects from enumerator. HR = %x\n", hr));
261 return VERR_INTERNAL_ERROR;
262 }
263
264 return VINF_SUCCESS;
265}
266
267int CollectorWin::getHostCpuLoad(ULONG *user, ULONG *kernel, ULONG *idle)
268{
269 return VERR_NOT_IMPLEMENTED;
270}
271
272int CollectorWin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle)
273{
274 HRESULT hr;
275 IWbemObjectAccess **apEnumAccess = NULL;
276 DWORD dwNumReturned = 0;
277
278 LogFlowThisFuncEnter();
279
280 if (FAILED (hr = mRefresher->Refresh(0L)))
281 {
282 Log (("Refresher failed. HR = %x\n", hr));
283 return VERR_INTERNAL_ERROR;
284 }
285
286 int rc = getObjects(mEnumProcessor, &apEnumAccess, &dwNumReturned);
287 if (RT_FAILURE(rc))
288 return rc;
289
290 for (unsigned i = 0; i < dwNumReturned; i++)
291 {
292 long bytesRead = 0;
293 WCHAR tmpBuf[200];
294
295 if (FAILED (hr = apEnumAccess[i]->ReadPropertyValue(
296 mHostCpuLoadNameHandle,
297 sizeof(tmpBuf),
298 &bytesRead,
299 (byte*)tmpBuf)))
300 {
301 Log (("Failed to read 'Name' property. HR = %x\n", hr));
302 return VERR_INTERNAL_ERROR;
303 }
304 if (wcscmp(tmpBuf, L"_Total") == 0)
305 {
306 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
307 mHostCpuLoadUserHandle,
308 user)))
309 {
310 Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
311 return VERR_INTERNAL_ERROR;
312 }
313 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
314 mHostCpuLoadKernelHandle,
315 kernel)))
316 {
317 Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
318 return VERR_INTERNAL_ERROR;
319 }
320 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
321 mHostCpuLoadIdleHandle,
322 idle)))
323 {
324 Log (("Failed to read 'PercentProcessorTime' property. HR = %x\n", hr));
325 return VERR_INTERNAL_ERROR;
326 }
327 rc = VINF_SUCCESS;
328 }
329 apEnumAccess[i]->Release();
330 apEnumAccess[i] = NULL;
331 }
332 delete [] apEnumAccess;
333
334 LogFlowThisFunc(("user=%lu kernel=%lu idle=%lu\n", *user, *kernel, *idle));
335 LogFlowThisFuncLeave();
336
337 return rc;
338}
339
340typedef struct _PROCESSOR_POWER_INFORMATION {
341 ULONG Number;
342 ULONG MaxMhz;
343 ULONG CurrentMhz;
344 ULONG MhzLimit;
345 ULONG MaxIdleState;
346 ULONG CurrentIdleState;
347} PROCESSOR_POWER_INFORMATION , *PPROCESSOR_POWER_INFORMATION;
348
349int CollectorWin::getHostCpuMHz(ULONG *mhz)
350{
351 uint64_t uTotalMhz = 0;
352 RTCPUID nProcessors = RTMpGetCount();
353 PPROCESSOR_POWER_INFORMATION ppi = new PROCESSOR_POWER_INFORMATION[nProcessors];
354 LONG ns = CallNtPowerInformation(ProcessorInformation, NULL, 0, ppi,
355 nProcessors * sizeof(PROCESSOR_POWER_INFORMATION));
356 if (ns)
357 {
358 Log(("CallNtPowerInformation() -> %x\n", ns));
359 return VERR_INTERNAL_ERROR;
360 }
361
362 /* Compute an average over all CPUs */
363 for (unsigned i = 0; i < nProcessors; i++)
364 uTotalMhz += ppi[i].CurrentMhz;
365 *mhz = (ULONG)(uTotalMhz / nProcessors);
366
367 LogFlowThisFunc(("mhz=%u\n", *mhz));
368 LogFlowThisFuncLeave();
369
370 return VINF_SUCCESS;
371}
372
373int CollectorWin::getHostMemoryUsage(ULONG *total, ULONG *used, ULONG *available)
374{
375 MEMORYSTATUSEX mstat;
376
377 mstat.dwLength = sizeof(mstat);
378 if (GlobalMemoryStatusEx(&mstat))
379 {
380 *total = (ULONG)( mstat.ullTotalPhys / 1000 );
381 *available = (ULONG)( mstat.ullAvailPhys / 1000 );
382 *used = *total - *available;
383 }
384 else
385 return RTErrConvertFromWin32(GetLastError());
386
387 return VINF_SUCCESS;
388}
389
390int CollectorWin::getProcessCpuLoad(RTPROCESS process, ULONG *user, ULONG *kernel)
391{
392 return VERR_NOT_IMPLEMENTED;
393}
394
395int CollectorWin::getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total)
396{
397 HRESULT hr;
398 IWbemObjectAccess **apEnumAccess = NULL;
399 DWORD dwNumReturned = 0;
400
401 LogFlowThisFuncEnter();
402
403 if (FAILED (hr = mRefresher->Refresh(0L)))
404 {
405 Log (("Refresher failed. HR = %x\n", hr));
406 return VERR_INTERNAL_ERROR;
407 }
408
409 int rc = getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned);
410 if (RT_FAILURE(rc))
411 return rc;
412
413 rc = VERR_NOT_FOUND;
414
415 for (unsigned i = 0; i < dwNumReturned; i++)
416 {
417 DWORD dwIDProcess;
418
419 if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
420 mProcessPIDHandle,
421 &dwIDProcess)))
422 {
423 Log (("Failed to read 'IDProcess' property. HR = %x\n", hr));
424 return VERR_INTERNAL_ERROR;
425 }
426 LogFlowThisFunc (("Matching machine process %x against %x...\n", process, dwIDProcess));
427 if (dwIDProcess == process)
428 {
429 LogFlowThisFunc (("Match found.\n"));
430 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
431 mProcessCpuLoadUserHandle,
432 user)))
433 {
434 Log (("Failed to read 'PercentUserTime' property. HR = %x\n", hr));
435 return VERR_INTERNAL_ERROR;
436 }
437 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
438 mProcessCpuLoadKernelHandle,
439 kernel)))
440 {
441 Log (("Failed to read 'PercentPrivilegedTime' property. HR = %x\n", hr));
442 return VERR_INTERNAL_ERROR;
443 }
444 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
445 mProcessCpuLoadTimestampHandle,
446 total)))
447 {
448 Log (("Failed to read 'Timestamp_Sys100NS' property. HR = %x\n", hr));
449 return VERR_INTERNAL_ERROR;
450 }
451 rc = VINF_SUCCESS;
452 }
453 apEnumAccess[i]->Release();
454 apEnumAccess[i] = NULL;
455 }
456 delete [] apEnumAccess;
457
458 LogFlowThisFunc(("user=%lu kernel=%lu total=%lu\n", *user, *kernel, *total));
459 LogFlowThisFuncLeave();
460
461 return rc;
462}
463
464int CollectorWin::getProcessMemoryUsage(RTPROCESS process, ULONG *used)
465{
466 HRESULT hr;
467 IWbemObjectAccess **apEnumAccess = NULL;
468 DWORD dwNumReturned = 0;
469
470 LogFlowThisFuncEnter();
471
472 if (FAILED (hr = mRefresher->Refresh(0L)))
473 {
474 Log (("Refresher failed. HR = %x\n", hr));
475 return VERR_INTERNAL_ERROR;
476 }
477
478 int rc = getObjects(mEnumProcess, &apEnumAccess, &dwNumReturned);
479 if (RT_FAILURE(rc))
480 return rc;
481
482 rc = VERR_NOT_FOUND;
483
484 for (unsigned i = 0; i < dwNumReturned; i++)
485 {
486 DWORD dwIDProcess;
487
488 if (FAILED (hr = apEnumAccess[i]->ReadDWORD(
489 mProcessPIDHandle,
490 &dwIDProcess)))
491 {
492 Log (("Failed to read 'IDProcess' property. HR = %x\n", hr));
493 return VERR_INTERNAL_ERROR;
494 }
495 if (dwIDProcess == process)
496 {
497 uint64_t u64used = 0;
498
499 if (FAILED (hr = apEnumAccess[i]->ReadQWORD(
500 mProcessMemoryUsedHandle,
501 &u64used)))
502 {
503 Log (("Failed to read 'WorkingSet' property. HR = %x\n", hr));
504 return VERR_INTERNAL_ERROR;
505 }
506 *used = (ULONG)(u64used / 1024);
507 rc = VINF_SUCCESS;
508 }
509 apEnumAccess[i]->Release();
510 apEnumAccess[i] = NULL;
511 }
512 delete [] apEnumAccess;
513
514 LogFlowThisFunc(("used=%lu\n", *used));
515 LogFlowThisFuncLeave();
516
517 return rc;
518}
519
520}
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