Windows NT 4.0 source code leak
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.

967 lines
30 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. poolmon.c
  5. Abstract:
  6. This module contains the NT/Win32 Pool Monitor
  7. Author:
  8. Lou Perazzoli (loup) 13-Sep-1993
  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. #define BUFFER_SIZE 64*1024
  17. #define CPU_USAGE 0
  18. #define QUOTAS 1
  19. #define TAG 0
  20. #define ALLOC 1
  21. #define FREE 2
  22. #define DIFF 3
  23. #define BYTES 4
  24. #define EACH 5
  25. #define LIGHT 6
  26. #define NONPAGED 0
  27. #define PAGED 1
  28. #define BOTH 2
  29. UCHAR *PoolType[] = {
  30. "Nonp ",
  31. "Paged" };
  32. UCHAR LargeBuffer1[BUFFER_SIZE];
  33. UCHAR LargeBuffer2[BUFFER_SIZE];
  34. typedef struct _POOLMON_OUT {
  35. union {
  36. UCHAR Tag[4];
  37. ULONG TagUlong;
  38. };
  39. UCHAR NullByte;
  40. BOOLEAN Changed;
  41. ULONG Type;
  42. ULONG Allocs;
  43. ULONG AllocsDiff;
  44. ULONG Frees;
  45. ULONG FreesDiff;
  46. ULONG Allocs_Frees;
  47. ULONG Used;
  48. ULONG UsedDiff;
  49. ULONG Each;
  50. } POOLMON_OUT, *PPOOLMON_OUT;
  51. POOLMON_OUT OutBuffer[1000];
  52. ULONG DisplayType = BOTH;
  53. ULONG SortBy = TAG;
  54. ULONG Paren;
  55. ULONG DelayTimeMsec = 5000;
  56. BOOLEAN Interactive;
  57. ULONG NumberOfInputRecords;
  58. INPUT_RECORD InputRecord;
  59. HANDLE InputHandle;
  60. HANDLE OriginalOutputHandle;
  61. HANDLE OutputHandle;
  62. DWORD OriginalInputMode;
  63. WORD NormalAttribute;
  64. WORD HighlightAttribute;
  65. ULONG NumberOfCols;
  66. ULONG NumberOfRows;
  67. ULONG NumberOfDetailLines;
  68. ULONG FirstDetailLine;
  69. CONSOLE_SCREEN_BUFFER_INFO OriginalConsoleInfo;
  70. ULONG NoHighlight;
  71. BOOLEAN DisplayTotals = FALSE;
  72. POOLMON_OUT Totals[2];
  73. typedef struct _FILTER {
  74. union {
  75. UCHAR Tag[4];
  76. ULONG TagUlong;
  77. };
  78. BOOLEAN Exclude;
  79. } FILTER, *PFILTER;
  80. #define MAX_FILTER 64
  81. FILTER Filter[MAX_FILTER];
  82. ULONG FilterCount = 0;
  83. VOID
  84. ShowHelpPopup( VOID );
  85. int _CRTAPI1
  86. ulcomp(const void *e1,const void *e2);
  87. int _CRTAPI1
  88. ulcomp(const void *e1,const void *e2)
  89. {
  90. ULONG u1;
  91. switch (SortBy) {
  92. case TAG:
  93. u1 = ((PUCHAR)e1)[0] - ((PUCHAR)e2)[0];
  94. if (u1 != 0) {
  95. return u1;
  96. }
  97. u1 = ((PUCHAR)e1)[1] - ((PUCHAR)e2)[1];
  98. if (u1 != 0) {
  99. return u1;
  100. }
  101. u1 = ((PUCHAR)e1)[2] - ((PUCHAR)e2)[2];
  102. if (u1 != 0) {
  103. return u1;
  104. }
  105. u1 = ((PUCHAR)e1)[3] - ((PUCHAR)e2)[3];
  106. return u1;
  107. break;
  108. case ALLOC:
  109. if (Paren & 1) {
  110. u1 = ((PPOOLMON_OUT)e2)->AllocsDiff -
  111. ((PPOOLMON_OUT)e1)->AllocsDiff;
  112. } else {
  113. u1 = ((PPOOLMON_OUT)e2)->Allocs -
  114. ((PPOOLMON_OUT)e1)->Allocs;
  115. }
  116. return (u1);
  117. break;
  118. case FREE:
  119. if (Paren & 1) {
  120. u1 = ((PPOOLMON_OUT)e2)->FreesDiff -
  121. ((PPOOLMON_OUT)e1)->FreesDiff;
  122. } else {
  123. u1 = ((PPOOLMON_OUT)e2)->Frees -
  124. ((PPOOLMON_OUT)e1)->Frees;
  125. }
  126. return (u1);
  127. break;
  128. case BYTES:
  129. if (Paren & 1) {
  130. u1 = ((PPOOLMON_OUT)e2)->UsedDiff -
  131. ((PPOOLMON_OUT)e1)->UsedDiff;
  132. } else {
  133. u1 = ((PPOOLMON_OUT)e2)->Used -
  134. ((PPOOLMON_OUT)e1)->Used;
  135. }
  136. return (u1);
  137. break;
  138. case DIFF:
  139. u1 = ((PPOOLMON_OUT)e2)->Allocs_Frees -
  140. ((PPOOLMON_OUT)e1)->Allocs_Frees;
  141. return (u1);
  142. break;
  143. case EACH:
  144. u1 = ((PPOOLMON_OUT)e2)->Each -
  145. ((PPOOLMON_OUT)e1)->Each;
  146. return (u1);
  147. break;
  148. default:
  149. return(0);
  150. break;
  151. }
  152. }
  153. BOOLEAN
  154. CheckSingleFilter (
  155. PCHAR Tag,
  156. PCHAR Filter
  157. )
  158. {
  159. ULONG i;
  160. CHAR tc;
  161. CHAR fc;
  162. for ( i = 0; i < 4; i++ ) {
  163. tc = *Tag++;
  164. fc = *Filter++;
  165. if ( fc == '*' ) return TRUE;
  166. if ( fc == '?' ) continue;
  167. if ( tc != fc ) return FALSE;
  168. }
  169. return TRUE;
  170. }
  171. BOOLEAN
  172. CheckFilters (
  173. PSYSTEM_POOLTAG TagInfo
  174. )
  175. {
  176. BOOLEAN pass;
  177. ULONG i;
  178. PCHAR tag;
  179. //
  180. // If there are no filters, all tags pass.
  181. //
  182. if ( FilterCount == 0 ) {
  183. return TRUE;
  184. }
  185. //
  186. // There are filters. If the first filter excludes tags, then any
  187. // tag not explicitly mentioned passes. If the first filter includes
  188. // tags, then any tag not explicitly mentioned fails.
  189. //
  190. if ( Filter[0].Exclude ) {
  191. pass = TRUE;
  192. } else {
  193. pass = FALSE;
  194. }
  195. tag = TagInfo->Tag;
  196. for ( i = 0; i < FilterCount; i++ ) {
  197. if ( CheckSingleFilter( tag, (PCHAR)&Filter[i].Tag ) ) {
  198. pass = !Filter[i].Exclude;
  199. }
  200. }
  201. return pass;
  202. }
  203. VOID
  204. AddFilter (
  205. BOOLEAN Exclude,
  206. PCHAR FilterString
  207. )
  208. {
  209. PFILTER f;
  210. PCHAR p;
  211. ULONG i;
  212. if ( FilterCount == MAX_FILTER ) {
  213. printf( "Too many filters specified. Limit is %d\n", MAX_FILTER );
  214. return;
  215. }
  216. f = &Filter[FilterCount];
  217. p = f->Tag;
  218. for ( i = 0; i < 4; i++ ) {
  219. if ( *FilterString == 0 ) break;
  220. *p++ = *FilterString++;
  221. }
  222. for ( ; i < 4; i++ ) {
  223. *p++ = ' ';
  224. }
  225. f->Exclude = Exclude;
  226. FilterCount++;
  227. return;
  228. }
  229. VOID
  230. ParseArgs (
  231. int argc,
  232. char *argv[]
  233. )
  234. {
  235. char *p;
  236. BOOLEAN exclude;
  237. argc--;
  238. argv++;
  239. while ( argc-- > 0 ) {
  240. p = *argv++;
  241. if ( *p == '-' || *p == '/' ) {
  242. p++;
  243. exclude = TRUE;
  244. switch ( tolower(*p) ) {
  245. case 'i':
  246. exclude = FALSE;
  247. case 'x':
  248. p++;
  249. if ( strlen(p) == 0 ) {
  250. printf( "missing filter string\n" );
  251. ExitProcess( 1 );
  252. } else if ( strlen(p) <= sizeof(ULONG) ) {
  253. AddFilter( exclude, p );
  254. } else {
  255. printf( "filter string too long: %s\n", p );
  256. ExitProcess( 1 );
  257. }
  258. break;
  259. case 'e':
  260. DisplayTotals = TRUE;
  261. break;
  262. case 't':
  263. SortBy = TAG;
  264. break;
  265. case 'a':
  266. SortBy = ALLOC;
  267. break;
  268. case 'u':
  269. case 'b':
  270. SortBy = BYTES;
  271. break;
  272. case 'f':
  273. SortBy = FREE;
  274. break;
  275. case 'd':
  276. SortBy = DIFF;
  277. break;
  278. case 'm':
  279. SortBy = EACH;
  280. case 'l':
  281. NoHighlight = 1 - NoHighlight;
  282. break;
  283. case 'p':
  284. DisplayType += 1;
  285. if (DisplayType > BOTH) {
  286. DisplayType = NONPAGED;
  287. }
  288. break;
  289. case '(':
  290. case ')':
  291. Paren += 1;
  292. break;
  293. default:
  294. printf( "unknown switch: %s\n", p );
  295. ExitProcess( 2 );
  296. }
  297. } else {
  298. printf( "unknown switch: %s\n", p );
  299. ExitProcess( 2 );
  300. }
  301. }
  302. return;
  303. }
  304. BOOL
  305. WriteConsoleLine(
  306. HANDLE OutputHandle,
  307. WORD LineNumber,
  308. LPSTR Text,
  309. BOOL Highlight
  310. )
  311. {
  312. COORD WriteCoord;
  313. DWORD NumberWritten;
  314. DWORD TextLength;
  315. WriteCoord.X = 0;
  316. WriteCoord.Y = LineNumber;
  317. if (!FillConsoleOutputCharacter( OutputHandle,
  318. ' ',
  319. NumberOfCols,
  320. WriteCoord,
  321. &NumberWritten
  322. )
  323. ) {
  324. return FALSE;
  325. }
  326. if (!FillConsoleOutputAttribute( OutputHandle,
  327. (WORD)((Highlight && !NoHighlight) ? HighlightAttribute : NormalAttribute),
  328. NumberOfCols,
  329. WriteCoord,
  330. &NumberWritten
  331. )
  332. ) {
  333. return FALSE;
  334. }
  335. if (Text == NULL || (TextLength = strlen( Text )) == 0) {
  336. return TRUE;
  337. }
  338. else {
  339. return WriteConsoleOutputCharacter( OutputHandle,
  340. Text,
  341. TextLength,
  342. WriteCoord,
  343. &NumberWritten
  344. );
  345. }
  346. }
  347. int
  348. _CRTAPI1 main( argc, argv )
  349. int argc;
  350. char *argv[];
  351. {
  352. NTSTATUS Status;
  353. ULONG LastCount = 0;
  354. SYSTEM_BASIC_INFORMATION BasicInfo;
  355. SYSTEM_PERFORMANCE_INFORMATION PerfInfo;
  356. PSYSTEM_POOLTAG_INFORMATION PoolInfo;
  357. PSYSTEM_POOLTAG_INFORMATION PoolInfoOld;
  358. PUCHAR PreviousBuffer;
  359. PUCHAR CurrentBuffer;
  360. PUCHAR TempBuffer;
  361. BOOLEAN DoHelp;
  362. BOOLEAN DoQuit;
  363. int NumberOfPoolTags;
  364. int i;
  365. UCHAR LastKey;
  366. PPOOLMON_OUT Out;
  367. LONG ScrollDelta;
  368. WORD DisplayLine, LastDetailRow;
  369. CHAR OutputBuffer[ 512 ];
  370. DoHelp = FALSE;
  371. DoQuit = FALSE;
  372. Interactive = TRUE;
  373. ParseArgs( argc, argv );
  374. InputHandle = GetStdHandle( STD_INPUT_HANDLE );
  375. OriginalOutputHandle = GetStdHandle( STD_OUTPUT_HANDLE );
  376. if (Interactive) {
  377. if (InputHandle == NULL ||
  378. OriginalOutputHandle == NULL ||
  379. !GetConsoleMode( InputHandle, &OriginalInputMode )
  380. ) {
  381. Interactive = FALSE;
  382. } else {
  383. OutputHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
  384. FILE_SHARE_WRITE,
  385. NULL,
  386. CONSOLE_TEXTMODE_BUFFER,
  387. NULL
  388. );
  389. if (OutputHandle == NULL ||
  390. !GetConsoleScreenBufferInfo( OriginalOutputHandle, &OriginalConsoleInfo ) ||
  391. !SetConsoleScreenBufferSize( OutputHandle, OriginalConsoleInfo.dwSize ) ||
  392. !SetConsoleActiveScreenBuffer( OutputHandle ) ||
  393. !SetConsoleMode( InputHandle, 0 )
  394. ) {
  395. if (OutputHandle != NULL) {
  396. CloseHandle( OutputHandle );
  397. OutputHandle = NULL;
  398. }
  399. Interactive = FALSE;
  400. } else {
  401. NormalAttribute = 0x1F;
  402. HighlightAttribute = 0x71;
  403. NumberOfCols = OriginalConsoleInfo.dwSize.X;
  404. NumberOfRows = OriginalConsoleInfo.dwSize.Y;
  405. NumberOfDetailLines = NumberOfRows;
  406. }
  407. }
  408. }
  409. NtQuerySystemInformation( SystemBasicInformation,
  410. &BasicInfo,
  411. sizeof(BasicInfo),
  412. NULL
  413. );
  414. if (GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  415. SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  416. }
  417. PreviousBuffer = NULL;
  418. CurrentBuffer = LargeBuffer1;
  419. while(TRUE) {
  420. Status = NtQuerySystemInformation(
  421. SystemPerformanceInformation,
  422. &PerfInfo,
  423. sizeof(PerfInfo),
  424. NULL
  425. );
  426. if ( !NT_SUCCESS(Status) ) {
  427. printf("Query perf Failed %lx\n",Status);
  428. break;
  429. }
  430. Status = NtQuerySystemInformation(
  431. SystemPoolTagInformation,
  432. CurrentBuffer,
  433. BUFFER_SIZE,
  434. NULL
  435. );
  436. if ( !NT_SUCCESS(Status) ) {
  437. printf("Query pooltags Failed %lx\n",Status);
  438. break;
  439. }
  440. //
  441. // Calculate pool tags and display information.
  442. //
  443. //
  444. PoolInfo = (PSYSTEM_POOLTAG_INFORMATION)CurrentBuffer;
  445. i = PoolInfo->Count;
  446. PoolInfoOld = (PSYSTEM_POOLTAG_INFORMATION)PreviousBuffer;
  447. DisplayLine = 0;
  448. sprintf( OutputBuffer,
  449. " Memory:%8ldK Avail:%8ldK PageFlts:%6ld InRam Krnl:%5ldK P:%5ldK",
  450. BasicInfo.NumberOfPhysicalPages*(BasicInfo.PageSize/1024),
  451. PerfInfo.AvailablePages*(BasicInfo.PageSize/1024),
  452. PerfInfo.PageFaultCount - LastCount,
  453. (PerfInfo.ResidentSystemCodePage + PerfInfo.ResidentSystemDriverPage)*(BasicInfo.PageSize/1024),
  454. (PerfInfo.ResidentPagedPoolPage)*(BasicInfo.PageSize/1024)
  455. );
  456. WriteConsoleLine( OutputHandle,
  457. DisplayLine++,
  458. OutputBuffer,
  459. FALSE
  460. );
  461. LastCount = PerfInfo.PageFaultCount;
  462. sprintf( OutputBuffer,
  463. " Commit:%7ldK Limit:%7ldK Peak:%7ldK Pool N:%5ldK P:%5ldK",
  464. PerfInfo.CommittedPages*(BasicInfo.PageSize/1024),
  465. PerfInfo.CommitLimit*(BasicInfo.PageSize/1024),
  466. PerfInfo.PeakCommitment*(BasicInfo.PageSize/1024),
  467. PerfInfo.NonPagedPoolPages*(BasicInfo.PageSize/1024),
  468. PerfInfo.PagedPoolPages*(BasicInfo.PageSize/1024)
  469. );
  470. WriteConsoleLine( OutputHandle,
  471. DisplayLine++,
  472. OutputBuffer,
  473. FALSE
  474. );
  475. WriteConsoleLine( OutputHandle,
  476. DisplayLine++,
  477. " Tag Type Allocs Frees Diff Bytes Per Alloc",
  478. FALSE
  479. );
  480. WriteConsoleLine( OutputHandle,
  481. DisplayLine++,
  482. NULL,
  483. FALSE
  484. );
  485. Out = &OutBuffer[0];
  486. if (DisplayTotals) {
  487. RtlZeroMemory( Totals, sizeof(POOLMON_OUT)*2 );
  488. }
  489. for (i = 0; i < (int)PoolInfo->Count; i++) {
  490. if ( !CheckFilters(&PoolInfo->TagInfo[i]) ) {
  491. continue;
  492. }
  493. if ((PoolInfo->TagInfo[i].NonPagedAllocs != 0) &&
  494. (DisplayType != PAGED)) {
  495. Out->Allocs = PoolInfo->TagInfo[i].NonPagedAllocs;
  496. Out->Frees = PoolInfo->TagInfo[i].NonPagedFrees;
  497. Out->Used = PoolInfo->TagInfo[i].NonPagedUsed;
  498. Out->Allocs_Frees = PoolInfo->TagInfo[i].NonPagedAllocs -
  499. PoolInfo->TagInfo[i].NonPagedFrees;
  500. Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
  501. Out->Type = NONPAGED;
  502. Out->Changed = FALSE;
  503. Out->NullByte = '\0';
  504. if (PoolInfoOld != NULL &&
  505. PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
  506. ) {
  507. Out->AllocsDiff = PoolInfo->TagInfo[i].NonPagedAllocs - PoolInfoOld->TagInfo[i].NonPagedAllocs;
  508. Out->FreesDiff = PoolInfo->TagInfo[i].NonPagedFrees - PoolInfoOld->TagInfo[i].NonPagedFrees;
  509. Out->UsedDiff = PoolInfo->TagInfo[i].NonPagedUsed - PoolInfoOld->TagInfo[i].NonPagedUsed;
  510. if (Out->AllocsDiff != 0 ||
  511. Out->FreesDiff != 0 ||
  512. Out->UsedDiff != 0
  513. ) {
  514. Out->Changed = TRUE;
  515. }
  516. } else {
  517. Out->AllocsDiff = 0;
  518. Out->UsedDiff = 0;
  519. Out->FreesDiff = 0;
  520. }
  521. Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
  522. if (DisplayTotals) {
  523. Totals[NONPAGED].Allocs += Out->Allocs;
  524. Totals[NONPAGED].AllocsDiff += Out->AllocsDiff;
  525. Totals[NONPAGED].Frees += Out->Frees;
  526. Totals[NONPAGED].FreesDiff += Out->FreesDiff;
  527. Totals[NONPAGED].Allocs_Frees += Out->Allocs_Frees;
  528. Totals[NONPAGED].Used += Out->Used;
  529. Totals[NONPAGED].UsedDiff += Out->UsedDiff;
  530. }
  531. Out += 1;
  532. }
  533. if ((PoolInfo->TagInfo[i].PagedAllocs != 0) &&
  534. (DisplayType != NONPAGED)) {
  535. Out->Allocs = PoolInfo->TagInfo[i].PagedAllocs;
  536. Out->Frees = PoolInfo->TagInfo[i].PagedFrees;
  537. Out->Used = PoolInfo->TagInfo[i].PagedUsed;
  538. Out->Allocs_Frees = PoolInfo->TagInfo[i].PagedAllocs -
  539. PoolInfo->TagInfo[i].PagedFrees;
  540. Out->TagUlong = PoolInfo->TagInfo[i].TagUlong;
  541. Out->Type = PAGED;
  542. Out->Changed = FALSE;
  543. Out->NullByte = '\0';
  544. if (PoolInfoOld != NULL &&
  545. PoolInfoOld->TagInfo[i].TagUlong == PoolInfo->TagInfo[i].TagUlong
  546. ) {
  547. Out->AllocsDiff = PoolInfo->TagInfo[i].PagedAllocs - PoolInfoOld->TagInfo[i].PagedAllocs;
  548. Out->FreesDiff = PoolInfo->TagInfo[i].PagedFrees - PoolInfoOld->TagInfo[i].PagedFrees;
  549. Out->UsedDiff = PoolInfo->TagInfo[i].PagedUsed - PoolInfoOld->TagInfo[i].PagedUsed;
  550. if (Out->AllocsDiff != 0 ||
  551. Out->FreesDiff != 0 ||
  552. Out->UsedDiff != 0
  553. ) {
  554. Out->Changed = TRUE;
  555. }
  556. } else {
  557. Out->AllocsDiff = 0;
  558. Out->UsedDiff = 0;
  559. Out->FreesDiff = 0;
  560. }
  561. Out->Each = Out->Used / (Out->Allocs_Frees?Out->Allocs_Frees:1);
  562. if (DisplayTotals) {
  563. Totals[PAGED].Allocs += Out->Allocs;
  564. Totals[PAGED].AllocsDiff += Out->AllocsDiff;
  565. Totals[PAGED].Frees += Out->Frees;
  566. Totals[PAGED].FreesDiff += Out->FreesDiff;
  567. Totals[PAGED].Allocs_Frees += Out->Allocs_Frees;
  568. Totals[PAGED].Used += Out->Used;
  569. Totals[PAGED].UsedDiff += Out->UsedDiff;
  570. }
  571. Out += 1;
  572. }
  573. } //end for
  574. //
  575. // Sort the running working set buffer
  576. //
  577. NumberOfPoolTags = Out - &OutBuffer[0];
  578. qsort((void *)&OutBuffer,
  579. (size_t)NumberOfPoolTags,
  580. (size_t)sizeof(POOLMON_OUT),
  581. ulcomp);
  582. LastDetailRow = (WORD)(NumberOfRows - (DisplayTotals ? (DisplayType == BOTH ? 3 : 2) : 0));
  583. for (i = FirstDetailLine; i < NumberOfPoolTags; i++) {
  584. if (DisplayLine >= LastDetailRow) {
  585. break;
  586. }
  587. sprintf( OutputBuffer,
  588. " %4s %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld",
  589. OutBuffer[i].Tag,
  590. PoolType[OutBuffer[i].Type],
  591. OutBuffer[i].Allocs,
  592. OutBuffer[i].AllocsDiff,
  593. OutBuffer[i].Frees,
  594. OutBuffer[i].FreesDiff,
  595. OutBuffer[i].Allocs_Frees,
  596. OutBuffer[i].Used,
  597. OutBuffer[i].UsedDiff,
  598. OutBuffer[i].Each
  599. );
  600. WriteConsoleLine( OutputHandle,
  601. DisplayLine++,
  602. OutputBuffer,
  603. OutBuffer[i].Changed
  604. );
  605. OutBuffer[i].Changed = FALSE;
  606. }
  607. if (DisplayTotals) {
  608. WriteConsoleLine( OutputHandle,
  609. DisplayLine++,
  610. NULL,
  611. FALSE
  612. );
  613. for (i = 0; i < 2; i++) {
  614. if ( (int)DisplayType == i || DisplayType == BOTH ) {
  615. sprintf( OutputBuffer,
  616. "Total %5s %9ld (%4ld) %9ld (%4ld) %8ld %7ld (%6ld) %6ld",
  617. PoolType[i],
  618. Totals[i].Allocs,
  619. Totals[i].AllocsDiff,
  620. Totals[i].Frees,
  621. Totals[i].FreesDiff,
  622. Totals[i].Allocs_Frees,
  623. Totals[i].Used,
  624. Totals[i].UsedDiff,
  625. Totals[i].Each
  626. );
  627. WriteConsoleLine( OutputHandle,
  628. DisplayLine++,
  629. OutputBuffer,
  630. FALSE
  631. );
  632. }
  633. }
  634. }
  635. if (PreviousBuffer == NULL) {
  636. PreviousBuffer = LargeBuffer2;
  637. }
  638. TempBuffer = PreviousBuffer;
  639. PreviousBuffer = CurrentBuffer;
  640. CurrentBuffer = TempBuffer;
  641. while (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0) {
  642. //
  643. // Check for input record
  644. //
  645. if (ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
  646. InputRecord.EventType == KEY_EVENT &&
  647. InputRecord.Event.KeyEvent.bKeyDown
  648. ) {
  649. LastKey = InputRecord.Event.KeyEvent.uChar.AsciiChar;
  650. if (LastKey < ' ') {
  651. ScrollDelta = 0;
  652. if (LastKey == 'C'-'A'+1) {
  653. DoQuit = TRUE;
  654. } else switch (InputRecord.Event.KeyEvent.wVirtualKeyCode) {
  655. case VK_ESCAPE:
  656. DoQuit = TRUE;
  657. break;
  658. case VK_PRIOR:
  659. ScrollDelta = -(LONG)(InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines);
  660. break;
  661. case VK_NEXT:
  662. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount * NumberOfDetailLines;
  663. break;
  664. case VK_UP:
  665. ScrollDelta = -InputRecord.Event.KeyEvent.wRepeatCount;
  666. break;
  667. case VK_DOWN:
  668. ScrollDelta = InputRecord.Event.KeyEvent.wRepeatCount;
  669. break;
  670. case VK_HOME:
  671. FirstDetailLine = 0;
  672. break;
  673. case VK_END:
  674. FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
  675. break;
  676. }
  677. if (ScrollDelta != 0) {
  678. if (ScrollDelta < 0) {
  679. if (FirstDetailLine <= (ULONG)-ScrollDelta) {
  680. FirstDetailLine = 0;
  681. } else {
  682. FirstDetailLine += ScrollDelta;
  683. }
  684. } else {
  685. FirstDetailLine += ScrollDelta;
  686. if (FirstDetailLine >= (NumberOfPoolTags - NumberOfDetailLines)) {
  687. FirstDetailLine = NumberOfPoolTags - NumberOfDetailLines;
  688. }
  689. }
  690. }
  691. } else {
  692. switch (toupper( LastKey )) {
  693. case 'Q':
  694. //
  695. // Go to the bottom of the current screen when
  696. // we quit.
  697. //
  698. DoQuit = TRUE;
  699. break;
  700. case 'T':
  701. SortBy = TAG;
  702. FirstDetailLine = 0;
  703. break;
  704. case 'A':
  705. SortBy = ALLOC;
  706. FirstDetailLine = 0;
  707. break;
  708. case 'U':
  709. case 'B':
  710. SortBy = BYTES;
  711. FirstDetailLine = 0;
  712. break;
  713. case 'F':
  714. SortBy = FREE;
  715. FirstDetailLine = 0;
  716. break;
  717. case 'D':
  718. SortBy = DIFF;
  719. FirstDetailLine = 0;
  720. break;
  721. case 'M':
  722. SortBy = EACH;
  723. FirstDetailLine = 0;
  724. break;
  725. case 'L':
  726. NoHighlight = 1 - NoHighlight;
  727. break;
  728. case 'P':
  729. DisplayType += 1;
  730. if (DisplayType > BOTH) {
  731. DisplayType = NONPAGED;
  732. }
  733. FirstDetailLine = 0;
  734. break;
  735. case 'X':
  736. case '(':
  737. case ')':
  738. Paren += 1;
  739. break;
  740. case 'E':
  741. DisplayTotals = !DisplayTotals;
  742. FirstDetailLine = 0;
  743. break;
  744. case 'H':
  745. case '?':
  746. DoHelp = TRUE;
  747. break;
  748. }
  749. }
  750. break;
  751. }
  752. }
  753. if (DoQuit) {
  754. break;
  755. }
  756. if (DoHelp) {
  757. DoHelp = FALSE;
  758. ShowHelpPopup();
  759. }
  760. }
  761. if (Interactive) {
  762. SetConsoleActiveScreenBuffer( OriginalOutputHandle );
  763. SetConsoleMode( InputHandle, OriginalInputMode );
  764. CloseHandle( OutputHandle );
  765. }
  766. ExitProcess( 0 );
  767. return 0;
  768. }
  769. VOID
  770. ShowHelpPopup( VOID )
  771. {
  772. HANDLE PopupHandle;
  773. WORD n;
  774. PopupHandle = CreateConsoleScreenBuffer( GENERIC_READ | GENERIC_WRITE,
  775. FILE_SHARE_WRITE,
  776. NULL,
  777. CONSOLE_TEXTMODE_BUFFER,
  778. NULL
  779. );
  780. if (PopupHandle == NULL) {
  781. return;
  782. }
  783. SetConsoleActiveScreenBuffer( PopupHandle );
  784. n = 0;
  785. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  786. WriteConsoleLine( PopupHandle, n++, " Poolmon Help", FALSE );
  787. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  788. WriteConsoleLine( PopupHandle, n++, " columns:", FALSE );
  789. WriteConsoleLine( PopupHandle, n++, " Tag is the 4 byte tag given to the pool allocation", FALSE );
  790. WriteConsoleLine( PopupHandle, n++, " Type is paged or nonp(aged)", FALSE );
  791. WriteConsoleLine( PopupHandle, n++, " Allocs is count of all alloctions", FALSE );
  792. WriteConsoleLine( PopupHandle, n++, " ( ) is difference in Allocs column from last update", FALSE );
  793. WriteConsoleLine( PopupHandle, n++, " Frees is count of all frees", FALSE );
  794. WriteConsoleLine( PopupHandle, n++, " ( ) difference in Frees column from last update", FALSE );
  795. WriteConsoleLine( PopupHandle, n++, " Diff is (Allocs - Frees)", FALSE );
  796. WriteConsoleLine( PopupHandle, n++, " Bytes is the total bytes consumed in pool", FALSE );
  797. WriteConsoleLine( PopupHandle, n++, " ( ) difference in Bytes column from last update", FALSE );
  798. WriteConsoleLine( PopupHandle, n++, " Per Alloc is (Bytes / Diff)", FALSE );
  799. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  800. WriteConsoleLine( PopupHandle, n++, " switches: ", FALSE );
  801. WriteConsoleLine( PopupHandle, n++, " ? or h - gives this help", FALSE );
  802. WriteConsoleLine( PopupHandle, n++, " q - quits", FALSE );
  803. WriteConsoleLine( PopupHandle, n++, " p - toggles default pool display between both, paged, and nonpaged", FALSE );
  804. WriteConsoleLine( PopupHandle, n++, " e - toggles totals lines on and off", FALSE );
  805. WriteConsoleLine( PopupHandle, n++, " l - toggles highlighting of changed lines on and off", FALSE );
  806. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  807. WriteConsoleLine( PopupHandle, n++, " sorting switches:", FALSE );
  808. WriteConsoleLine( PopupHandle, n++, " t - tag a - allocations", FALSE );
  809. WriteConsoleLine( PopupHandle, n++, " f - frees d - difference", FALSE );
  810. WriteConsoleLine( PopupHandle, n++, " b - bytes m - per alloc", FALSE );
  811. WriteConsoleLine( PopupHandle, n++, " (u is the same as b)", FALSE );
  812. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  813. WriteConsoleLine( PopupHandle, n++, " ) - toggles sort between primary tag and value in ( )", FALSE );
  814. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  815. WriteConsoleLine( PopupHandle, n++, " command line switches", FALSE );
  816. WriteConsoleLine( PopupHandle, n++, " -i<tag> - list only matching tags", FALSE );
  817. WriteConsoleLine( PopupHandle, n++, " -x<tag> - list everything except matching tags", FALSE );
  818. WriteConsoleLine( PopupHandle, n++, " <tag> can include * and ?", FALSE );
  819. WriteConsoleLine( PopupHandle, n++, " -peltafdbum) - as listed above", FALSE );
  820. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  821. WriteConsoleLine( PopupHandle, n++, NULL, FALSE );
  822. while (TRUE) {
  823. if (WaitForSingleObject( InputHandle, DelayTimeMsec ) == STATUS_WAIT_0 &&
  824. ReadConsoleInput( InputHandle, &InputRecord, 1, &NumberOfInputRecords ) &&
  825. InputRecord.EventType == KEY_EVENT &&
  826. InputRecord.Event.KeyEvent.bKeyDown &&
  827. InputRecord.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE
  828. ) {
  829. break;
  830. }
  831. }
  832. SetConsoleActiveScreenBuffer( OutputHandle );
  833. CloseHandle( PopupHandle );
  834. return;
  835. }