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.

846 lines
20 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. perfsup.c
  5. Abstract:
  6. This module contains support routines for performance traces.
  7. Author:
  8. Stephen Hsiao (shsiao) 01-Jan-2000
  9. Revision History:
  10. --*/
  11. #include "perfp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, PerfInfoProfileInit)
  14. #pragma alloc_text(PAGE, PerfInfoProfileUninit)
  15. #pragma alloc_text(PAGE, PerfInfoStartLog)
  16. #pragma alloc_text(PAGE, PerfInfoStopLog)
  17. #endif //ALLOC_PRAGMA
  18. extern NTSTATUS IoPerfInit();
  19. extern NTSTATUS IoPerfReset();
  20. #ifdef NTPERF
  21. NTSTATUS
  22. PerfInfopStartLog(
  23. PERFINFO_GROUPMASK *pGroupMask,
  24. PERFINFO_START_LOG_LOCATION StartLogLocation
  25. );
  26. NTSTATUS
  27. PerfInfopStopLog(
  28. VOID
  29. );
  30. VOID
  31. PerfInfoSetProcessorSpeed(
  32. VOID
  33. );
  34. #endif // NTPERF
  35. VOID
  36. PerfInfoProfileInit(
  37. )
  38. /*++
  39. Routine description:
  40. Starts the sampled profile and initializes the cache
  41. Arguments:
  42. None
  43. Return Value:
  44. None
  45. --*/
  46. {
  47. #if !defined(NT_UP)
  48. PerfInfoSampledProfileCaching = FALSE;
  49. #else
  50. PerfInfoSampledProfileCaching = TRUE;
  51. #endif // !defined(NT_UP)
  52. PerfInfoSampledProfileFlushInProgress = 0;
  53. PerfProfileCache.Entries = 0;
  54. PerfInfoProfileSourceActive = PerfInfoProfileSourceRequested;
  55. KeSetIntervalProfile(PerfInfoProfileInterval, PerfInfoProfileSourceActive);
  56. KeInitializeProfile(&PerfInfoProfileObject,
  57. NULL,
  58. NULL,
  59. 0,
  60. 0,
  61. 0,
  62. PerfInfoProfileSourceActive,
  63. 0
  64. );
  65. KeStartProfile(&PerfInfoProfileObject, NULL);
  66. }
  67. VOID
  68. PerfInfoProfileUninit(
  69. )
  70. /*++
  71. Routine description:
  72. Stops the sampled profile
  73. Arguments:
  74. None
  75. Return Value:
  76. None
  77. --*/
  78. {
  79. PerfInfoProfileSourceActive = ProfileMaximum; // Invalid value stops us from
  80. // collecting more samples
  81. KeStopProfile(&PerfInfoProfileObject);
  82. PerfInfoFlushProfileCache();
  83. }
  84. NTSTATUS
  85. PerfInfoStartLog (
  86. PERFINFO_GROUPMASK *PGroupMask,
  87. PERFINFO_START_LOG_LOCATION StartLogLocation
  88. )
  89. /*++
  90. Routine Description:
  91. This routine is called by WMI as part of kernel logger initiaziation.
  92. Arguments:
  93. GroupMask - Masks for what to log. This pointer point to an allocated
  94. area in WMI LoggerContext.
  95. StartLogLocation - Indication of whether we're starting logging
  96. at boot time or while the system is running. If
  97. we're starting at boot time, we don't need to snapshot
  98. the open files because there aren't any and we would
  99. crash if we tried to find the list.
  100. Return Value:
  101. BUGBUG Need proper return/ error handling
  102. --*/
  103. {
  104. NTSTATUS Status = STATUS_SUCCESS;
  105. BOOLEAN ProfileInitialized = FALSE;
  106. BOOLEAN ContextSwapStarted = FALSE;
  107. BOOLEAN IoPerfInitialized = FALSE;
  108. PERFINFO_CLEAR_GROUPMASK(&PerfGlobalGroupMask);
  109. //
  110. // Enable logging.
  111. //
  112. PPerfGlobalGroupMask = &PerfGlobalGroupMask;
  113. PerfSetLogging(PPerfGlobalGroupMask);
  114. if (PerfIsGroupOnInGroupMask(PERF_MEMORY, PGroupMask) ||
  115. PerfIsGroupOnInGroupMask(PERF_FILENAME, PGroupMask) ||
  116. PerfIsGroupOnInGroupMask(PERF_DRIVERS, PGroupMask)) {
  117. PERFINFO_OR_GROUP_WITH_GROUPMASK(PERF_FILENAME_ALL, PGroupMask);
  118. }
  119. if (StartLogLocation == PERFINFO_START_LOG_FROM_GLOBAL_LOGGER) {
  120. //
  121. // From the wmi global logger, need to do Rundown in kernel mode
  122. //
  123. if (PerfIsGroupOnInGroupMask(PERF_PROC_THREAD, PGroupMask)) {
  124. Status = PerfInfoProcessRunDown();
  125. if (!NT_SUCCESS(Status)) {
  126. goto Finish;
  127. }
  128. }
  129. if (PerfIsGroupOnInGroupMask(PERF_PROC_THREAD, PGroupMask)) {
  130. Status = PerfInfoSysModuleRunDown();
  131. if (!NT_SUCCESS(Status)) {
  132. goto Finish;
  133. }
  134. }
  135. }
  136. //
  137. // File Name Rundown code
  138. //
  139. if ((StartLogLocation != PERFINFO_START_LOG_AT_BOOT) &&
  140. PerfIsGroupOnInGroupMask(PERF_FILENAME_ALL, PGroupMask)) {
  141. PERFINFO_OR_GROUP_WITH_GROUPMASK(PERF_FILENAME_ALL, PPerfGlobalGroupMask);
  142. Status = PerfInfoFileNameRunDown();
  143. if (!NT_SUCCESS(Status)) {
  144. goto Finish;
  145. }
  146. }
  147. //
  148. // Initialize Perf Driver hooks
  149. //
  150. if (PerfIsGroupOnInGroupMask(PERF_DRIVERS, PGroupMask)) {
  151. Status = IoPerfInit();
  152. if (NT_SUCCESS(Status)) {
  153. IoPerfInitialized = TRUE;
  154. } else {
  155. goto Finish;
  156. }
  157. }
  158. //
  159. // Enable context swap tracing
  160. //
  161. if ( PerfIsGroupOnInGroupMask(PERF_CONTEXT_SWITCH, PGroupMask) ) {
  162. WmiStartContextSwapTrace();
  163. ContextSwapStarted = TRUE;
  164. }
  165. //
  166. // Sampled Profile
  167. //
  168. if (PerfIsGroupOnInGroupMask(PERF_PROFILE, PGroupMask)) {
  169. if ((KeGetPreviousMode() == KernelMode) ||
  170. (SeSinglePrivilegeCheck(SeSystemProfilePrivilege, UserMode))) {
  171. PerfInfoProfileInit();
  172. ProfileInitialized = TRUE;
  173. } else {
  174. Status = STATUS_NO_SUCH_PRIVILEGE;
  175. goto Finish;
  176. }
  177. }
  178. #ifdef NTPERF
  179. Status = PerfInfopStartLog(PGroupMask, StartLogLocation);
  180. #else
  181. //
  182. // See if we need to empty the working set to start
  183. //
  184. if (PerfIsGroupOnInGroupMask(PERF_FOOTPRINT, PGroupMask) ||
  185. PerfIsGroupOnInGroupMask(PERF_BIGFOOT, PGroupMask)) {
  186. MmEmptyAllWorkingSets ();
  187. }
  188. #endif // NTPERF
  189. Finish:
  190. if (!NT_SUCCESS(Status)) {
  191. //
  192. // Failed to turn on trace, clean up now.
  193. //
  194. if (ContextSwapStarted) {
  195. WmiStopContextSwapTrace();
  196. }
  197. if (ProfileInitialized) {
  198. PerfInfoProfileUninit();
  199. }
  200. if (IoPerfInitialized) {
  201. IoPerfReset();
  202. }
  203. //
  204. // Disable logging.
  205. //
  206. PPerfGlobalGroupMask = NULL;
  207. PerfSetLogging(NULL);
  208. PERFINFO_CLEAR_GROUPMASK(&PerfGlobalGroupMask);
  209. } else {
  210. #ifdef NTPERF
  211. if (PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  212. //
  213. // Make a copy of the GroupMask in PerfMem header
  214. // so user mode logging can work
  215. //
  216. PerfBufHdr()->GlobalGroupMask = *PGroupMask;
  217. }
  218. #endif // NTPERF
  219. *PPerfGlobalGroupMask = *PGroupMask;
  220. }
  221. return Status;
  222. }
  223. NTSTATUS
  224. PerfInfoStopLog (
  225. )
  226. /*++
  227. Routine Description:
  228. This routine turn off the PerfInfo trace hooks.
  229. Arguments:
  230. None.
  231. Return Value:
  232. BUGBUG Need proper return/ error handling
  233. --*/
  234. {
  235. NTSTATUS Status = STATUS_SUCCESS;
  236. BOOLEAN DisableContextSwaps=FALSE;
  237. if (PPerfGlobalGroupMask == NULL) {
  238. return Status;
  239. }
  240. if (PERFINFO_IS_GROUP_ON(PERF_MEMORY)) {
  241. MmIdentifyPhysicalMemory();
  242. }
  243. if (PERFINFO_IS_GROUP_ON(PERF_PROFILE)) {
  244. PerfInfoProfileUninit();
  245. }
  246. if (PERFINFO_IS_GROUP_ON(PERF_DRIVERS)) {
  247. IoPerfReset();
  248. }
  249. #ifdef NTPERF
  250. if (PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  251. //
  252. // Now clear the GroupMask in Perfmem to stop logging.
  253. //
  254. PERFINFO_CLEAR_GROUPMASK(&PerfBufHdr()->GlobalGroupMask);
  255. }
  256. Status = PerfInfopStopLog();
  257. #endif // NTPERF
  258. if ( PERFINFO_IS_GROUP_ON(PERF_CONTEXT_SWITCH) ) {
  259. DisableContextSwaps = TRUE;
  260. }
  261. //
  262. // Reset the PPerfGlobalGroupMask.
  263. //
  264. PERFINFO_CLEAR_GROUPMASK(PPerfGlobalGroupMask);
  265. //
  266. // Disable logging.
  267. //
  268. PPerfGlobalGroupMask = NULL;
  269. PerfSetLogging(NULL);
  270. //
  271. // Disable context swap tracing.
  272. // IMPORTANT: This must be done AFTER the global flag is set to NULL!!!
  273. //
  274. if( DisableContextSwaps ) {
  275. WmiStopContextSwapTrace();
  276. }
  277. return (Status);
  278. }
  279. #ifdef NTPERF
  280. NTSTATUS
  281. PerfInfoStartPerfMemLog (
  282. )
  283. /*++
  284. Routine Description:
  285. Indicate a logger wants to log into Perfmem. If it is the first logger,
  286. initialize the shared memory buffer. Otherwise, just increment LoggerCounts.
  287. Arguments:
  288. None
  289. Return Value:
  290. STATUS_BUFFER_TOO_SMALL - if buffer not big enough
  291. STATUS_SUCCESS - otherwize
  292. --*/
  293. {
  294. PPERF_BYTE pbCurrentStart;
  295. ULONG cbBufferSize;
  296. LARGE_INTEGER PerformanceFrequency;
  297. const PPERFINFO_TRACEBUF_HEADER Buffer = PerfBufHdr();
  298. ULONG LoggerCounts;
  299. ULONG Idx;
  300. //
  301. // Is it big enough to use?
  302. //
  303. if (PerfQueryBufferSizeBytes() <= 2 * PERFINFO_HEADER_ZONE_SIZE) {
  304. PERFINFO_SET_LOGGING_TO_PERFMEM(FALSE);
  305. return STATUS_BUFFER_TOO_SMALL;
  306. }
  307. //
  308. // It is OK to use the buffer, increment the reference count
  309. //
  310. LoggerCounts = InterlockedIncrement(&Buffer->LoggerCounts);
  311. if (LoggerCounts != 1) {
  312. //
  313. // Other logger has turned on logging, just return.
  314. //
  315. return STATUS_SUCCESS;
  316. }
  317. //
  318. // Code to acquire the buffer would go here.
  319. //
  320. Buffer->SelfPointer = Buffer;
  321. Buffer->MmSystemRangeStart = MmSystemRangeStart;
  322. //
  323. // initialize buffer version information
  324. //
  325. Buffer->usMajorVersion = PERFINFO_MAJOR_VERSION;
  326. Buffer->usMinorVersion = PERFINFO_MINOR_VERSION;
  327. //
  328. // initialize timer stuff
  329. //
  330. Buffer->BufferFlag = FLAG_CYCLE_COUNT;
  331. KeQuerySystemTime(&Buffer->PerfInitSystemTime);
  332. Buffer->PerfInitTime = PerfGetCycleCount();
  333. Buffer->LastClockRef.SystemTime = Buffer->PerfInitSystemTime;
  334. Buffer->LastClockRef.TickCount = Buffer->PerfInitTime;
  335. Buffer->CalcPerfFrequency = PerfInfoTickFrequency;
  336. Buffer->EventPerfFrequency = PerfInfoTickFrequency;
  337. Buffer->PerfBufHeaderZoneSize = PERFINFO_HEADER_ZONE_SIZE;
  338. KeQueryPerformanceCounter(&PerformanceFrequency);
  339. Buffer->KePerfFrequency = PerformanceFrequency.QuadPart;
  340. //
  341. // Determine the size of the thread hash table
  342. //
  343. Buffer->ThreadHash = (PERFINFO_THREAD_HASH_ENTRY *)
  344. (((PCHAR) Buffer) + sizeof(PERFINFO_TRACEBUF_HEADER));
  345. Buffer->ThreadHashOverflow = FALSE;
  346. RtlZeroMemory(Buffer->ThreadHash,
  347. PERFINFO_THREAD_HASH_SIZE *
  348. sizeof(PERFINFO_THREAD_HASH_ENTRY));
  349. for (Idx = 0; Idx < PERFINFO_THREAD_HASH_SIZE; Idx++)
  350. Buffer->ThreadHash[Idx].CurThread = PERFINFO_INVALID_ID;
  351. pbCurrentStart = (PPERF_BYTE) Buffer + Buffer->PerfBufHeaderZoneSize;
  352. cbBufferSize = PerfQueryBufferSizeBytes() - Buffer->PerfBufHeaderZoneSize;
  353. Buffer->Start.Ptr = Buffer->Current.Ptr = pbCurrentStart;
  354. Buffer->Max.Ptr = pbCurrentStart + cbBufferSize;
  355. //
  356. // initialize version mismatch tracking
  357. //
  358. Buffer->fVersionMismatch = FALSE;
  359. //
  360. // initialize buffer overflow counter
  361. //
  362. Buffer->BufferBytesLost = 0;
  363. //
  364. // initialize the pointer to the COWHeader
  365. //
  366. Buffer->pCOWHeader = NULL;
  367. RtlZeroMemory(Buffer->Start.Ptr, Buffer->Max.Ptr - Buffer->Start.Ptr);
  368. PERFINFO_SET_LOGGING_TO_PERFMEM(TRUE);
  369. return STATUS_SUCCESS;
  370. }
  371. NTSTATUS
  372. PerfInfoStopPerfMemLog (
  373. )
  374. /*++
  375. Routine Description:
  376. Indicate a logger finishes logging. If the loggerCounts goes to zero, the
  377. buffer will be reset the next time it is turned on.
  378. Arguments:
  379. None
  380. Return Value:
  381. STATUS_BUFFER_TOO_SMALL - if buffer not big enough
  382. STATUS_SUCCESS - otherwize
  383. --*/
  384. {
  385. ULONG LoggerCounts;
  386. const PPERFINFO_TRACEBUF_HEADER Buffer = PerfBufHdr();
  387. LoggerCounts = InterlockedDecrement(&Buffer->LoggerCounts);
  388. if (LoggerCounts == 0) {
  389. //
  390. // Other logger has turned on logging, just return.
  391. //
  392. PERFINFO_SET_LOGGING_TO_PERFMEM(FALSE);
  393. }
  394. return STATUS_SUCCESS;
  395. }
  396. NTSTATUS
  397. PerfInfopStartLog(
  398. PERFINFO_GROUPMASK *pGroupMask,
  399. PERFINFO_START_LOG_LOCATION StartLogLocation
  400. )
  401. /*++
  402. Routine Description:
  403. This routine initialize the mminfo log and turn on the monitor.
  404. Arguments:
  405. GroupMask: Masks for what to log.
  406. Return Value:
  407. BUGBUG Need proper return/ error handling
  408. --*/
  409. {
  410. NTSTATUS Status = STATUS_SUCCESS;
  411. #ifdef NTPERF_PRIVATE
  412. Status = PerfInfopStartPrivateLog(pGroupMask, StartLogLocation);
  413. if (!NT_SUCCESS(Status)) {
  414. PERFINFO_CLEAR_GROUPMASK(PPerfGlobalGroupMask);
  415. return Status;
  416. }
  417. #else
  418. UNREFERENCED_PARAMETER(pGroupMask);
  419. UNREFERENCED_PARAMETER(StartLogLocation);
  420. #endif // NTPERF_PRIVATE
  421. return Status;
  422. }
  423. NTSTATUS
  424. PerfInfopStopLog (
  425. VOID
  426. )
  427. /*++
  428. Routine Description:
  429. This routine turn off the mminfo monitor and (if needed) dump the
  430. data for user.
  431. NOTE: The shutdown and hibernate paths have similar code. Check
  432. those if you make changes.
  433. Arguments:
  434. None
  435. Return Value:
  436. STATUS_SUCCESS
  437. --*/
  438. {
  439. if (PERFINFO_IS_ANY_GROUP_ON()) {
  440. #ifdef NTPERF_PRIVATE
  441. PerfInfopStopPrivateLog();
  442. #endif // NTPERF_PRIVATE
  443. if (PERFINFO_IS_LOGGING_TO_PERFMEM()) {
  444. PerfBufHdr()->LogStopTime = PerfGetCycleCount();
  445. }
  446. }
  447. return STATUS_SUCCESS;
  448. }
  449. NTSTATUS
  450. PerfInfoSetPerformanceTraceInformation (
  451. IN PVOID SystemInformation,
  452. IN ULONG SystemInformationLength
  453. )
  454. /*++
  455. Routine Description:
  456. This routine implements the performance system information functions.
  457. Arguments:
  458. SystemInformation - A pointer to a buffer which receives the specified
  459. information. This is of type PPERFINFO_PERFORMANCE_INFORMATION.
  460. SystemInformationLength - Specifies the length in bytes of the system
  461. information buffer.
  462. Return Value:
  463. STATUS_SUCCESS if successful
  464. STATUS_INFO_LENGTH_MISMATCH if size of buffer is incorrect
  465. --*/
  466. {
  467. NTSTATUS Status = STATUS_SUCCESS;
  468. PPERFINFO_PERFORMANCE_INFORMATION PerfInfo;
  469. PVOID PerfBuffer;
  470. if (SystemInformationLength < sizeof(PERFINFO_PERFORMANCE_INFORMATION)) {
  471. return STATUS_INFO_LENGTH_MISMATCH;
  472. }
  473. PerfInfo = (PPERFINFO_PERFORMANCE_INFORMATION) SystemInformation;
  474. PerfBuffer = PerfInfo + 1;
  475. switch (PerfInfo->PerformanceType) {
  476. case PerformancePerfInfoStart:
  477. // Status = PerfInfoStartLog(&PerfInfo->StartInfo.Flags, PERFINFO_START_LOG_POST_BOOT);
  478. Status = STATUS_INVALID_INFO_CLASS;
  479. break;
  480. case PerformancePerfInfoStop:
  481. // Status = PerfInfoStopLog();
  482. Status = STATUS_INVALID_INFO_CLASS;
  483. break;
  484. #ifdef NTPERF_PRIVATE
  485. case PerformanceMmInfoMarkWithFlush:
  486. case PerformanceMmInfoMark:
  487. case PerformanceMmInfoAsyncMark:
  488. {
  489. USHORT LogType;
  490. ULONG StringLength;
  491. if (PerfInfo->PerformanceType == PerformanceMmInfoMarkWithFlush) {
  492. if (PERFINFO_IS_GROUP_ON(PERF_FOOTPRINT) ||
  493. PERFINFO_IS_GROUP_ON(PERF_FOOTPRINT_PROC)) {
  494. //
  495. // BUGBUG We should get a non-Mi* call for this...
  496. //
  497. MmEmptyAllWorkingSets();
  498. Status = MmPerfSnapShotValidPhysicalMemory();
  499. }
  500. else if (PERFINFO_IS_GROUP_ON(PERF_CLEARWS)) {
  501. MmEmptyAllWorkingSets();
  502. }
  503. } else if (PerfinfoBigFootSize) {
  504. MmEmptyAllWorkingSets();
  505. }
  506. if (PERFINFO_IS_ANY_GROUP_ON()) {
  507. PERFINFO_MARK_INFORMATION Event;
  508. StringLength = SystemInformationLength - sizeof(PERFINFO_PERFORMANCE_INFORMATION);
  509. LogType = (PerfInfo->PerformanceType == PerformanceMmInfoAsyncMark) ?
  510. PERFINFO_LOG_TYPE_ASYNCMARK :
  511. PERFINFO_LOG_TYPE_MARK;
  512. PerfInfoLogBytesAndANSIString(LogType,
  513. &Event,
  514. FIELD_OFFSET(PERFINFO_MARK_INFORMATION, Name),
  515. (PCSTR) PerfBuffer,
  516. StringLength
  517. );
  518. }
  519. if (PERFINFO_IS_GROUP_ON(PERF_FOOTPRINT_PROC)) {
  520. PerfInfoDumpWSInfo (TRUE);
  521. }
  522. break;
  523. }
  524. case PerformanceMmInfoFlush:
  525. MmEmptyAllWorkingSets();
  526. break;
  527. #endif // NTPERF_PRIVATE
  528. default:
  529. #ifdef NTPERF_PRIVATE
  530. Status = PerfInfoSetPerformanceTraceInformationPrivate(PerfInfo, SystemInformationLength);
  531. #else
  532. Status = STATUS_INVALID_INFO_CLASS;
  533. #endif // NTPERF_PRIVATE
  534. break;
  535. }
  536. return Status;
  537. }
  538. NTSTATUS
  539. PerfInfoQueryPerformanceTraceInformation (
  540. IN PVOID SystemInformation,
  541. IN ULONG SystemInformationLength,
  542. OUT PULONG ReturnLength
  543. )
  544. /*++
  545. Routine Description:
  546. Satisfy queries for performance trace state information.
  547. Arguments:
  548. SystemInformation - A pointer to a buffer which receives the specified
  549. information. This is of type PPERFINFO_PERFORMANCE_INFORMATION.
  550. SystemInformationLength - Specifies the length in bytes of the system
  551. information buffer.
  552. ReturnLength - Receives the number of bytes placed in the system information buffer.
  553. Return Value:
  554. STATUS_SUCCESS
  555. --*/
  556. {
  557. NTSTATUS Status = STATUS_SUCCESS;
  558. if (SystemInformationLength != sizeof(PERFINFO_PERFORMANCE_INFORMATION)) {
  559. return STATUS_INFO_LENGTH_MISMATCH;
  560. }
  561. #ifdef NTPERF_PRIVATE
  562. return PerfInfoQueryPerformanceTraceInformationPrivate(
  563. (PPERFINFO_PERFORMANCE_INFORMATION) SystemInformation,
  564. ReturnLength
  565. );
  566. #else
  567. UNREFERENCED_PARAMETER(ReturnLength);
  568. UNREFERENCED_PARAMETER(SystemInformation);
  569. return STATUS_INVALID_INFO_CLASS;
  570. #endif // NTPERF_PRIVATE
  571. }
  572. VOID
  573. PerfInfoSetProcessorSpeed(
  574. VOID
  575. )
  576. /*++
  577. Routine Description:
  578. Calculate and set the processor speed in MHz.
  579. Note: KPRCB->MHz, once it's set reliably, should be used instead
  580. Arguments:
  581. None
  582. Return Value:
  583. None
  584. --*/
  585. {
  586. ULONGLONG start;
  587. ULONGLONG end;
  588. ULONGLONG freq;
  589. ULONGLONG TSCStart;
  590. LARGE_INTEGER *Pstart = (LARGE_INTEGER *) &start;
  591. LARGE_INTEGER *Pend = (LARGE_INTEGER *) &end;
  592. LARGE_INTEGER Delay;
  593. ULONGLONG time[3];
  594. ULONGLONG clocks;
  595. int i;
  596. int RetryCount = 50;
  597. Delay.QuadPart = -50000; // relative delay of 5ms (100ns ticks)
  598. while (RetryCount) {
  599. for (i = 0; i < 3; i++) {
  600. *Pstart = KeQueryPerformanceCounter(NULL);
  601. TSCStart = PerfGetCycleCount();
  602. KeDelayExecutionThread (KernelMode, FALSE, &Delay);
  603. clocks = PerfGetCycleCount() - TSCStart;
  604. *Pend = KeQueryPerformanceCounter((LARGE_INTEGER*)&freq);
  605. time[i] = (((end-start) * 1000000) / freq);
  606. time[i] = (clocks + time[i]/2) / time[i];
  607. }
  608. // If all three match then use it, else try again.
  609. if (time[0] == time[1] && time[1] == time[2])
  610. break;
  611. --RetryCount;
  612. }
  613. if (!RetryCount) {
  614. // Take the largest value.
  615. if (time[1] > time[0])
  616. time[0] = time[1];
  617. if (time[2] > time[0])
  618. time[0] = time[2];
  619. }
  620. PerfInfoTickFrequency = time[0];
  621. }
  622. BOOLEAN
  623. PerfInfoIsGroupOn(
  624. ULONG Group
  625. )
  626. {
  627. return PERFINFO_IS_GROUP_ON(Group);
  628. }
  629. #ifdef NTPERF_PRIVATE
  630. #include "..\..\tools\ntperf\ntosperf\perfinfokrn.c"
  631. #endif // NTPERF_PRIVATE
  632. #endif // NTPERF