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.

404 lines
9.7 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. memfilt.cpp
  5. Abstract:
  6. This module filters out the useful information from a sorted memsnap output file.
  7. Author:
  8. Matt Bandy (t-mattba) 27-Jul-1998
  9. Revision History:
  10. 27-Jul-1998 t-mattba
  11. Modified module to conform to coding standards.
  12. --*/
  13. #include <nt.h>
  14. #include <tchar.h>
  15. #include <stdio.h>
  16. #include <string.h>
  17. #include <stdlib.h>
  18. #define MF_NEW_PROCESS 0
  19. #define MF_UPDATE 1
  20. // globals
  21. LONG MinimumCommitChangeToReport = 1;
  22. LONG MinimumHandleChangeToReport = 1;
  23. BOOLEAN ReportIncreasesOnly = TRUE;
  24. VOID
  25. PrintUsage(
  26. )
  27. /*++
  28. Routine Description:
  29. This routine prints an informational message about the proper usage of MEMFILT.
  30. Arguments:
  31. None.
  32. Return value:
  33. None.
  34. --*/
  35. {
  36. _ftprintf(stderr, _T("Summarizes possible leaks in a sorted MEMSNAP output file.\n\n"));
  37. _ftprintf(stderr, _T("MEMFILT file [/MINCOMMIT:n] [/MINHANDLES:n] [/ALL]\n\n"));
  38. _ftprintf(stderr, _T("file A sorted memsnap output file.\n"));
  39. _ftprintf(stderr, _T("/MINCOMMIT:n Reports only processes where commit charge increased by\n"));
  40. _ftprintf(stderr, _T(" at least n.\n"));
  41. _ftprintf(stderr, _T("/MINHANDLES:n Reports only processes where handle count increased by\n"));
  42. _ftprintf(stderr, _T(" at least n.\n"));
  43. _ftprintf(stderr, _T("/ALL Reports decreases as well as increases.\n"));
  44. }
  45. VOID
  46. PrintProcessInformation(
  47. IN BOOLEAN CommitAlwaysGrows,
  48. IN BOOLEAN HandlesAlwaysGrow,
  49. IN LPTSTR ProcessName,
  50. IN LONG InitialCommit,
  51. IN LONG FinalCommit,
  52. IN LONG InitialHandles,
  53. IN LONG FinalHandles
  54. )
  55. /*++
  56. Routine Description:
  57. This routine reports the memory usage of a single process.
  58. Arguments:
  59. CommitAlwaysGrows - TRUE if commit monotonically increases.
  60. HandlesAlwaysGrow - TRUE if handles monotonically increase.
  61. ProcessName - the name of the process being reported.
  62. InitialCommit - initial commit charge for this process.
  63. FinalCommit - final commit charge for this process.
  64. InitialHandles - initial handle count for this process.
  65. FinalHandles - final handle count for this process.
  66. Return value:
  67. None.
  68. --*/
  69. {
  70. _TCHAR CommitString[64];
  71. _TCHAR HandlesString[64];
  72. if(((!ReportIncreasesOnly) &&
  73. (abs(FinalCommit - InitialCommit) >=
  74. MinimumCommitChangeToReport)) ||
  75. (FinalCommit - InitialCommit >=
  76. MinimumCommitChangeToReport)) {
  77. _stprintf(CommitString, _T("%10d->%10d"), InitialCommit, FinalCommit);
  78. } else {
  79. _tcscpy(CommitString, _T(" "));
  80. }
  81. if(((!ReportIncreasesOnly) &&
  82. (abs(FinalHandles - InitialHandles) >=
  83. MinimumHandleChangeToReport)) ||
  84. (FinalHandles - InitialHandles >=
  85. MinimumHandleChangeToReport)) {
  86. _stprintf(HandlesString, _T("%10d->%10d"), InitialHandles, FinalHandles);
  87. } else {
  88. _tcscpy(HandlesString, _T(" "));
  89. }
  90. _tprintf(_T("%c%c %s %s %s\n"),
  91. (CommitAlwaysGrows && (FinalCommit != InitialCommit) ? _T('!') : _T(' ')),
  92. (HandlesAlwaysGrow && (FinalHandles != InitialHandles) ? _T('!') : _T(' ')),
  93. ProcessName, CommitString, HandlesString);
  94. }
  95. LONG _cdecl
  96. _tmain(
  97. IN LONG argc,
  98. IN LPTSTR argv[]
  99. )
  100. /*++
  101. Routine Description:
  102. This routine parses program arguments, reads the input file, and outputs the result.
  103. Arguments:
  104. argc - Number of command line arguments.
  105. argv - Command line arguments.
  106. Return value:
  107. 0 if filtering is successful, 1 otherwise.
  108. --*/
  109. {
  110. try {
  111. FILE *InputFile = NULL;
  112. _TCHAR LineBuffer[256];
  113. _TCHAR ProcessName[64];
  114. LONG CurrentState = MF_NEW_PROCESS;
  115. LONG InitialCommit = 0;
  116. LONG FinalCommit = 0;
  117. LONG NewCommit = 0;
  118. LONG InitialHandles = 0;
  119. LONG FinalHandles = 0;
  120. LONG NewHandles = 0;
  121. LONG MonotonicallyIncreasing = 0;
  122. BOOLEAN CommitAlwaysGrows = TRUE;
  123. BOOLEAN HandlesAlwaysGrow = TRUE;
  124. BOOLEAN InterpretedArgument = FALSE;
  125. LONG Processes = 0;
  126. LPTSTR InputFileName = NULL;
  127. // make sure ProcessName is properly terminated
  128. ProcessName[30]=_T('\0');
  129. // parse command line arguments
  130. if(argc < 2) {
  131. PrintUsage();
  132. return 1;
  133. }
  134. for(LONG n=1; n<argc; n++) {
  135. InterpretedArgument = FALSE;
  136. switch(argv[n][0]) {
  137. case _T('-'):
  138. case _T('/'):
  139. // it's a switch
  140. if(!_tcsicmp(argv[n]+1, _T("all"))) {
  141. ReportIncreasesOnly = FALSE;
  142. InterpretedArgument = TRUE;
  143. }
  144. if(!_tcsnicmp(argv[n]+1, _T("mincommit:"), 10)) {
  145. MinimumCommitChangeToReport = _ttoi(argv[n]+10);
  146. InterpretedArgument = TRUE;
  147. }
  148. if(!_tcsnicmp(argv[n]+1, _T("minhandles:"), 11)) {
  149. MinimumHandleChangeToReport = _ttoi(argv[n]+11);
  150. InterpretedArgument = TRUE;
  151. }
  152. break;
  153. default:
  154. if(InputFileName != NULL) {
  155. // too many filenames
  156. PrintUsage();
  157. return 1;
  158. }
  159. InputFileName = argv[n];
  160. InterpretedArgument = TRUE;
  161. break;
  162. }
  163. if(!InterpretedArgument) {
  164. PrintUsage();
  165. return 1;
  166. }
  167. }
  168. if(InputFileName == NULL) {
  169. // filename not specified
  170. PrintUsage();
  171. return 1;
  172. }
  173. InputFile = _tfopen(InputFileName, _T("rt"));
  174. if(InputFile == NULL) {
  175. _ftprintf(stderr, _T("Cannot open input file.\n"));
  176. return 1;
  177. }
  178. // skip header
  179. if (!_fgetts(LineBuffer, 256, InputFile)) {
  180. _ftprintf(stderr, _T("Cannot read input file.\n"));
  181. return 1;
  182. }
  183. if (!_fgetts(LineBuffer, 256, InputFile)) {
  184. _ftprintf(stderr, _T("Cannot read input file.\n"));
  185. return 1;
  186. }
  187. while(!feof(InputFile)) {
  188. if(!_tcscmp(LineBuffer,_T("\n"))) {
  189. // blank line indicates a new process
  190. CurrentState = MF_NEW_PROCESS;
  191. // does the most recent process meet the criteria to be reported?
  192. if(ReportIncreasesOnly) {
  193. if(((FinalCommit - InitialCommit) >= MinimumCommitChangeToReport) ||
  194. ((FinalHandles - InitialHandles) >= MinimumHandleChangeToReport)) {
  195. PrintProcessInformation(CommitAlwaysGrows, HandlesAlwaysGrow,
  196. ProcessName, InitialCommit, FinalCommit, InitialHandles,
  197. FinalHandles);
  198. }
  199. } else {
  200. if((abs(FinalCommit - InitialCommit) >= MinimumCommitChangeToReport) ||
  201. (abs(FinalHandles - InitialHandles) >= MinimumHandleChangeToReport)) {
  202. PrintProcessInformation(CommitAlwaysGrows, HandlesAlwaysGrow,
  203. ProcessName, InitialCommit, FinalCommit, InitialHandles,
  204. FinalHandles);
  205. }
  206. }
  207. } else {
  208. if(_tcslen(LineBuffer) <= 80) {
  209. _ftprintf(stderr, _T("Format violated.\n"));
  210. return 1;
  211. }
  212. switch(CurrentState) {
  213. case MF_NEW_PROCESS:
  214. _tcsncpy(ProcessName, LineBuffer, 30);
  215. if (_stscanf(LineBuffer+70, _T("%d"), &InitialCommit) != 1) break;
  216. if (_stscanf(LineBuffer+80, _T("%d"), &InitialHandles) != 1) break;
  217. FinalCommit = 0;
  218. FinalHandles = 0;
  219. CommitAlwaysGrows = TRUE;
  220. HandlesAlwaysGrow = TRUE;
  221. CurrentState = MF_UPDATE;
  222. break;
  223. case MF_UPDATE:
  224. if (_stscanf(LineBuffer+70, _T("%d"), &NewCommit) != 1) break;
  225. if (_stscanf(LineBuffer+80, _T("%d"), &NewHandles) != 1) break;
  226. if(NewCommit < FinalCommit) {
  227. CommitAlwaysGrows = FALSE;
  228. }
  229. if(NewHandles < FinalHandles) {
  230. HandlesAlwaysGrow = FALSE;
  231. }
  232. FinalCommit = NewCommit;
  233. FinalHandles = NewHandles;
  234. break;
  235. }
  236. }
  237. if (!_fgetts(LineBuffer, 256, InputFile)) {
  238. _ftprintf(stderr, _T("Cannot read input file.\n"));
  239. return 1;
  240. }
  241. }
  242. fclose(InputFile);
  243. return 0;
  244. } catch (...) {
  245. // this is mostly intended to catch out-of-memory errors
  246. _tprintf(_T("\nAn exception was detected. MEMFILT aborted.\n"));
  247. return 1;
  248. }
  249. }