Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

599 lines
19 KiB

  1. /*++
  2. Copyright (C) 1997-2001 Microsoft Corporation
  3. Module Name:
  4. Abstract:
  5. History:
  6. --*/
  7. //***************************************************************************
  8. //
  9. // PERFHELP.CPP
  10. //
  11. // Registry-based performance counter reading helper
  12. //
  13. //***************************************************************************
  14. #include "precomp.h"
  15. #include <stdio.h>
  16. #include <wbemidl.h>
  17. #include <wbemint.h>
  18. #include "flexarry.h"
  19. #include "ntperf.h"
  20. #include "perfhelp.h"
  21. #include "refreshr.h"
  22. //***************************************************************************
  23. //
  24. // PerfHelper::GetInstances
  25. //
  26. // This is called to retrieve all instances of a given class.
  27. //
  28. // Parameters:
  29. // <pBuf> The perf blob retrieved from HKEY_PERFORMANCE_DATA.
  30. // <pClassMap> A map object of the class required.
  31. // <pSink> The sink to which to deliver the objects.
  32. //
  33. //***************************************************************************
  34. void PerfHelper::GetInstances(
  35. LPBYTE pBuf,
  36. CClassMapInfo *pClassMap,
  37. IWbemObjectSink *pSink
  38. )
  39. {
  40. PPERF_OBJECT_TYPE PerfObj = 0;
  41. PPERF_INSTANCE_DEFINITION PerfInst = 0;
  42. PPERF_COUNTER_DEFINITION PerfCntr = 0, CurCntr = 0;
  43. PPERF_COUNTER_BLOCK PtrToCntr = 0;
  44. PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) pBuf;
  45. DWORD i, j, k;
  46. // Get the first object type.
  47. // ==========================
  48. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
  49. PerfData->HeaderLength);
  50. // Process all objects.
  51. // ====================
  52. for (i = 0; i < PerfData->NumObjectTypes; i++ )
  53. {
  54. // Within each PERF_OBJECT_TYPE is a series of
  55. // PERF_COUNTER_DEFINITION blocks.
  56. // ==========================================
  57. PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
  58. PerfObj->HeaderLength);
  59. // If the current object isn't of the class we requested,
  60. // simply skip over it. I am not sure if this can really
  61. // happen or not in practice.
  62. // ======================================================
  63. if (PerfObj->ObjectNameTitleIndex != pClassMap->m_dwObjectId)
  64. {
  65. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
  66. PerfObj->TotalByteLength);
  67. continue;
  68. }
  69. if (PerfObj->NumInstances > 0)
  70. {
  71. // Get the first instance.
  72. // =======================
  73. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
  74. PerfObj->DefinitionLength);
  75. // Retrieve all instances.
  76. // =======================
  77. for (k = 0; k < DWORD(PerfObj->NumInstances); k++ )
  78. {
  79. CurCntr = PerfCntr;
  80. // Get the first counter.
  81. // ======================
  82. PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
  83. PerfInst->ByteLength);
  84. // Quickly clone a new instance to send back to the user.
  85. // Since SpawnInstance() returns an IWbemClassObject and
  86. // we really need an IWbemObjectAccess,we have to QI
  87. // after the spawn. We need to fix this, as this number
  88. // of calls is too time consuming.
  89. // ======================================================
  90. IWbemObjectAccess *pNewInst = 0;
  91. IWbemClassObject *pClsObj = 0;
  92. pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj);
  93. pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst);
  94. pClsObj->Release(); // We only need the IWbemObjectAccess pointer
  95. // Locate the instance name.
  96. // ==========================
  97. LPWSTR pName = (LPWSTR) ((PBYTE)PerfInst + PerfInst->NameOffset);
  98. // Retrieve all counters.
  99. // ======================
  100. for(j = 0; j < PerfObj->NumCounters; j++ )
  101. {
  102. // Find the WBEM property handle based on the counter title index.
  103. // This function does a quick binary search of the class map object
  104. // to find the handle that goes with this counter.
  105. // ================================================================
  106. LONG hPropHandle = pClassMap->GetPropHandle(CurCntr->CounterNameTitleIndex);
  107. if (hPropHandle == 0)
  108. continue;
  109. // Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
  110. // Only supporting simple DWORD types for now. BobW knows more about
  111. // all this stuff and can extend it properly.
  112. // ==================================================================
  113. if ((CurCntr->CounterType & 0x700) == 0)
  114. {
  115. LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset));
  116. HRESULT hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal);
  117. }
  118. // Get next counter.
  119. // =================
  120. CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +
  121. CurCntr->ByteLength);
  122. }
  123. // Write the instance 'name'
  124. // =========================
  125. if (pName && pClassMap->m_dwNameHandle)
  126. {
  127. pNewInst->WritePropertyValue(
  128. pClassMap->m_dwNameHandle,
  129. (wcslen(pName) + 1) * 2,
  130. LPBYTE(pName)
  131. );
  132. }
  133. // Deliver the instance to the user.
  134. // =================================
  135. pSink->Indicate(1, (IWbemClassObject **) &pNewInst);
  136. pNewInst->Release();
  137. // Move to the next perf instance.
  138. // ================================
  139. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +
  140. PtrToCntr->ByteLength);
  141. }
  142. }
  143. // Cases where the counters have no instances.
  144. // ===========================================
  145. else
  146. {
  147. // Get the first counter.
  148. // ======================
  149. PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
  150. PerfObj->DefinitionLength );
  151. // Quickly clone a new instance to send back to the user.
  152. // Since SpawnInstance() returns an IWbemClassObject and
  153. // we really need an IWbemObjectAccess,we have to QI
  154. // after the spawn. We need to fix this, as this number
  155. // of calls is too time consuming.
  156. // ======================================================
  157. IWbemObjectAccess *pNewInst = 0;
  158. IWbemClassObject *pClsObj = 0;
  159. pClassMap->m_pClassDef->SpawnInstance(0, &pClsObj);
  160. pClsObj->QueryInterface(IID_IWbemObjectAccess, (LPVOID *) &pNewInst);
  161. pClsObj->Release();
  162. // Retrieve all counters.
  163. // ======================
  164. for( j=0; j < PerfObj->NumCounters; j++ )
  165. {
  166. // Find the WBEM property handle based on the counter title index.
  167. // This function does a quick binary search of the class map object
  168. // to find the handle that goes with this counter.
  169. // ================================================================
  170. LONG hPropHandle = pClassMap->GetPropHandle(PerfCntr->CounterNameTitleIndex);
  171. if (hPropHandle == 0)
  172. continue;
  173. // Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
  174. // We will ignore non-DWORD types for now.
  175. // =======================================
  176. if ((PerfCntr->CounterType & 0x700) == 0)
  177. {
  178. LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset));
  179. HRESULT hRes = pNewInst->WriteDWORD(hPropHandle, *pdwVal);
  180. }
  181. PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
  182. PerfCntr->ByteLength);
  183. }
  184. // Since IWbemObjectAccess derives from IWbemClassObject, the following
  185. // cast is legal. Note that indicate wants IWbemClassObject objects.
  186. // ====================================================================
  187. pSink->Indicate(1, (IWbemClassObject **) &pNewInst);
  188. pNewInst->Release();
  189. }
  190. // Get the next object type.
  191. // =========================
  192. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
  193. PerfObj->TotalByteLength);
  194. }
  195. }
  196. //***************************************************************************
  197. //
  198. // PerfHelper::RefreshInstances
  199. //
  200. //***************************************************************************
  201. void PerfHelper::RefreshInstances(
  202. LPBYTE pBuf,
  203. CNt5Refresher *pRef
  204. )
  205. {
  206. PPERF_OBJECT_TYPE PerfObj = 0;
  207. PPERF_INSTANCE_DEFINITION PerfInst = 0;
  208. PPERF_COUNTER_DEFINITION PerfCntr = 0, CurCntr = 0;
  209. PPERF_COUNTER_BLOCK PtrToCntr = 0;
  210. PPERF_DATA_BLOCK PerfData = (PPERF_DATA_BLOCK) pBuf;
  211. DWORD i, j, k;
  212. // Get the first object type.
  213. // ==========================
  214. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfData +
  215. PerfData->HeaderLength);
  216. // Process all objects.
  217. // ====================
  218. for (i = 0; i < PerfData->NumObjectTypes; i++ )
  219. {
  220. // Within each PERF_OBJECT_TYPE is a series of
  221. // PERF_COUNTER_DEFINITION blocks.
  222. // ==========================================
  223. PerfCntr = (PPERF_COUNTER_DEFINITION) ((PBYTE)PerfObj +
  224. PerfObj->HeaderLength);
  225. if (PerfObj->NumInstances > 0)
  226. {
  227. // Get the first instance.
  228. // =======================
  229. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PerfObj +
  230. PerfObj->DefinitionLength);
  231. // Retrieve all instances.
  232. // =======================
  233. for (k = 0; k < DWORD(PerfObj->NumInstances); k++ )
  234. {
  235. CurCntr = PerfCntr;
  236. // Get the first counter.
  237. // ======================
  238. PtrToCntr = (PPERF_COUNTER_BLOCK)((PBYTE)PerfInst +
  239. PerfInst->ByteLength);
  240. // Locate the instance name.
  241. // ==========================
  242. LPWSTR pName = (LPWSTR) ((PBYTE)PerfInst + PerfInst->NameOffset);
  243. // Find the instance in the refresher, if there is one, which
  244. // corresponds to the instance we are looking at.
  245. // ==========================================================
  246. CClassMapInfo *pClassMap = 0;
  247. IWbemObjectAccess *pInst = 0;
  248. BOOL bRes = pRef->FindInst(
  249. PerfObj->ObjectNameTitleIndex, // Object type (WBEM Class)
  250. pName, // Instance name
  251. &pInst,
  252. &pClassMap
  253. );
  254. // Retrieve all counters for the instance if it was one of the instances
  255. // we are supposed to be refreshing.
  256. // =====================================================================
  257. if (bRes)
  258. {
  259. for (j = 0; j < PerfObj->NumCounters; j++ )
  260. {
  261. LONG hPropHandle = pClassMap->GetPropHandle(CurCntr->CounterNameTitleIndex);
  262. if (hPropHandle == 0)
  263. continue;
  264. // Data is (LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset);
  265. if ((CurCntr->CounterType & 0x700) == 0)
  266. {
  267. LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + CurCntr->CounterOffset));
  268. HRESULT hRes = pInst->WriteDWORD(hPropHandle, *pdwVal);
  269. }
  270. // Get next counter.
  271. // =================
  272. CurCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)CurCntr +
  273. CurCntr->ByteLength);
  274. }
  275. }
  276. // Get the next instance.
  277. // ======================
  278. PerfInst = (PPERF_INSTANCE_DEFINITION)((PBYTE)PtrToCntr +
  279. PtrToCntr->ByteLength);
  280. }
  281. }
  282. // Cases where the counters have no instances.
  283. // ===========================================
  284. else
  285. {
  286. // Get the first counter.
  287. // ======================
  288. PtrToCntr = (PPERF_COUNTER_BLOCK) ((PBYTE)PerfObj +
  289. PerfObj->DefinitionLength );
  290. // Find the singleton WBEM instance which correponds to the singleton perf instance
  291. // along with its class def so that we have the property handles.
  292. //
  293. // Note that since the perf object index translates to a WBEM class and there
  294. // can only be one instance, all that is required to find the instance in the
  295. // refresher is the perf object title index.
  296. // =================================================================================
  297. CClassMapInfo *pClassMap = 0;
  298. IWbemObjectAccess *pInst = 0;
  299. BOOL bRes = pRef->FindSingletonInst(
  300. PerfObj->ObjectNameTitleIndex,
  301. &pInst,
  302. &pClassMap
  303. );
  304. // Retrieve all counters if the instance is one we are supposed to be refreshing.
  305. // ==============================================================================
  306. if (bRes)
  307. {
  308. for( j=0; j < PerfObj->NumCounters; j++ )
  309. {
  310. // Get the property handle for the counter.
  311. // ========================================
  312. LONG hPropHandle = pClassMap->GetPropHandle(PerfCntr->CounterNameTitleIndex);
  313. if (hPropHandle == 0)
  314. continue;
  315. // Data is (LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset);
  316. // We will ignore non-DWORD types for now.
  317. // =======================================
  318. if ((PerfCntr->CounterType & 0x700) == 0)
  319. {
  320. LPDWORD pdwVal = LPDWORD((LPVOID)((PBYTE)PtrToCntr + PerfCntr->CounterOffset));
  321. HRESULT hRes = pInst->WriteDWORD(hPropHandle, *pdwVal);
  322. }
  323. PerfCntr = (PPERF_COUNTER_DEFINITION)((PBYTE)PerfCntr +
  324. PerfCntr->ByteLength);
  325. }
  326. }
  327. }
  328. // Get the next object type.
  329. // =========================
  330. PerfObj = (PPERF_OBJECT_TYPE)((PBYTE)PerfObj +
  331. PerfObj->TotalByteLength);
  332. }
  333. }
  334. //***************************************************************************
  335. //
  336. // QueryInstances
  337. //
  338. // Used to send back all instances of a perf counter. The counter
  339. // is specified by the <pClassMap> object, which is tightly bound to
  340. // a particular counter.
  341. //
  342. //***************************************************************************
  343. BOOL PerfHelper::QueryInstances(
  344. CClassMapInfo *pClassMap,
  345. IWbemObjectSink *pSink
  346. )
  347. {
  348. DWORD dwBufSize = 0;
  349. DWORD dwType = 0;
  350. LPBYTE pBuf = 0;
  351. for (;;)
  352. {
  353. dwBufSize += 0x20000; // 128K
  354. pBuf = new BYTE[dwBufSize];
  355. wchar_t ID[32];
  356. LONG lStatus;
  357. swprintf(ID, L"%d", pClassMap->m_dwObjectId);
  358. lStatus = RegQueryValueExW(
  359. HKEY_PERFORMANCE_DATA,
  360. ID,
  361. 0,
  362. &dwType,
  363. pBuf,
  364. &dwBufSize
  365. );
  366. if (lStatus == ERROR_MORE_DATA)
  367. {
  368. continue;
  369. }
  370. if (lStatus)
  371. return FALSE;
  372. break;
  373. }
  374. // Decode the instances and send them back.
  375. // ========================================
  376. GetInstances(pBuf, pClassMap, pSink);
  377. // Cleanup.
  378. // ========
  379. delete [] pBuf;
  380. return TRUE;
  381. }
  382. //***************************************************************************
  383. //
  384. // RefreshInstances
  385. //
  386. // Used to refresh a set of instances.
  387. //
  388. //***************************************************************************
  389. BOOL PerfHelper::RefreshInstances(
  390. CNt5Refresher *pRef
  391. )
  392. {
  393. DWORD dwBufSize = 0;
  394. DWORD dwType = 0;
  395. LPBYTE pBuf = 0;
  396. // Build up the Perf Object ID list.
  397. // =================================
  398. DWORD dwNumIds;
  399. DWORD *pdwIdList;
  400. pRef->GetObjectIds(&dwNumIds, &pdwIdList);
  401. wchar_t *IDList = new wchar_t[dwNumIds * 8]; // Allow 8 wide chars per id
  402. IDList[0] = 0;
  403. for (DWORD n = 0; n < dwNumIds; n++)
  404. {
  405. wchar_t Tmp[32];
  406. swprintf(Tmp, L"%d", pdwIdList[n]);
  407. if (n > 0)
  408. wcscat(IDList, L" ");
  409. wcscat(IDList, Tmp);
  410. }
  411. delete [] pdwIdList;
  412. for (;;)
  413. {
  414. dwBufSize += 0x20000; // 128K
  415. pBuf = new BYTE[dwBufSize];
  416. LONG lStatus;
  417. lStatus = RegQueryValueExW(
  418. HKEY_PERFORMANCE_DATA,
  419. IDList,
  420. 0,
  421. &dwType,
  422. pBuf,
  423. &dwBufSize
  424. );
  425. if (lStatus == ERROR_MORE_DATA)
  426. {
  427. continue;
  428. }
  429. if (lStatus)
  430. {
  431. delete [] pBuf;
  432. delete [] IDList;
  433. return FALSE;
  434. }
  435. break;
  436. }
  437. // Decode the instances and send them back.
  438. // ========================================
  439. RefreshInstances(pBuf, pRef);
  440. // Cleanup.
  441. // ========
  442. delete [] pBuf;
  443. delete [] IDList;
  444. return TRUE;
  445. }