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.

243 lines
6.0 KiB

  1. // memsnap.c
  2. //
  3. // this simple program takes a snapshot of all the process
  4. // and their memory usage and append it to the logfile (arg)
  5. // pmon was model for this
  6. //
  7. // includes
  8. #include <nt.h>
  9. #include <ntrtl.h>
  10. #include <nturtl.h>
  11. #include <windows.h>
  12. #include <assert.h>
  13. #include <stdlib.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <io.h>
  18. #include <srvfsctl.h>
  19. // declarations
  20. #define INIT_BUFFER_SIZE 4*1024
  21. #include "tags.c"
  22. VOID Usage(VOID)
  23. {
  24. printf( "memsnap [-t] [-g] [-?] [<logfile>]\n" );
  25. printf( "memsnap logs system memory usage to <logfile>\n" );
  26. printf( "<logfile> = memsnap.log by default\n" );
  27. printf( "-t Add tagging information (time (GMT), date, machinename)\n" );
  28. printf( "-g Add GDI and USER resource counts\n");
  29. printf( "-? Gets this message\n" );
  30. exit(-1);
  31. }
  32. void _cdecl main(int argc, char* argv[])
  33. {
  34. FILE* LogFile; // log file handle
  35. BOOL bTags= FALSE; // true if we are to output tags
  36. BOOL bGuiCount= FALSE; // true if we are to output GUI counters
  37. PCHAR pszFileName; // name of file to log to
  38. INT iArg;
  39. ULONG Offset1;
  40. PUCHAR CurrentBuffer=NULL;
  41. ULONG CurrentSize;
  42. NTSTATUS Status=STATUS_SUCCESS;
  43. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  44. //
  45. // Get higher priority in case this is a bogged down machine
  46. //
  47. if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  48. SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  49. }
  50. //
  51. // Scan off the command line options
  52. //
  53. pszFileName= &"memsnap.log"; // this is the default log file if none is given
  54. for( iArg=1; iArg < argc; iArg++ ) {
  55. if( (*argv[iArg] == '-' ) || (*argv[iArg] == '/') ) {
  56. switch( *(argv[iArg]+1) ) {
  57. //
  58. // -t -- Add tags
  59. //
  60. case 't':
  61. case 'T':
  62. bTags= TRUE;
  63. break;
  64. //
  65. // -g -- Add GUI counters like User and Gdi handles
  66. //
  67. case 'g':
  68. case 'G':
  69. bGuiCount= TRUE;
  70. break;
  71. default:
  72. printf("invalid switch: %s\n",argv[iArg]);
  73. Usage();
  74. }
  75. }
  76. else { // must be the log filename
  77. pszFileName= argv[iArg];
  78. }
  79. }
  80. //
  81. // Open the output file
  82. //
  83. LogFile= fopen( pszFileName, "a" );
  84. if( LogFile == NULL ) {
  85. printf("Error opening file %s\n",pszFileName);
  86. exit(-1);
  87. }
  88. //
  89. // print file header once
  90. //
  91. if (_filelength(_fileno(LogFile)) == 0 ) {
  92. fprintf(LogFile,"Process ID Proc.Name Wrkng.Set PagedPool NonPgdPl Pagefile Commit Handles Threads" );
  93. if( bGuiCount ) {
  94. fprintf( LogFile, " User Gdi");
  95. }
  96. }
  97. fprintf( LogFile, "\n" );
  98. if( bTags ) {
  99. OutputStdTags(LogFile,"memsnap");
  100. }
  101. //
  102. // grab all process information
  103. // log line format:
  104. // pid,name,WorkingSetSize,QuotaPagedPoolUsage,QuotaNonPagedPoolUsage,PagefileUsage,CommitCharge,User,Gdi
  105. //
  106. //
  107. // Keep trying larger buffers until we get all the information
  108. //
  109. CurrentSize=INIT_BUFFER_SIZE;
  110. for(;;) {
  111. CurrentBuffer= LocalAlloc( LPTR, CurrentSize );
  112. if( NULL == CurrentBuffer ) {
  113. printf("Out of memory\n");
  114. exit(-1);
  115. }
  116. Status= NtQuerySystemInformation(
  117. SystemProcessInformation,
  118. CurrentBuffer,
  119. CurrentSize,
  120. NULL
  121. );
  122. if( Status != STATUS_INFO_LENGTH_MISMATCH ) break;
  123. LocalFree( CurrentBuffer );
  124. CurrentSize= CurrentSize * 2;
  125. };
  126. if( Status == STATUS_SUCCESS ) {
  127. Offset1= 0;
  128. do {
  129. //
  130. // get process info from buffer
  131. //
  132. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&CurrentBuffer[Offset1];
  133. Offset1 += ProcessInfo->NextEntryOffset;
  134. //
  135. // print in file
  136. //
  137. fprintf(LogFile,
  138. "%8p%20ws%10u%10u%10u%10u%10u%10u%10u",
  139. ProcessInfo->UniqueProcessId,
  140. ProcessInfo->ImageName.Buffer,
  141. ProcessInfo->WorkingSetSize,
  142. ProcessInfo->QuotaPagedPoolUsage,
  143. ProcessInfo->QuotaNonPagedPoolUsage,
  144. ProcessInfo->PagefileUsage,
  145. ProcessInfo->PrivatePageCount,
  146. ProcessInfo->HandleCount,
  147. ProcessInfo->NumberOfThreads
  148. );
  149. //
  150. // put optional GDI and USER counts at the end
  151. // If we can't open the process to get the information, report zeros
  152. //
  153. if( bGuiCount ) {
  154. DWORD dwGdi, dwUser; // Count of GDI and USER handles
  155. HANDLE hProcess; // process handle
  156. dwGdi= dwUser= 0;
  157. hProcess= OpenProcess( PROCESS_QUERY_INFORMATION,
  158. FALSE,
  159. PtrToUlong(ProcessInfo->UniqueProcessId) );
  160. if( hProcess ) {
  161. dwGdi= GetGuiResources( hProcess, GR_GDIOBJECTS );
  162. dwUser= GetGuiResources( hProcess, GR_USEROBJECTS );
  163. CloseHandle( hProcess );
  164. }
  165. fprintf(LogFile, "%10u%10u", dwUser, dwGdi );
  166. }
  167. fprintf(LogFile, "\n" );
  168. } while( ProcessInfo->NextEntryOffset != 0 );
  169. }
  170. else {
  171. fprintf(LogFile, "NtQuerySystemInformation call failed! NtStatus= %08x\n",Status);
  172. exit(-1);
  173. }
  174. //
  175. // free buffer
  176. //
  177. LocalFree(CurrentBuffer);
  178. //
  179. // close file
  180. //
  181. fclose(LogFile);
  182. exit(0);
  183. }