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.

1114 lines
30 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. lookmon.c
  5. Abstract:
  6. This module contains the NT/Win32 Lookaside List Monitor
  7. Author:
  8. David N. Cutler (davec) 8-Jun-1996
  9. Revision History:
  10. --*/
  11. #include "perfmtrp.h"
  12. #include <search.h>
  13. #include <malloc.h>
  14. #include <limits.h>
  15. #include <stdlib.h>
  16. //
  17. // Define lookaside query information buffer size and buffers.
  18. //
  19. #define BUFFER_SIZE (64 * 1024 / sizeof(ULONG))
  20. ULONG LargeBuffer1[BUFFER_SIZE];
  21. ULONG LargeBuffer2[BUFFER_SIZE];
  22. //
  23. // Define lookaside output structure and lookaside output information buffer.
  24. //
  25. typedef struct _LOOKASIDE_OUTPUT {
  26. USHORT CurrentDepth;
  27. USHORT MaximumDepth;
  28. ULONG Allocates;
  29. ULONG AllocateRate;
  30. ULONG AllocateHits;
  31. ULONG AllocateMisses;
  32. ULONG Frees;
  33. ULONG FreeRate;
  34. ULONG Type;
  35. ULONG Tag;
  36. ULONG Size;
  37. LOGICAL Changed;
  38. } LOOKASIDE_OUTPUT, *PLOOKASIDE_OUTPUT;
  39. LOOKASIDE_OUTPUT OutputBuffer[1000];
  40. //
  41. // Define sort types and default sort type.
  42. //
  43. #define TOTAL_ALLOCATES 0
  44. #define ALLOCATE_HITS 1
  45. #define ALLOCATE_MISSES 2
  46. #define CURRENT_DEPTH 3
  47. #define MAXIMUM_DEPTH 4
  48. #define RATE 5
  49. #define TAG 6
  50. ULONG SortBy = TAG;
  51. //
  52. // Define pool types to include and default pool type.
  53. //
  54. #define NONPAGED 0
  55. #define PAGED 1
  56. #define BOTH 2
  57. UCHAR *PoolType[] = {
  58. "Nonp",
  59. "Page"
  60. };
  61. ULONG DisplayType = BOTH;
  62. //
  63. // Define miscellaneous values.
  64. //
  65. ULONG DelayTimeMsec = 5000;
  66. ULONG NumberOfInputRecords;
  67. INPUT_RECORD InputRecord;
  68. HANDLE InputHandle;
  69. HANDLE OutputHandle;
  70. DWORD OriginalInputMode;
  71. WORD NormalAttribute;
  72. WORD HighlightAttribute;
  73. ULONG NumberOfCols;
  74. ULONG NumberOfRows;
  75. SIZE_T FirstDetailLine = 0;
  76. CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
  77. ULONG NoHighlight;
  78. //
  79. // Define filter structure and filter data.
  80. //
  81. #define MAX_FILTER 64
  82. typedef struct _FILTER {
  83. union {
  84. UCHAR Tag[4];
  85. ULONG TagUlong;
  86. };
  87. BOOLEAN Exclude;
  88. } FILTER, *PFILTER;
  89. FILTER Filter[MAX_FILTER];
  90. ULONG FilterCount = 0;
  91. VOID
  92. ShowHelpPopup(
  93. VOID
  94. );
  95. int
  96. __cdecl
  97. ulcomp(
  98. const void *e1,
  99. const void *e2
  100. );
  101. int
  102. __cdecl
  103. ulcomp(
  104. const void *E1,
  105. const void *E2
  106. )
  107. /*++
  108. Routine Description:
  109. This function compares two lookaside entries and returns the comparison
  110. value based on the comparison type.
  111. Arguments:
  112. E1 - Supplies a pointer to a lookaside output entry.
  113. E2 - Supplies a pointer to a lookaside output entry.
  114. Return Value:
  115. A negative value is returned if the first lookaside entry compares less
  116. than the second lookaside entry. A zero value is returned if the two
  117. lookaside entries compare equal. A positive nonzero value is returned if
  118. the first lookaside entry is greater than the second lookaside entry.
  119. --*/
  120. {
  121. PUCHAR C1;
  122. PUCHAR C2;
  123. PLOOKASIDE_OUTPUT L1 = (PLOOKASIDE_OUTPUT)E1;
  124. PLOOKASIDE_OUTPUT L2 = (PLOOKASIDE_OUTPUT)E2;
  125. LONG U1;
  126. C1 = (PUCHAR)&L1->Tag;
  127. C2 = (PUCHAR)&L2->Tag;
  128. switch (SortBy) {
  129. //
  130. // Sort by number of allocations in descending order.
  131. //
  132. case TOTAL_ALLOCATES:
  133. return L2->Allocates - L1->Allocates;
  134. break;
  135. //
  136. // Sort by number of allocate hits in descending order.
  137. //
  138. case ALLOCATE_HITS:
  139. return L2->AllocateHits - L1->AllocateHits;
  140. break;
  141. //
  142. // Sort by number of allocate misses in descending order.
  143. //
  144. case ALLOCATE_MISSES:
  145. return L2->AllocateMisses - L1->AllocateMisses;
  146. break;
  147. //
  148. // Sort by current depth in descending order.
  149. //
  150. case CURRENT_DEPTH:
  151. return L2->CurrentDepth - L1->CurrentDepth;
  152. break;
  153. //
  154. // Sort by maximum depth in descending order.
  155. //
  156. case MAXIMUM_DEPTH:
  157. return L2->MaximumDepth - L1->MaximumDepth;
  158. break;
  159. //
  160. // Sort by allocation rate in descending order.
  161. //
  162. case RATE:
  163. return L2->AllocateRate - L1->AllocateRate;
  164. break;
  165. //
  166. // Sort by tag, type, and size.
  167. //
  168. case TAG:
  169. U1 = *C1++ - *C2++;
  170. if (U1 == 0) {
  171. U1 = *C1++ - *C2++;
  172. if (U1 == 0) {
  173. U1 = *C1++ - *C2++;
  174. if (U1 == 0) {
  175. U1 = *C1 - *C2;
  176. if (U1 == 0) {
  177. U1 = L1->Type - L2->Type;
  178. if (U1 == 0) {
  179. U1 = L1->Size - L2->Size;
  180. }
  181. }
  182. }
  183. }
  184. }
  185. return U1;
  186. break;
  187. }
  188. return 0;
  189. }
  190. LOGICAL
  191. CheckSingleFilter (
  192. PUCHAR Tag,
  193. PUCHAR Filter
  194. )
  195. {
  196. UCHAR Fc;
  197. ULONG Index;
  198. UCHAR Tc;
  199. //
  200. // Check if tag matches filter.
  201. //
  202. for (Index = 0; Index < 4; Index += 1) {
  203. Fc = *Filter++;
  204. Tc = *Tag++;
  205. if (Fc == '*') {
  206. return TRUE;
  207. } else if (Fc == '?') {
  208. continue;
  209. } else if (Fc != Tc) {
  210. return FALSE;
  211. }
  212. }
  213. return TRUE;
  214. }
  215. LOGICAL
  216. CheckFilters (
  217. PUCHAR Tag
  218. )
  219. {
  220. ULONG Index;
  221. LOGICAL Pass;
  222. //
  223. // If there are no filters, then all tags pass. Otherwise, tags pass or
  224. // do not pass based on whether they are included or excluded.
  225. //
  226. Pass = TRUE;
  227. if (FilterCount != 0) {
  228. //
  229. // If the first filter excludes tags, then any tag not explicitly
  230. // specified passes. If the first filter includes tags, then any
  231. // tag not explicitly specified fails.
  232. //
  233. Pass = Filter[0].Exclude;
  234. for (Index = 0; Index < FilterCount; Index += 1) {
  235. if (CheckSingleFilter(Tag, (PUCHAR)&Filter[Index].Tag) != FALSE) {
  236. Pass = !Filter[Index].Exclude;
  237. break;
  238. }
  239. }
  240. }
  241. return Pass;
  242. }
  243. VOID
  244. AddFilter (
  245. BOOLEAN Exclude,
  246. PCHAR FilterString
  247. )
  248. {
  249. PFILTER f;
  250. ULONG i;
  251. PCHAR p;
  252. if (FilterCount == MAX_FILTER) {
  253. printf("Too many filters specified. Limit is %d\n", MAX_FILTER);
  254. return;
  255. }
  256. f = &Filter[FilterCount];
  257. p = f->Tag;
  258. for (i = 0; i < 4; i++) {
  259. if (*FilterString == 0) {
  260. break;
  261. }
  262. *p++ = *FilterString++;
  263. }
  264. for (; i < 4; i++) {
  265. *p++ = ' ';
  266. }
  267. f->Exclude = Exclude;
  268. FilterCount += 1;
  269. return;
  270. }
  271. VOID
  272. ParseArgs (
  273. int argc,
  274. char *argv[]
  275. )
  276. /*++
  277. Routine Description:
  278. This function parses the input arguments and sets global state variables.
  279. Arguments:
  280. argc - Supplies the number of argument strings.
  281. argv - Supplies a pointer to an array of pointers to argument strings.
  282. Return Value:
  283. None.
  284. --*/
  285. {
  286. char *p;
  287. BOOLEAN exclude;
  288. argc -= 1;
  289. argv += 1;
  290. while (argc-- > 0) {
  291. p = *argv++;
  292. if (*p == '-' || *p == '/') {
  293. p++;
  294. exclude = TRUE;
  295. switch (tolower(*p)) {
  296. case 'i':
  297. exclude = FALSE;
  298. case 'x':
  299. p++;
  300. if (strlen(p) == 0) {
  301. printf("missing filter string\n");
  302. ExitProcess(1);
  303. } else if (strlen(p) > sizeof(ULONG)) {
  304. printf("filter string too long: %s\n", p);
  305. ExitProcess(1);
  306. }
  307. AddFilter(exclude, p);
  308. break;
  309. default:
  310. printf("unknown switch: %s\n", p);
  311. ExitProcess(2);
  312. }
  313. } else {
  314. printf("unknown switch: %s\n", p);
  315. ExitProcess(2);
  316. }
  317. }
  318. return;
  319. }
  320. LOGICAL
  321. WriteConsoleLine(
  322. HANDLE OutputHandle,
  323. WORD LineNumber,
  324. LPSTR Text,
  325. LOGICAL Highlight
  326. )
  327. {
  328. COORD WriteCoord;
  329. DWORD NumberWritten;
  330. DWORD TextLength;
  331. WriteCoord.X = 0;
  332. WriteCoord.Y = LineNumber;
  333. if (!FillConsoleOutputCharacter(OutputHandle,
  334. ' ',
  335. NumberOfCols,
  336. WriteCoord,
  337. &NumberWritten)) {
  338. return FALSE;
  339. }
  340. if (!FillConsoleOutputAttribute(OutputHandle,
  341. (WORD)((Highlight && !NoHighlight) ? HighlightAttribute : NormalAttribute),
  342. NumberOfCols,
  343. WriteCoord,
  344. &NumberWritten)) {
  345. return FALSE;
  346. }
  347. if (Text == NULL || (TextLength = strlen(Text)) == 0) {
  348. return TRUE;
  349. } else {
  350. return WriteConsoleOutputCharacter(OutputHandle,
  351. Text,
  352. TextLength,
  353. WriteCoord,
  354. &NumberWritten);
  355. }
  356. }
  357. int
  358. __cdecl
  359. main(
  360. int argc,
  361. char *argv[]
  362. )
  363. /*++
  364. Routine Description:
  365. This function is the main program entry.
  366. Arguments:
  367. argc - Supplies the number of argument strings.
  368. argv - Supplies a pointer to an array of pointers to argument strings.
  369. Return Value:
  370. Final execution status.
  371. --*/
  372. {
  373. SIZE_T ActiveNumber;
  374. CHAR Buffer[512];
  375. SYSTEM_BASIC_INFORMATION BasicInfo;
  376. PULONG CurrentBuffer;
  377. ULONG GeneralNonpagedTotal;
  378. ULONG GeneralPagedTotal;
  379. SIZE_T Index;
  380. BOOLEAN Interactive;
  381. ULONG Length;
  382. ULONG LinesInHeader;
  383. PSYSTEM_LOOKASIDE_INFORMATION LookasideNew;
  384. PSYSTEM_LOOKASIDE_INFORMATION LookasideOld;
  385. HANDLE OriginalOutputHandle;
  386. PLOOKASIDE_OUTPUT Output;
  387. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  388. ULONG PoolNonpagedTotal;
  389. ULONG PoolPagedTotal;
  390. PULONG PreviousBuffer;
  391. NTSTATUS Status;
  392. PULONG TempBuffer;
  393. BOOLEAN DoHelp;
  394. BOOLEAN DoQuit;
  395. UCHAR LastKey;
  396. LONG ScrollDelta;
  397. WORD DisplayLine;
  398. UCHAR T1;
  399. UCHAR T2;
  400. UCHAR T3;
  401. UCHAR T4;
  402. //
  403. // Parse command line arguments.
  404. //
  405. DoHelp = FALSE;
  406. DoQuit = FALSE;
  407. Interactive = TRUE;
  408. ParseArgs(argc, argv);
  409. //
  410. // Get input and output handles.
  411. //
  412. InputHandle = GetStdHandle(STD_INPUT_HANDLE);
  413. OriginalOutputHandle = GetStdHandle(STD_OUTPUT_HANDLE);
  414. if (InputHandle == NULL ||
  415. OriginalOutputHandle == NULL ||
  416. !GetConsoleMode(InputHandle, &OriginalInputMode)) {
  417. Interactive = FALSE;
  418. } else {
  419. OutputHandle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  420. FILE_SHARE_WRITE | FILE_SHARE_READ,
  421. NULL,
  422. CONSOLE_TEXTMODE_BUFFER,
  423. NULL);
  424. if (OutputHandle == NULL ||
  425. !GetConsoleScreenBufferInfo(OriginalOutputHandle, &OriginalConsoleInfo) ||
  426. !SetConsoleScreenBufferSize(OutputHandle, OriginalConsoleInfo.dwSize) ||
  427. !SetConsoleActiveScreenBuffer(OutputHandle) ||
  428. !SetConsoleMode(InputHandle, 0)) {
  429. if (OutputHandle != NULL) {
  430. CloseHandle(OutputHandle);
  431. OutputHandle = NULL;
  432. }
  433. Interactive = FALSE;
  434. } else {
  435. NormalAttribute = 0x1F;
  436. HighlightAttribute = 0x71;
  437. NumberOfCols = OriginalConsoleInfo.dwSize.X;
  438. NumberOfRows = OriginalConsoleInfo.dwSize.Y;
  439. }
  440. }
  441. NtQuerySystemInformation(SystemBasicInformation,
  442. &BasicInfo,
  443. sizeof(BasicInfo),
  444. NULL);
  445. //
  446. // If the priority class on the current process is normal, then raise
  447. // the priority class to high.
  448. //
  449. if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  450. SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  451. }
  452. //
  453. // Continuously display the lookaside information until an exit signal
  454. // is received.
  455. //
  456. CurrentBuffer = &LargeBuffer1[0];
  457. PreviousBuffer = &LargeBuffer2[0];
  458. while(TRUE) {
  459. Status = NtQuerySystemInformation(SystemPerformanceInformation,
  460. &PerfInfo,
  461. sizeof(PerfInfo),
  462. NULL);
  463. if (!NT_SUCCESS(Status)) {
  464. printf("Query performance information failed %lx\n", Status);
  465. break;
  466. }
  467. //
  468. // Query system lookaside information.
  469. //
  470. Status = NtQuerySystemInformation(SystemLookasideInformation,
  471. CurrentBuffer,
  472. BUFFER_SIZE,
  473. &Length);
  474. if (!NT_SUCCESS(Status)) {
  475. printf("Query lookaside information failed %lx\n", Status);
  476. break;
  477. }
  478. //
  479. // Compute total memory allocated to paged and nonpaged lookaside
  480. // lists.
  481. //
  482. Length /= sizeof(SYSTEM_LOOKASIDE_INFORMATION);
  483. LookasideNew = (PSYSTEM_LOOKASIDE_INFORMATION)CurrentBuffer;
  484. GeneralNonpagedTotal = 0;
  485. GeneralPagedTotal = 0;
  486. PoolNonpagedTotal = 0;
  487. PoolPagedTotal = 0;
  488. for (Index = 0; Index < Length; Index += 1) {
  489. if ((LookasideNew->Tag == 'looP') ||
  490. (LookasideNew->Tag == 'LooP')) {
  491. if (LookasideNew->Type == NONPAGED) {
  492. PoolNonpagedTotal +=
  493. (LookasideNew->CurrentDepth * LookasideNew->Size);
  494. } else {
  495. PoolPagedTotal +=
  496. (LookasideNew->CurrentDepth * LookasideNew->Size);
  497. }
  498. } else {
  499. if (LookasideNew->Type == NONPAGED) {
  500. GeneralNonpagedTotal +=
  501. (LookasideNew->CurrentDepth * LookasideNew->Size);
  502. } else {
  503. GeneralPagedTotal +=
  504. (LookasideNew->CurrentDepth * LookasideNew->Size);
  505. }
  506. }
  507. LookasideNew += 1;
  508. }
  509. //
  510. // Output total memory and available memory in kbytes.
  511. //
  512. DisplayLine = 0;
  513. sprintf(Buffer,
  514. " Total Memory: %ldkb Available Memory: %ldkb",
  515. BasicInfo.NumberOfPhysicalPages * (BasicInfo.PageSize / 1024),
  516. PerfInfo.AvailablePages * (BasicInfo.PageSize / 1024));
  517. WriteConsoleLine(OutputHandle,
  518. DisplayLine++,
  519. Buffer,
  520. FALSE);
  521. //
  522. // Output total memory reserved for nonpaged and paged pool.
  523. //
  524. sprintf(Buffer,
  525. " Pool Memory - Nonpaged: %ldkb Paged: %ldkb",
  526. PerfInfo.NonPagedPoolPages * (BasicInfo.PageSize / 1024),
  527. PerfInfo.PagedPoolPages * (BasicInfo.PageSize / 1024));
  528. WriteConsoleLine(OutputHandle,
  529. DisplayLine++,
  530. Buffer,
  531. FALSE);
  532. //
  533. // Output total memory allocated for nonpaged and paged lookaside
  534. // lists.
  535. //
  536. sprintf(Buffer,
  537. " Pool Lookaside - Nonpaged: %ldkb Paged: %ldkb",
  538. PoolNonpagedTotal / 1024,
  539. PoolPagedTotal / 1024);
  540. WriteConsoleLine(OutputHandle,
  541. DisplayLine++,
  542. Buffer,
  543. FALSE);
  544. sprintf(Buffer,
  545. " General Lookaside - Nonpaged: %ldkb Paged: %ldkb",
  546. GeneralNonpagedTotal / 1024,
  547. GeneralPagedTotal / 1024);
  548. WriteConsoleLine(OutputHandle,
  549. DisplayLine++,
  550. Buffer,
  551. FALSE);
  552. //
  553. // Output report headings.
  554. //
  555. WriteConsoleLine(OutputHandle,
  556. DisplayLine++,
  557. " Tag Type Size CurDp MaxDp Allocates Rate Frees Rate A-Hits A-Misses",
  558. FALSE);
  559. WriteConsoleLine(OutputHandle,
  560. DisplayLine++,
  561. NULL,
  562. FALSE);
  563. //
  564. // Extract the specified lookaside information.
  565. //
  566. LinesInHeader = DisplayLine;
  567. LookasideNew = (PSYSTEM_LOOKASIDE_INFORMATION)CurrentBuffer;
  568. LookasideOld = (PSYSTEM_LOOKASIDE_INFORMATION)PreviousBuffer;
  569. Output = &OutputBuffer[0];
  570. for (Index = 0; Index < Length; Index += 1) {
  571. //
  572. // Check if the tag should be extracted.
  573. //
  574. if (!CheckFilters((PUCHAR)&LookasideNew[Index].Tag)) {
  575. continue;
  576. }
  577. //
  578. // Check if the lookaside information should be extracted.
  579. //
  580. if ((DisplayType == BOTH) ||
  581. ((LookasideNew[Index].Type == 0) && (DisplayType == NONPAGED)) ||
  582. ((LookasideNew[Index].Type != 0) && (DisplayType == PAGED))) {
  583. Output->CurrentDepth = LookasideNew[Index].CurrentDepth;
  584. Output->MaximumDepth = LookasideNew[Index].MaximumDepth;
  585. Output->Allocates = LookasideNew[Index].TotalAllocates;
  586. Output->AllocateRate = Output->Allocates - LookasideNew[Index].AllocateMisses;
  587. if (Output->Allocates != 0) {
  588. Output->AllocateRate = (Output->AllocateRate * 100) / Output->Allocates;
  589. }
  590. Output->Frees = LookasideNew[Index].TotalFrees;
  591. Output->FreeRate = Output->Frees - LookasideNew[Index].FreeMisses;
  592. if (Output->Frees != 0) {
  593. Output->FreeRate = (Output->FreeRate * 100) / Output->Frees;
  594. }
  595. Output->Tag = LookasideNew[Index].Tag;
  596. Output->Type = LookasideNew[Index].Type;
  597. Output->Size = LookasideNew[Index].Size;
  598. if (LookasideNew[Index].Tag == LookasideOld[Index].Tag) {
  599. Output->Changed =
  600. LookasideNew[Index].CurrentDepth != LookasideOld[Index].CurrentDepth;
  601. Output->AllocateMisses =
  602. LookasideNew[Index].AllocateMisses - LookasideOld[Index].AllocateMisses;
  603. Output->AllocateHits =
  604. LookasideNew[Index].TotalAllocates - LookasideOld[Index].TotalAllocates - Output->AllocateMisses;
  605. } else {
  606. Output->Changed = FALSE;
  607. Output->AllocateHits = 0;
  608. Output->AllocateMisses = 0;
  609. }
  610. Output += 1;
  611. }
  612. }
  613. //
  614. // Sort the extracted lookaside information.
  615. //
  616. ActiveNumber = Output - &OutputBuffer[0];
  617. qsort((void *)&OutputBuffer,
  618. (size_t)ActiveNumber,
  619. (size_t)sizeof(LOOKASIDE_OUTPUT),
  620. ulcomp);
  621. //
  622. // Display the selected information.
  623. //
  624. for (Index = FirstDetailLine; Index < ActiveNumber; Index += 1) {
  625. if (DisplayLine >= NumberOfRows) {
  626. break;
  627. }
  628. //
  629. // Check to make sure the tag is displayable.
  630. //
  631. if ((OutputBuffer[Index].Tag == 0) ||
  632. (OutputBuffer[Index].Tag == ' ')) {
  633. OutputBuffer[Index].Tag = 'nknU';
  634. }
  635. T1 = (UCHAR)(OutputBuffer[Index].Tag & 0xff);
  636. T2 = (UCHAR)((OutputBuffer[Index].Tag >> 8) & 0xff);
  637. T3 = (UCHAR)((OutputBuffer[Index].Tag >> 16) & 0xff);
  638. T4 = (UCHAR)((OutputBuffer[Index].Tag >> 24) & 0xff);
  639. if (T1 == 0) {
  640. T1 = ' ';
  641. }
  642. if (T2 == 0) {
  643. T2 = ' ';
  644. }
  645. if (T3 == 0) {
  646. T3 = ' ';
  647. }
  648. if (T4 == 0) {
  649. T4 = ' ';
  650. }
  651. if ((!isalpha(T1) && (T1 != ' ')) ||
  652. (!isalpha(T2) && (T2 != ' ')) ||
  653. (!isalpha(T3) && (T3 != ' ')) ||
  654. (!isalpha(T4) && (T4 != ' '))) {
  655. OutputBuffer[Index].Tag = 'nknU';
  656. }
  657. sprintf(Buffer,
  658. " %c%c%c%c %4s %4ld %5ld %5ld %9ld %3ld%% %9ld %3ld%% %6ld %6ld",
  659. T1,
  660. T2,
  661. T3,
  662. T4,
  663. PoolType[OutputBuffer[Index].Type],
  664. OutputBuffer[Index].Size,
  665. OutputBuffer[Index].CurrentDepth,
  666. OutputBuffer[Index].MaximumDepth,
  667. OutputBuffer[Index].Allocates,
  668. OutputBuffer[Index].AllocateRate,
  669. OutputBuffer[Index].Frees,
  670. OutputBuffer[Index].FreeRate,
  671. OutputBuffer[Index].AllocateHits,
  672. OutputBuffer[Index].AllocateMisses);
  673. WriteConsoleLine(OutputHandle,
  674. DisplayLine++,
  675. Buffer,
  676. OutputBuffer[Index].Changed);
  677. }
  678. //
  679. // If the entire screen is not filled by the selected information,
  680. // then fill the rest of the screen with blank lines.
  681. //
  682. while (DisplayLine < NumberOfRows) {
  683. WriteConsoleLine(OutputHandle,
  684. DisplayLine++,
  685. "",
  686. FALSE);
  687. }
  688. //
  689. // Wait for input or timeout.
  690. //
  691. TempBuffer = PreviousBuffer;
  692. PreviousBuffer = CurrentBuffer;
  693. CurrentBuffer = TempBuffer;
  694. while (WaitForSingleObject(InputHandle, DelayTimeMsec) == STATUS_WAIT_0) {
  695. //
  696. // Check for input record
  697. //
  698. if (ReadConsoleInput(InputHandle, &InputRecord, 1, &NumberOfInputRecords) &&
  699. InputRecord.EventType == KEY_EVENT &&
  700. InputRecord.Event.KeyEvent.bKeyDown) {
  701. LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
  702. if (LastKey<' ') {
  703. ScrollDelta = 0;
  704. if (LastKey == 'C'-'A' + 1) {
  705. DoQuit = TRUE;
  706. } else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
  707. case VK_ESCAPE:
  708. DoQuit = TRUE;
  709. break;
  710. case VK_PRIOR:
  711. ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfRows);
  712. break;
  713. case VK_NEXT:
  714. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfRows;
  715. break;
  716. case VK_UP:
  717. ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
  718. break;
  719. case VK_DOWN:
  720. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
  721. break;
  722. case VK_HOME:
  723. FirstDetailLine = 0;
  724. break;
  725. case VK_END:
  726. if (ActiveNumber <= (NumberOfRows - LinesInHeader)) {
  727. FirstDetailLine = 0;
  728. } else {
  729. FirstDetailLine = ActiveNumber - NumberOfRows + LinesInHeader;
  730. }
  731. break;
  732. }
  733. if (ScrollDelta != 0) {
  734. if (ScrollDelta < 0) {
  735. if (FirstDetailLine <= (ULONG)-ScrollDelta) {
  736. FirstDetailLine = 0;
  737. } else {
  738. FirstDetailLine += ScrollDelta;
  739. }
  740. } else {
  741. if ((ActiveNumber + LinesInHeader) > NumberOfRows) {
  742. FirstDetailLine += ScrollDelta;
  743. if (FirstDetailLine >= (ActiveNumber - NumberOfRows + LinesInHeader)) {
  744. FirstDetailLine = ActiveNumber - NumberOfRows + LinesInHeader;
  745. }
  746. }
  747. }
  748. }
  749. } else {
  750. switch (toupper( LastKey )) {
  751. case 'Q':
  752. DoQuit = TRUE;
  753. break;
  754. case 'A':
  755. SortBy = TOTAL_ALLOCATES;
  756. FirstDetailLine = 0;
  757. break;
  758. case 'C':
  759. SortBy = CURRENT_DEPTH;
  760. FirstDetailLine = 0;
  761. break;
  762. case 'H':
  763. case '?':
  764. DoHelp = TRUE;
  765. break;
  766. case 'L':
  767. NoHighlight = 1 - NoHighlight;
  768. break;
  769. case 'M':
  770. SortBy = MAXIMUM_DEPTH;
  771. FirstDetailLine = 0;
  772. break;
  773. case 'P':
  774. DisplayType += 1;
  775. if (DisplayType > BOTH) {
  776. DisplayType = NONPAGED;
  777. }
  778. FirstDetailLine = 0;
  779. break;
  780. case 'R':
  781. SortBy = RATE;
  782. FirstDetailLine = 0;
  783. break;
  784. case 'S':
  785. SortBy = ALLOCATE_MISSES;
  786. FirstDetailLine = 0;
  787. break;
  788. case 'T':
  789. SortBy = TAG;
  790. FirstDetailLine = 0;
  791. break;
  792. case 'X':
  793. SortBy = ALLOCATE_HITS;
  794. FirstDetailLine = 0;
  795. break;
  796. }
  797. }
  798. break;
  799. }
  800. }
  801. if (DoQuit) {
  802. break;
  803. }
  804. if (DoHelp) {
  805. DoHelp = FALSE;
  806. ShowHelpPopup();
  807. }
  808. }
  809. if (Interactive) {
  810. SetConsoleActiveScreenBuffer(OriginalOutputHandle);
  811. SetConsoleMode(InputHandle, OriginalInputMode);
  812. CloseHandle(OutputHandle);
  813. }
  814. ExitProcess(0);
  815. return 0;
  816. }
  817. VOID
  818. ShowHelpPopup(
  819. VOID
  820. )
  821. {
  822. HANDLE PopupHandle;
  823. WORD n;
  824. PopupHandle = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
  825. FILE_SHARE_WRITE | FILE_SHARE_READ,
  826. NULL,
  827. CONSOLE_TEXTMODE_BUFFER,
  828. NULL);
  829. if (PopupHandle == NULL) {
  830. return;
  831. }
  832. SetConsoleActiveScreenBuffer( PopupHandle );
  833. n = 0;
  834. WriteConsoleLine(PopupHandle, n++, NULL, FALSE );
  835. WriteConsoleLine(PopupHandle, n++, " Lookaside Monitor Help", FALSE);
  836. WriteConsoleLine(PopupHandle, n++, NULL, FALSE );
  837. WriteConsoleLine(PopupHandle, n++, " columns:", FALSE );
  838. WriteConsoleLine(PopupHandle, n++, " Tag is the four character name of the lookaside list", FALSE);
  839. WriteConsoleLine(PopupHandle, n++, " Type is page(d) or nonp(aged)", FALSE);
  840. WriteConsoleLine(PopupHandle, n++, " Size is size of the pool allocation in bytes", FALSE);
  841. WriteConsoleLine(PopupHandle, n++, " CurDp is the current depth of the lookaside list", FALSE);
  842. WriteConsoleLine(PopupHandle, n++, " MaxDp is the maximum depth of the lookaside list", FALSE);
  843. WriteConsoleLine(PopupHandle, n++, " Allocates is the total number of allocations from the lookaside list", FALSE);
  844. WriteConsoleLine(PopupHandle, n++, " Rate is the percent of allocates that hit in the lookaside list", FALSE);
  845. WriteConsoleLine(PopupHandle, n++, " Frees is the total number of frees to the lookaside list", FALSE);
  846. WriteConsoleLine(PopupHandle, n++, " Rate is the percent of frees that hit in the lookaside list", FALSE);
  847. WriteConsoleLine(PopupHandle, n++, " A-Hits is the number of allocation hits within the display period", FALSE);
  848. WriteConsoleLine(PopupHandle, n++, " A-Misses is the number of allocation misses within the display period", FALSE);
  849. WriteConsoleLine(PopupHandle, n++, NULL, FALSE);
  850. WriteConsoleLine(PopupHandle, n++, " switches:", FALSE);
  851. WriteConsoleLine(PopupHandle, n++, " ? or h - gives this help", FALSE);
  852. WriteConsoleLine(PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE);
  853. WriteConsoleLine(PopupHandle, n++, " q - quits", FALSE);
  854. WriteConsoleLine(PopupHandle, n++, " p - toggles default pool display between both, page(d), and nonp(aged)", FALSE);
  855. WriteConsoleLine(PopupHandle, n++, NULL, FALSE);
  856. WriteConsoleLine(PopupHandle, n++, " sorting switches:", FALSE);
  857. WriteConsoleLine(PopupHandle, n++, " a - sort by total allocations", FALSE);
  858. WriteConsoleLine(PopupHandle, n++, " c - sort by current depth", FALSE);
  859. WriteConsoleLine(PopupHandle, n++, " m - sort by maximum depth", FALSE);
  860. WriteConsoleLine(PopupHandle, n++, " r - sort by allocation hit rate", FALSE);
  861. WriteConsoleLine(PopupHandle, n++, " s - sort by allocate misses", FALSE);
  862. WriteConsoleLine(PopupHandle, n++, " t - sort by tag, type, and size", FALSE);
  863. WriteConsoleLine(PopupHandle, n++, " x - sort by allocate hits", FALSE);
  864. WriteConsoleLine(PopupHandle, n++, NULL, FALSE);
  865. WriteConsoleLine(PopupHandle, n++, " command line switches", FALSE);
  866. WriteConsoleLine(PopupHandle, n++, " -i<tag> - list only matching tags", FALSE);
  867. WriteConsoleLine(PopupHandle, n++, " -x<tag> - list everything except matching tags", FALSE);
  868. WriteConsoleLine(PopupHandle, n++, " <tag> can include * and ?", FALSE);
  869. WriteConsoleLine(PopupHandle, n++, NULL, FALSE );
  870. WriteConsoleLine(PopupHandle, n++, NULL, FALSE );
  871. while (TRUE) {
  872. if (WaitForSingleObject(InputHandle, DelayTimeMsec) == STATUS_WAIT_0 &&
  873. ReadConsoleInput(InputHandle, &InputRecord, 1, &NumberOfInputRecords) &&
  874. InputRecord.EventType == KEY_EVENT &&
  875. InputRecord.Event.KeyEvent.bKeyDown &&
  876. InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE
  877. ) {
  878. break;
  879. }
  880. }
  881. SetConsoleActiveScreenBuffer(OutputHandle);
  882. CloseHandle(PopupHandle);
  883. return;
  884. }