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.

393 lines
9.4 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 <tchar.h>
  17. #include <ctype.h>
  18. #include <common.ver>
  19. #include <io.h>
  20. #include <srvfsctl.h>
  21. #define SORTLOG_INCLUDED
  22. #define ANALOG_INCLUDED
  23. #include "analog.c"
  24. #include "sortlog.c"
  25. // declarations
  26. #define INIT_BUFFER_SIZE 4*1024
  27. #include "tags.c"
  28. LPTSTR HelpText =
  29. TEXT("memsnap - System and pool snapshots. (") BUILD_MACHINE_TAG TEXT(")\n")
  30. VER_LEGALCOPYRIGHT_STR TEXT("\n\n")
  31. TEXT("memsnap -m LOGFILE Snapshot process information. \n")
  32. TEXT("memsnap -p LOGFILE Snapshot kernel pool information. \n")
  33. TEXT("memsnap -a LOGFILE Analyze a log for leaks. \n")
  34. TEXT("memsnap -ah LOGFILE Same as `-a' but generate HTML tables. \n")
  35. TEXT(" \n")
  36. TEXT("The `-a' option will analyze the log file containing several \n")
  37. TEXT("snapshots of same type (process or pool information) and will \n")
  38. TEXT("print resources for which there is an increase everytime \n")
  39. TEXT("a snapshot was taken. \n")
  40. TEXT(" \n");
  41. VOID Usage(VOID)
  42. {
  43. fputs (HelpText, stdout);
  44. exit(-1);
  45. }
  46. VOID
  47. AnalyzeLog (
  48. PCHAR FileName,
  49. BOOL HtmlOutput
  50. )
  51. {
  52. char * Args[8];
  53. ULONG Index;
  54. CHAR TempFileName [ MAX_PATH];
  55. UINT TempNumber;
  56. TempNumber = GetTempFileName (".",
  57. "snp",
  58. 0,
  59. TempFileName);
  60. if (TempNumber == 0) {
  61. strcpy (TempFileName, "_memsnap_temp_");
  62. }
  63. //printf ("Temporary file: %s \n", TempFileName);
  64. //
  65. // sortlog
  66. //
  67. Index = 0;
  68. Args[Index++] = "memsnap.exe";
  69. Args[Index++] = FileName;
  70. Args[Index++] = TempFileName;
  71. Args[Index++] = NULL;
  72. SortlogMain (3, Args);
  73. //
  74. // analog
  75. //
  76. Index = 0;
  77. Args[Index++] = "memsnap.exe";
  78. Args[Index++] = "-d";
  79. if (HtmlOutput) {
  80. Args[Index++] = "-h";
  81. }
  82. Args[Index++] = TempFileName;
  83. Args[Index++] = NULL;
  84. if (HtmlOutput) {
  85. AnalogMain (4, Args);
  86. }
  87. else {
  88. AnalogMain (3, Args);
  89. }
  90. DeleteFile (TempFileName);
  91. }
  92. #define POOLSNAP_INCLUDED
  93. #include "poolsnap.c"
  94. VOID
  95. PoolSnap (
  96. PCHAR FileName
  97. )
  98. {
  99. char * Args[8];
  100. ULONG Index;
  101. Index = 0;
  102. Args[Index++] = "memsnap.exe";
  103. Args[Index++] = "-t";
  104. Args[Index++] = FileName;
  105. Args[Index++] = NULL;
  106. PoolsnapMain (Index - 1, Args);
  107. }
  108. VOID
  109. MemorySnap (
  110. PCHAR FileName
  111. )
  112. {
  113. FILE* LogFile; // log file handle
  114. PCHAR pszFileName; // name of file to log to
  115. INT iArg;
  116. ULONG Offset1;
  117. PUCHAR SnapBuffer = NULL;
  118. ULONG CurrentSize;
  119. NTSTATUS Status=STATUS_SUCCESS;
  120. PSYSTEM_PROCESS_INFORMATION ProcessInfo;
  121. pszFileName= FileName;
  122. //
  123. // Open the output file
  124. //
  125. LogFile= fopen( pszFileName, "a" );
  126. if( LogFile == NULL ) {
  127. printf("Error opening file %s\n",pszFileName);
  128. exit(-1);
  129. }
  130. //
  131. // print file header once
  132. //
  133. if (_filelength(_fileno(LogFile)) == 0 ) {
  134. fprintf(LogFile,"Process ID Proc.Name Wrkng.Set PagedPool NonPgdPl Pagefile Commit Handles Threads" );
  135. fprintf( LogFile, " User Gdi");
  136. }
  137. fprintf( LogFile, "\n" );
  138. OutputStdTags(LogFile,"memsnap");
  139. //
  140. // grab all process information
  141. // log line format:
  142. // pid,name,WorkingSetSize,QuotaPagedPoolUsage,QuotaNonPagedPoolUsage,PagefileUsage,CommitCharge,User,Gdi
  143. //
  144. //
  145. // Keep trying larger buffers until we get all the information
  146. //
  147. CurrentSize=INIT_BUFFER_SIZE;
  148. for(;;) {
  149. SnapBuffer= LocalAlloc( LPTR, CurrentSize );
  150. if( NULL == SnapBuffer ) {
  151. printf("Out of memory\n");
  152. exit(-1);
  153. }
  154. Status= NtQuerySystemInformation(
  155. SystemProcessInformation,
  156. SnapBuffer,
  157. CurrentSize,
  158. NULL
  159. );
  160. if( Status != STATUS_INFO_LENGTH_MISMATCH ) break;
  161. LocalFree( SnapBuffer );
  162. CurrentSize= CurrentSize * 2;
  163. };
  164. if( Status == STATUS_SUCCESS ) {
  165. Offset1= 0;
  166. do {
  167. //
  168. // get process info from buffer
  169. //
  170. ProcessInfo = (PSYSTEM_PROCESS_INFORMATION)&SnapBuffer[Offset1];
  171. Offset1 += ProcessInfo->NextEntryOffset;
  172. //
  173. // print in file
  174. //
  175. fprintf(LogFile,
  176. "%8p%20ws%10u%10u%10u%10u%10u%10u%10u",
  177. ProcessInfo->UniqueProcessId,
  178. ProcessInfo->ImageName.Buffer,
  179. ProcessInfo->WorkingSetSize,
  180. ProcessInfo->QuotaPagedPoolUsage,
  181. ProcessInfo->QuotaNonPagedPoolUsage,
  182. ProcessInfo->PagefileUsage,
  183. ProcessInfo->PrivatePageCount,
  184. ProcessInfo->HandleCount,
  185. ProcessInfo->NumberOfThreads
  186. );
  187. //
  188. // put optional GDI and USER counts at the end
  189. // If we can't open the process to get the information, report zeros
  190. //
  191. {
  192. DWORD dwGdi, dwUser; // Count of GDI and USER handles
  193. HANDLE hProcess; // process handle
  194. dwGdi= dwUser= 0;
  195. hProcess= OpenProcess( PROCESS_QUERY_INFORMATION,
  196. FALSE,
  197. PtrToUlong(ProcessInfo->UniqueProcessId) );
  198. if( hProcess ) {
  199. dwGdi= GetGuiResources( hProcess, GR_GDIOBJECTS );
  200. dwUser= GetGuiResources( hProcess, GR_USEROBJECTS );
  201. CloseHandle( hProcess );
  202. }
  203. fprintf(LogFile, "%10u%10u", dwUser, dwGdi );
  204. }
  205. fprintf(LogFile, "\n" );
  206. } while( ProcessInfo->NextEntryOffset != 0 );
  207. }
  208. else {
  209. fprintf(LogFile, "NtQuerySystemInformation call failed! NtStatus= %08x\n",Status);
  210. exit(-1);
  211. }
  212. //
  213. // free buffer
  214. //
  215. LocalFree(SnapBuffer);
  216. //
  217. // close file
  218. //
  219. fclose(LogFile);
  220. }
  221. void _cdecl
  222. main (
  223. int argc,
  224. char* argv[]
  225. )
  226. {
  227. int Index;
  228. BOOL NewSyntax = FALSE;
  229. PCHAR LogName = NULL;
  230. //
  231. // Get higher priority in case this is a bogged down machine
  232. //
  233. if ( GetPriorityClass(GetCurrentProcess()) == NORMAL_PRIORITY_CLASS) {
  234. SetPriorityClass(GetCurrentProcess(),HIGH_PRIORITY_CLASS);
  235. }
  236. //
  237. // Check out old command line.
  238. //
  239. for (Index = 1; Index < argc; Index += 1) {
  240. //
  241. // Ignore old options.
  242. //
  243. if (_stricmp (argv[Index], "/g") == 0 || _stricmp (argv[Index], "-g") == 0) {
  244. continue;
  245. }
  246. if (_stricmp (argv[Index], "/t") == 0 || _stricmp (argv[Index], "-t") == 0) {
  247. continue;
  248. }
  249. //
  250. // Go to new command line parsing if new options used.
  251. //
  252. if (_stricmp (argv[Index], "/m") == 0 || _stricmp (argv[Index], "-m") == 0) {
  253. NewSyntax = TRUE;
  254. break;
  255. }
  256. if (_stricmp (argv[Index], "/p") == 0 || _stricmp (argv[Index], "-p") == 0) {
  257. NewSyntax = TRUE;
  258. break;
  259. }
  260. if (_stricmp (argv[Index], "/a") == 0 || _stricmp (argv[Index], "-a") == 0) {
  261. NewSyntax = TRUE;
  262. break;
  263. }
  264. if (_stricmp (argv[Index], "/ah") == 0 || _stricmp (argv[Index], "-ah") == 0) {
  265. NewSyntax = TRUE;
  266. break;
  267. }
  268. if (_stricmp (argv[Index], "/?") == 0 || _stricmp (argv[Index], "-?") == 0) {
  269. NewSyntax = TRUE;
  270. break;
  271. }
  272. //
  273. // This must be a log name therefore we will od a memory snap.
  274. //
  275. LogName = argv[Index];
  276. break;
  277. }
  278. if (NewSyntax == FALSE) {
  279. MemorySnap (LogName ? LogName : "memsnap.log");
  280. exit (0);
  281. }
  282. //
  283. // Parse command line.
  284. //
  285. if (argc != 3) {
  286. Usage ();
  287. }
  288. else if (_stricmp (argv[1], "/p") == 0 || _stricmp (argv[1], "-p") == 0) {
  289. PoolSnap (argv[2]);
  290. }
  291. else if (_stricmp (argv[1], "/m") == 0 || _stricmp (argv[1], "-m") == 0) {
  292. MemorySnap (argv[2]);
  293. }
  294. else if (_stricmp (argv[1], "/a") == 0 || _stricmp (argv[1], "-a") == 0) {
  295. AnalyzeLog (argv[2], FALSE);
  296. }
  297. else if (_stricmp (argv[1], "/ah") == 0 || _stricmp (argv[1], "-ah") == 0) {
  298. AnalyzeLog (argv[2], TRUE);
  299. }
  300. else {
  301. Usage ();
  302. }
  303. exit(0);
  304. }