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.

977 lines
30 KiB

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