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.

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