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.

1125 lines
34 KiB

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