Changeset 12513 in vbox for trunk/src/VBox/Main/win
- Timestamp:
- Sep 16, 2008 7:11:15 PM (16 years ago)
- svn:sync-xref-src-repo-rev:
- 36654
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/win/PerformanceWin.cpp
r12460 r12513 22 22 */ 23 23 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> 25 40 extern "C" { 26 41 #include <powrprof.h> … … 52 67 virtual int getRawProcessCpuLoad(RTPROCESS process, uint64_t *user, uint64_t *kernel, uint64_t *total); 53 68 private: 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 75 69 struct VMProcessStats 76 70 { … … 91 85 } 92 86 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; 87 CollectorWin::CollectorWin() 88 { 205 89 } 206 90 207 91 CollectorWin::~CollectorWin() 208 92 { 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) 300 98 301 99 int CollectorWin::preCollect(const CollectorHints& hints) 302 100 { 303 304 std::vector<RTPROCESS> processes;305 hints.getProcesses(processes);306 307 HRESULT hr;308 IWbemObjectAccess **apEnumAccess = NULL;309 DWORD dwNumReturned = 0;310 311 101 LogFlowThisFuncEnter(); 312 102 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); 320 105 if (RT_FAILURE(rc)) 321 106 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) 332 122 { 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); 335 126 break; 336 127 } 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) 339 131 { 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)) 346 134 { 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); 350 138 } 351 if (FAILED (hr = apEnumAccess[i]->ReadQWORD( 352 mProcessCpuLoadKernelHandle, 353 &vmStats.cpuKernel))) 139 else 354 140 { 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; 358 144 } 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))) 362 150 { 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); 366 154 } 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; 379 157 } 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 } 388 161 389 162 LogFlowThisFuncLeave(); … … 399 172 int CollectorWin::getRawHostCpuLoad(uint64_t *user, uint64_t *kernel, uint64_t *idle) 400 173 { 401 HRESULT hr;402 IWbemObjectAccess **apEnumAccess = NULL;403 DWORD dwNumReturned = 0;404 405 174 LogFlowThisFuncEnter(); 406 175 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; 461 188 462 189 LogFlowThisFunc(("user=%lu kernel=%lu idle=%lu\n", *user, *kernel, *idle)); 463 190 LogFlowThisFuncLeave(); 464 191 465 return rc;192 return VINF_SUCCESS; 466 193 } 467 194
Note:
See TracChangeset
for help on using the changeset viewer.