Leaked source code of windows server 2003
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.

798 lines
26 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. perfcpu.c
  5. Abstract:
  6. This file implements an Performance Object that presents
  7. System Processor performance object data
  8. Created:
  9. Bob Watson 22-Oct-1996
  10. Revision History
  11. --*/
  12. //
  13. // Include Files
  14. //
  15. #include <nt.h>
  16. #include <ntrtl.h>
  17. #include <nturtl.h>
  18. #include <windows.h>
  19. #include <assert.h>
  20. #include <winperf.h>
  21. #include <ntprfctr.h>
  22. #define PERF_HEAP hLibHeap
  23. #include <perfutil.h>
  24. #include "perfos.h"
  25. #include "perfosmc.h"
  26. #include "datacpu.h"
  27. DWORD dwCpuOpenCount = 0; // count of "Open" threads
  28. // variables local to this module.
  29. SYSTEM_INTERRUPT_INFORMATION *pProcessorInterruptInformation = NULL;
  30. DWORD dwInterruptInfoBufferSize = 0;
  31. SYSTEM_PROCESSOR_IDLE_INFORMATION *pProcessorIdleInformation = NULL;
  32. DWORD dwProcessorIdleBufferSize = 0;
  33. UCHAR *pProcessorBuffer = NULL;
  34. ULONG ProcessorBufSize = 0;
  35. BOOL bPerfCpuUseIdleData = FALSE;
  36. BOOL bPerfCpuIdleDataTested = FALSE;
  37. DWORD APIENTRY
  38. OpenProcessorObject (
  39. LPWSTR lpDeviceNames
  40. )
  41. /*++
  42. Routine Description:
  43. This routine will initialize the data structures used to pass
  44. data back to the registry
  45. Arguments:
  46. Pointer to object ID of each device to be opened (PerfGen)
  47. Return Value:
  48. None.
  49. --*/
  50. {
  51. DWORD status = ERROR_SUCCESS;
  52. //
  53. // Since WINLOGON is multi-threaded and will call this routine in
  54. // order to service remote performance queries, this library
  55. // must keep track of how many times it has been opened (i.e.
  56. // how many threads have accessed it). the registry routines will
  57. // limit access to the initialization routine to only one thread
  58. // at a time so synchronization (i.e. reentrancy) should not be
  59. // a problem
  60. //
  61. UNREFERENCED_PARAMETER (lpDeviceNames);
  62. if (!dwCpuOpenCount) {
  63. dwInterruptInfoBufferSize = (ULONG)BasicInfo.NumberOfProcessors *
  64. sizeof (SYSTEM_INTERRUPT_INFORMATION);
  65. pProcessorInterruptInformation = ALLOCMEM (dwInterruptInfoBufferSize);
  66. if (pProcessorInterruptInformation == NULL) {
  67. status = ERROR_OUTOFMEMORY;
  68. goto OpenExitPoint;
  69. }
  70. ProcessorBufSize = BasicInfo.NumberOfProcessors *
  71. sizeof(SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION);
  72. pProcessorBuffer = ALLOCMEM(ProcessorBufSize);
  73. if (pProcessorBuffer == NULL) {
  74. status = ERROR_OUTOFMEMORY;
  75. goto OpenExitPoint;
  76. }
  77. dwProcessorIdleBufferSize = BasicInfo.NumberOfProcessors *
  78. sizeof(SYSTEM_PROCESSOR_IDLE_INFORMATION);
  79. pProcessorIdleInformation = ALLOCMEM(dwProcessorIdleBufferSize);
  80. if (pProcessorIdleInformation == NULL) {
  81. status = ERROR_OUTOFMEMORY;
  82. goto OpenExitPoint;
  83. }
  84. }
  85. dwCpuOpenCount++; // increment OPEN counter
  86. status = ERROR_SUCCESS; // for successful exit
  87. OpenExitPoint:
  88. if (status == ERROR_OUTOFMEMORY) {
  89. if (pProcessorInterruptInformation) {
  90. FREEMEM (pProcessorInterruptInformation);
  91. pProcessorInterruptInformation = NULL;
  92. }
  93. if (pProcessorBuffer) {
  94. FREEMEM (pProcessorBuffer);
  95. pProcessorBuffer = NULL;
  96. }
  97. dwInterruptInfoBufferSize = 0;
  98. ProcessorBufSize = 0;
  99. dwProcessorIdleBufferSize = 0;
  100. }
  101. return status;
  102. }
  103. DWORD APIENTRY
  104. CollectProcessorObjectData (
  105. IN OUT LPVOID *lppData,
  106. IN OUT LPDWORD lpcbTotalBytes,
  107. IN OUT LPDWORD lpNumObjectTypes
  108. )
  109. /*++
  110. Routine Description:
  111. This routine will return the data for the processor object
  112. Arguments:
  113. IN OUT LPVOID *lppData
  114. IN: pointer to the address of the buffer to receive the completed
  115. PerfDataBlock and subordinate structures. This routine will
  116. append its data to the buffer starting at the point referenced
  117. by *lppData.
  118. OUT: points to the first byte after the data structure added by this
  119. routine. This routine updated the value at lppdata after appending
  120. its data.
  121. IN OUT LPDWORD lpcbTotalBytes
  122. IN: the address of the DWORD that tells the size in bytes of the
  123. buffer referenced by the lppData argument
  124. OUT: the number of bytes added by this routine is writted to the
  125. DWORD pointed to by this argument
  126. IN OUT LPDWORD NumObjectTypes
  127. IN: the address of the DWORD to receive the number of objects added
  128. by this routine
  129. OUT: the number of objects added by this routine is writted to the
  130. DWORD pointed to by this argument
  131. Returns:
  132. 0 if successful, else Win 32 error code of failure
  133. --*/
  134. {
  135. LONG lReturn = ERROR_SUCCESS;
  136. DWORD TotalLen; // Length of the total return block
  137. DWORD dwBufferSize;
  138. DWORD dwReturnedBufferSize = 0;
  139. PPROCESSOR_DATA_DEFINITION pProcessorDataDefinition = NULL;
  140. PPROCESSOR_COUNTER_DATA pPCD;
  141. PEX_PROCESSOR_DATA_DEFINITION pExProcessorDataDefinition = NULL;
  142. PEX_PROCESSOR_COUNTER_DATA pExPCD;
  143. PROCESSOR_COUNTER_DATA pcdTotalData;
  144. EX_PROCESSOR_COUNTER_DATA pexcdTotalData;
  145. PERF_INSTANCE_DEFINITION *pPerfInstanceDefinition;
  146. ULONG CurProc;
  147. UNICODE_STRING ProcessorName;
  148. WCHAR ProcessorNameBuffer[512];
  149. SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *pProcessorInformation = NULL;
  150. SYSTEM_PROCESSOR_IDLE_INFORMATION *pProcIdleInformation = NULL;
  151. SYSTEM_INTERRUPT_INFORMATION *pThisProcessorInterruptInformation = NULL;
  152. NTSTATUS ntStatus;
  153. //
  154. // Check for sufficient space for processor data
  155. //
  156. #ifdef DBG
  157. STARTTIMING;
  158. #endif
  159. // check for QUADWORD alignment of incoming pointer
  160. assert (((ULONG_PTR)(*lppData) & 0x00000007) == 0);
  161. if (!bPerfCpuIdleDataTested) {
  162. // call this function once to see if this info is available from the system
  163. //
  164. // get system idle information by processor
  165. //
  166. dwBufferSize = dwProcessorIdleBufferSize;
  167. ntStatus = NtQuerySystemInformation(
  168. SystemProcessorIdleInformation,
  169. pProcessorIdleInformation,
  170. dwBufferSize,
  171. &dwReturnedBufferSize
  172. );
  173. if (NT_SUCCESS(ntStatus)) {
  174. bPerfCpuUseIdleData = TRUE;
  175. } else {
  176. memset (pProcessorIdleInformation, 0, dwProcessorIdleBufferSize);
  177. }
  178. bPerfCpuIdleDataTested = TRUE;
  179. }
  180. if (bPerfCpuUseIdleData) {
  181. pExProcessorDataDefinition = (EX_PROCESSOR_DATA_DEFINITION *) *lppData;
  182. TotalLen =
  183. sizeof(EX_PROCESSOR_DATA_DEFINITION) + // object def header
  184. ((sizeof (PERF_INSTANCE_DEFINITION) + // plus an instance for
  185. ((MAX_INSTANCE_NAME + 1) * sizeof(WCHAR)) +
  186. sizeof (PROCESSOR_COUNTER_DATA)) * // each processor and
  187. (BasicInfo.NumberOfProcessors + 1)); // the "total" instance
  188. TotalLen = QWORD_MULTIPLE(TotalLen);
  189. if ( *lpcbTotalBytes < TotalLen ) {
  190. lReturn = ERROR_MORE_DATA;
  191. *lpcbTotalBytes = (DWORD) 0;
  192. *lpNumObjectTypes = (DWORD) 0;
  193. goto COLLECT_BAIL_OUT;
  194. }
  195. } else {
  196. pProcessorDataDefinition = (PROCESSOR_DATA_DEFINITION *) *lppData;
  197. TotalLen =
  198. sizeof(PROCESSOR_DATA_DEFINITION) + // object def header
  199. ((sizeof (PERF_INSTANCE_DEFINITION) + // plus an instance for
  200. ((MAX_INSTANCE_NAME + 1) * sizeof(WCHAR)) +
  201. sizeof (PROCESSOR_COUNTER_DATA)) * // each processor and
  202. (BasicInfo.NumberOfProcessors + 1)); // the "total" instance
  203. if ( *lpcbTotalBytes < TotalLen ) {
  204. lReturn = ERROR_MORE_DATA;
  205. *lpcbTotalBytes = (DWORD) 0;
  206. *lpNumObjectTypes = (DWORD) 0;
  207. goto COLLECT_BAIL_OUT;
  208. }
  209. }
  210. //
  211. // Get processor data from system
  212. //
  213. if ( ProcessorBufSize ) {
  214. ntStatus = NtQuerySystemInformation(
  215. SystemProcessorPerformanceInformation,
  216. pProcessorBuffer,
  217. ProcessorBufSize,
  218. &dwReturnedBufferSize
  219. );
  220. if (!NT_SUCCESS(ntStatus) && (hEventLog != NULL)) {
  221. // clear buffer & log error
  222. ReportEvent (hEventLog,
  223. EVENTLOG_WARNING_TYPE,
  224. 0,
  225. PERFOS_UNABLE_QUERY_PROCSSOR_INFO,
  226. NULL,
  227. 0,
  228. sizeof(DWORD),
  229. NULL,
  230. (LPVOID)&ntStatus);
  231. memset (pProcessorBuffer, 0, ProcessorBufSize);
  232. }
  233. #ifdef DBG
  234. ENDTIMING (("PERFCPU: %d takes %I64u ms\n", __LINE__, diff));
  235. #endif
  236. }
  237. //
  238. // get system interrupt information by processor
  239. //
  240. dwInterruptInfoBufferSize = (ULONG)BasicInfo.NumberOfProcessors *
  241. sizeof (SYSTEM_INTERRUPT_INFORMATION);
  242. ntStatus = NtQuerySystemInformation(
  243. SystemInterruptInformation,
  244. pProcessorInterruptInformation,
  245. dwInterruptInfoBufferSize,
  246. &dwReturnedBufferSize
  247. );
  248. if (!NT_SUCCESS(ntStatus) && (hEventLog != NULL)) {
  249. // clear buffer & log error
  250. ReportEvent (hEventLog,
  251. EVENTLOG_WARNING_TYPE,
  252. 0,
  253. PERFOS_UNABLE_QUERY_INTERRUPT_INFO,
  254. NULL,
  255. 0,
  256. sizeof(DWORD),
  257. NULL,
  258. (LPVOID)&ntStatus);
  259. memset (pProcessorInterruptInformation, 0,
  260. (BasicInfo.NumberOfProcessors *
  261. sizeof (SYSTEM_INTERRUPT_INFORMATION)));
  262. }
  263. #ifdef DBG
  264. ENDTIMING (("PERFCPU: %d takes %I64u ms\n", __LINE__, diff));
  265. #endif
  266. if (bPerfCpuUseIdleData) {
  267. //
  268. // get system idle information by processor
  269. //
  270. dwBufferSize = dwProcessorIdleBufferSize;
  271. ntStatus = NtQuerySystemInformation(
  272. SystemProcessorIdleInformation,
  273. pProcessorIdleInformation,
  274. dwBufferSize,
  275. &dwReturnedBufferSize
  276. );
  277. if (!NT_SUCCESS(ntStatus) && (hEventLog != NULL)) {
  278. // it worked once before or this flag wouldn't be set
  279. // so report the error.
  280. ReportEvent (hEventLog,
  281. EVENTLOG_WARNING_TYPE,
  282. 0,
  283. PERFOS_UNABLE_QUERY_IDLE_INFO,
  284. NULL,
  285. 0,
  286. sizeof(DWORD),
  287. NULL,
  288. (LPVOID)&ntStatus);
  289. memset (pProcessorIdleInformation, 0, dwProcessorIdleBufferSize);
  290. }
  291. #ifdef DBG
  292. ENDTIMING (("PERFCPU: %d takes %I64u ms\n", __LINE__, diff));
  293. #endif
  294. } else {
  295. memset (pProcessorIdleInformation, 0, dwProcessorIdleBufferSize);
  296. }
  297. // clear the pointers to trap unassigned ones below
  298. pPCD = NULL;
  299. pExPCD = NULL;
  300. if ((!bPerfCpuUseIdleData) && (pProcessorDataDefinition != NULL)) {
  301. // use the original format of the structure
  302. // clear the "Total" instance
  303. memset (&pcdTotalData, 0, sizeof (pcdTotalData));
  304. // Define processor data block
  305. //
  306. memcpy (pProcessorDataDefinition,
  307. &ProcessorDataDefinition,
  308. sizeof(PROCESSOR_DATA_DEFINITION));
  309. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  310. &pProcessorDataDefinition[1];
  311. pProcessorInformation = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *)
  312. pProcessorBuffer;
  313. // point to the first processor in the returned array of interrupt
  314. // information. data is returned as an array of structures.
  315. pThisProcessorInterruptInformation = pProcessorInterruptInformation;
  316. pProcIdleInformation = pProcessorIdleInformation;
  317. for ( CurProc = 0;
  318. CurProc < (ULONG) BasicInfo.NumberOfProcessors;
  319. CurProc++ ) {
  320. //
  321. // Define processor instance 0;
  322. // More could be defined like this
  323. //
  324. ProcessorName.Length = 0;
  325. ProcessorName.MaximumLength = sizeof(ProcessorNameBuffer);
  326. ProcessorName.Buffer = ProcessorNameBuffer;
  327. ProcessorNameBuffer[0] = 0;
  328. RtlIntegerToUnicodeString(CurProc, 10, &ProcessorName);
  329. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  330. (PVOID *) &pPCD,
  331. 0,
  332. 0,
  333. (DWORD)-1,
  334. ProcessorNameBuffer);
  335. // test for Quadword Alignment
  336. assert (((ULONG_PTR)(pPCD) & 0x00000007) == 0);
  337. //
  338. // Format and collect processor data. While doing so,
  339. // accumulate totals in the System Object Type data block.
  340. // Pointers to these were initialized in QuerySystemData.
  341. //
  342. pPCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (PROCESSOR_COUNTER_DATA));
  343. pcdTotalData.ProcessorTime +=
  344. pPCD->ProcessorTime =
  345. pProcessorInformation->IdleTime.QuadPart;
  346. pcdTotalData.UserTime +=
  347. pPCD->UserTime =
  348. pProcessorInformation->UserTime.QuadPart;
  349. // kernel time is total kernel time less the time spent in the
  350. // idle thread for that processor
  351. pcdTotalData.KernelTime +=
  352. pPCD->KernelTime =
  353. pProcessorInformation->KernelTime.QuadPart -
  354. pPCD->ProcessorTime;
  355. pcdTotalData.Interrupts +=
  356. pPCD->Interrupts = pProcessorInformation->InterruptCount;
  357. pcdTotalData.DpcTime +=
  358. pPCD->DpcTime = pProcessorInformation->DpcTime.QuadPart;
  359. pcdTotalData.InterruptTime +=
  360. pPCD->InterruptTime =
  361. pProcessorInformation->InterruptTime.QuadPart;
  362. pcdTotalData.DpcCountRate +=
  363. pPCD->DpcCountRate =
  364. pThisProcessorInterruptInformation->DpcCount;
  365. pcdTotalData.DpcRate +=
  366. pPCD->DpcRate =
  367. pThisProcessorInterruptInformation->DpcRate;
  368. //
  369. // Advance to next processor
  370. //
  371. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pPCD[1];
  372. // point to next processor's data in return array(s)
  373. pProcessorInformation++;
  374. pThisProcessorInterruptInformation++;
  375. pProcIdleInformation++;
  376. }
  377. // do the total instance now
  378. ProcessorName.Length = (WORD)((lstrlenW (wszTotal) + 1) * sizeof (WCHAR));
  379. ProcessorName.MaximumLength = (WORD)(sizeof (ProcessorNameBuffer));
  380. lstrcpyW (ProcessorNameBuffer, wszTotal);
  381. ProcessorName.Buffer = ProcessorNameBuffer;
  382. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  383. (PVOID *) &pPCD,
  384. 0,
  385. 0,
  386. (DWORD)-1,
  387. ProcessorNameBuffer);
  388. // define the size
  389. pcdTotalData.CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (PROCESSOR_COUNTER_DATA));
  390. // adjust the total values of the time fields to the number of
  391. // processors to "normalize" the values
  392. pcdTotalData.ProcessorTime /= BasicInfo.NumberOfProcessors;
  393. pcdTotalData.UserTime /= BasicInfo.NumberOfProcessors;
  394. pcdTotalData.KernelTime /= BasicInfo.NumberOfProcessors;
  395. pcdTotalData.DpcTime /= BasicInfo.NumberOfProcessors;
  396. pcdTotalData.InterruptTime /= BasicInfo.NumberOfProcessors;
  397. // these fields are OK as totals
  398. //
  399. // pcdTotalData.Interrupts
  400. // pcdTotalData.DpcCountRate
  401. // pcdTotalData.DpcRate
  402. // copy total data to buffer
  403. memcpy (pPCD, &pcdTotalData, sizeof (pcdTotalData));
  404. // adjust local buffer pointer
  405. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pPCD[1];
  406. //
  407. // Now we know how large an area we used for the
  408. // processor definition, so we can update the offset
  409. // to the next object definition
  410. //
  411. pProcessorDataDefinition->ProcessorObjectType.NumInstances =
  412. BasicInfo.NumberOfProcessors + 1;
  413. *lppData = (LPVOID)pPerfInstanceDefinition;
  414. // round up buffer to the nearest QUAD WORD
  415. *lppData = ALIGN_ON_QWORD (*lppData);
  416. *lpcbTotalBytes =
  417. pProcessorDataDefinition->ProcessorObjectType.TotalByteLength =
  418. QWORD_MULTIPLE(
  419. (DWORD)((LPBYTE) pPerfInstanceDefinition -
  420. (LPBYTE) pProcessorDataDefinition));
  421. }
  422. if ((bPerfCpuUseIdleData) && (pExProcessorDataDefinition != NULL)) {
  423. // use the new extended structure
  424. // clear the "Total" instance
  425. memset (&pexcdTotalData, 0, sizeof (pexcdTotalData));
  426. // Define processor data block
  427. //
  428. memcpy (pExProcessorDataDefinition,
  429. &ExProcessorDataDefinition,
  430. sizeof(EX_PROCESSOR_DATA_DEFINITION));
  431. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)
  432. &pExProcessorDataDefinition[1];
  433. pProcessorInformation = (SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION *)
  434. pProcessorBuffer;
  435. // point to the first processor in the returned array of interrupt
  436. // information. data is returned as an array of structures.
  437. pThisProcessorInterruptInformation = pProcessorInterruptInformation;
  438. pProcIdleInformation = pProcessorIdleInformation;
  439. for ( CurProc = 0;
  440. CurProc < (ULONG) BasicInfo.NumberOfProcessors;
  441. CurProc++ ) {
  442. //
  443. // Define processor instance 0;
  444. // More could be defined like this
  445. //
  446. ProcessorName.Length = 0;
  447. ProcessorName.MaximumLength = sizeof(ProcessorNameBuffer);
  448. ProcessorName.Buffer = ProcessorNameBuffer;
  449. ProcessorNameBuffer[0] = 0;
  450. RtlIntegerToUnicodeString(CurProc, 10, &ProcessorName);
  451. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  452. (PVOID *) &pExPCD,
  453. 0,
  454. 0,
  455. (DWORD)-1,
  456. ProcessorNameBuffer);
  457. // test for Quadword Alignment
  458. assert (((ULONG_PTR)(pExPCD) & 0x00000007) == 0);
  459. //
  460. // Format and collect processor data. While doing so,
  461. // accumulate totals in the System Object Type data block.
  462. // Pointers to these were initialized in QuerySystemData.
  463. //
  464. pExPCD->CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (EX_PROCESSOR_COUNTER_DATA));
  465. pexcdTotalData.ProcessorTime +=
  466. pExPCD->ProcessorTime =
  467. pProcessorInformation->IdleTime.QuadPart;
  468. pexcdTotalData.UserTime +=
  469. pExPCD->UserTime =
  470. pProcessorInformation->UserTime.QuadPart;
  471. // kernel time is total kernel time less the time spent in the
  472. // idle thread for that processor
  473. pexcdTotalData.KernelTime +=
  474. pExPCD->KernelTime =
  475. pProcessorInformation->KernelTime.QuadPart -
  476. pExPCD->ProcessorTime;
  477. pexcdTotalData.Interrupts +=
  478. pExPCD->Interrupts = pProcessorInformation->InterruptCount;
  479. pexcdTotalData.DpcTime +=
  480. pExPCD->DpcTime = pProcessorInformation->DpcTime.QuadPart;
  481. pexcdTotalData.InterruptTime +=
  482. pExPCD->InterruptTime =
  483. pProcessorInformation->InterruptTime.QuadPart;
  484. pexcdTotalData.DpcCountRate +=
  485. pExPCD->DpcCountRate =
  486. pThisProcessorInterruptInformation->DpcCount;
  487. pexcdTotalData.DpcRate +=
  488. pExPCD->DpcRate =
  489. pThisProcessorInterruptInformation->DpcRate;
  490. // fill in the system idle info
  491. pexcdTotalData.IdleTime +=
  492. pExPCD->IdleTime =
  493. pProcIdleInformation->IdleTime;
  494. pexcdTotalData.C1Time +=
  495. pExPCD->C1Time =
  496. pProcIdleInformation->C1Time;
  497. pexcdTotalData.C2Time +=
  498. pExPCD->C2Time =
  499. pProcIdleInformation->C2Time;
  500. pexcdTotalData.C3Time +=
  501. pExPCD->C3Time =
  502. pProcIdleInformation->C3Time;
  503. pexcdTotalData.C1Transitions +=
  504. pExPCD->C1Transitions =
  505. pProcIdleInformation->C1Transitions;
  506. pexcdTotalData.C2Transitions +=
  507. pExPCD->C2Transitions =
  508. pProcIdleInformation->C2Transitions;
  509. pexcdTotalData.C3Transitions +=
  510. pExPCD->C3Transitions =
  511. pProcIdleInformation->C3Transitions;
  512. //
  513. // Advance to next processor
  514. //
  515. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pExPCD[1];
  516. // point to next processor's data in return array(s)
  517. pProcessorInformation++;
  518. pThisProcessorInterruptInformation++;
  519. pProcIdleInformation++;
  520. }
  521. // do the total instance now
  522. ProcessorName.Length = (WORD)((lstrlenW (wszTotal) + 1) * sizeof (WCHAR));
  523. ProcessorName.MaximumLength = (WORD)(sizeof (ProcessorNameBuffer));
  524. lstrcpyW (ProcessorNameBuffer, wszTotal);
  525. ProcessorName.Buffer = ProcessorNameBuffer;
  526. MonBuildInstanceDefinition(pPerfInstanceDefinition,
  527. (PVOID *) &pExPCD,
  528. 0,
  529. 0,
  530. (DWORD)-1,
  531. ProcessorNameBuffer);
  532. // define the size
  533. pexcdTotalData.CounterBlock.ByteLength = QWORD_MULTIPLE(sizeof (EX_PROCESSOR_COUNTER_DATA));
  534. // adjust the total values of the time fields to the number of
  535. // processors to "normalize" the values
  536. pexcdTotalData.ProcessorTime /= BasicInfo.NumberOfProcessors;
  537. pexcdTotalData.UserTime /= BasicInfo.NumberOfProcessors;
  538. pexcdTotalData.KernelTime /= BasicInfo.NumberOfProcessors;
  539. pexcdTotalData.IdleTime /= BasicInfo.NumberOfProcessors;
  540. pexcdTotalData.C1Time /= BasicInfo.NumberOfProcessors;
  541. pexcdTotalData.C2Time /= BasicInfo.NumberOfProcessors;
  542. pexcdTotalData.C3Time /= BasicInfo.NumberOfProcessors;
  543. pexcdTotalData.DpcTime /= BasicInfo.NumberOfProcessors;
  544. pexcdTotalData.InterruptTime /= BasicInfo.NumberOfProcessors;
  545. // these fields are OK as totals
  546. //
  547. // pexcdTotalData.Interrupts
  548. // pexcdTotalData.DpcCountRate
  549. // pexcdTotalData.DpcRate
  550. // copy total data to buffer
  551. memcpy (pExPCD, &pexcdTotalData, sizeof (pexcdTotalData));
  552. // adjust local buffer pointer
  553. pPerfInstanceDefinition = (PERF_INSTANCE_DEFINITION *)&pExPCD[1];
  554. //
  555. // Now we know how large an area we used for the
  556. // processor definition, so we can update the offset
  557. // to the next object definition
  558. //
  559. pExProcessorDataDefinition->ProcessorObjectType.NumInstances =
  560. BasicInfo.NumberOfProcessors + 1;
  561. *lpcbTotalBytes =
  562. pExProcessorDataDefinition->ProcessorObjectType.TotalByteLength =
  563. (DWORD) QWORD_MULTIPLE(((LPBYTE) pPerfInstanceDefinition) -
  564. (LPBYTE) pExProcessorDataDefinition);
  565. * lppData = (LPVOID) (((LPBYTE) pExProcessorDataDefinition) + * lpcbTotalBytes);
  566. }
  567. if ((pExProcessorDataDefinition == NULL) && (pProcessorDataDefinition == NULL)) {
  568. // then no data buffer found to use
  569. lReturn = ERROR_SUCCESS;
  570. *lpcbTotalBytes = (DWORD) 0;
  571. *lpNumObjectTypes = (DWORD) 0;
  572. goto COLLECT_BAIL_OUT;
  573. }
  574. #ifdef DBG
  575. if (*lpcbTotalBytes > TotalLen ) {
  576. DbgPrint ("\nPERFOS: Processor Perf Ctr. Instance Size Underestimated:");
  577. DbgPrint ("\nPERFOS: Estimated size: %d, Actual Size: %d", TotalLen, *lpcbTotalBytes);
  578. }
  579. #endif
  580. *lpNumObjectTypes = 1;
  581. #ifdef DBG
  582. ENDTIMING (("PERFCPU: %d takes %I64u ms total\n", __LINE__, diff));
  583. #endif
  584. return ERROR_SUCCESS;
  585. COLLECT_BAIL_OUT:
  586. #ifdef DBG
  587. ENDTIMING (("PERFCPU: %d takes %I64u ms total\n", __LINE__, diff));
  588. #endif
  589. return lReturn;
  590. }
  591. DWORD APIENTRY
  592. CloseProcessorObject (
  593. )
  594. /*++
  595. Routine Description:
  596. This routine closes the open handles
  597. Arguments:
  598. None.
  599. Return Value:
  600. ERROR_SUCCESS
  601. --*/
  602. {
  603. if (dwCpuOpenCount > 0) {
  604. if (!(--dwCpuOpenCount)) { // when this is the last thread...
  605. // close stuff here
  606. if (hLibHeap != NULL) {
  607. if (pProcessorInterruptInformation != NULL) {
  608. FREEMEM (pProcessorInterruptInformation);
  609. pProcessorInterruptInformation = NULL;
  610. }
  611. if (pProcessorBuffer != NULL) {
  612. FREEMEM (pProcessorBuffer);
  613. pProcessorBuffer = NULL;
  614. }
  615. if (pProcessorIdleInformation != NULL) {
  616. FREEMEM (pProcessorIdleInformation);
  617. pProcessorIdleInformation = NULL;
  618. }
  619. dwInterruptInfoBufferSize = 0;
  620. ProcessorBufSize = 0;
  621. dwProcessorIdleBufferSize = 0;
  622. }
  623. }
  624. } else {
  625. // if the open count is 0, then these should have been deleted
  626. assert (pProcessorBuffer == NULL);
  627. assert (pProcessorInterruptInformation == NULL);
  628. assert (pProcessorIdleInformation == NULL);
  629. }
  630. return ERROR_SUCCESS;
  631. }