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.

461 lines
11 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. poolfilt.cpp
  5. Abstract:
  6. This module filters out the useful information from a sorted poolsnap 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 PF_NEW_TAG 0
  19. #define PF_UPDATE 1
  20. // globals
  21. LONG MinimumAllocationsChangeToReport=1;
  22. LONG MinimumBytesChangeToReport=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 POOLFILT.
  30. Arguments:
  31. None.
  32. Return value:
  33. None.
  34. --*/
  35. {
  36. _ftprintf(stderr, _T("Summarizes possible leaks in a sorted poolsnap output file.\n\n"));
  37. _ftprintf(stderr, _T("POOLFILT file [/MINALLOCS:n] [/MINBYTES:n] [/ALL]\n\n"));
  38. _ftprintf(stderr, _T("file The sorted poolsnap output file to summarize.\n"));
  39. _ftprintf(stderr, _T("/MINALLOCS:n Reports only tags where open allocations change by at least n.\n"));
  40. _ftprintf(stderr, _T("/MINBYTES:n Reports only tags where bytes allocated change by at least n.\n"));
  41. _ftprintf(stderr, _T("/ALL Reports decreases as well as increases.\n"));
  42. }
  43. VOID
  44. PrintTagInformation(
  45. IN BOOLEAN AllocationsAlwaysGrow,
  46. IN BOOLEAN BytesAlwaysGrow,
  47. IN LPTSTR TagName,
  48. IN LONG InitialAllocations,
  49. IN LONG FinalAllocations,
  50. IN LONG InitialBytes,
  51. IN LONG FinalBytes
  52. )
  53. /*++
  54. Routine Description:
  55. This routine reports the memory usage of a single process.
  56. Arguments:
  57. AllocationsAlwaysGrow - TRUE if number of open allocations monotonically increases.
  58. BytesAlwaysGrow - TRUE if number of bytes allocated monotonically increases.
  59. TagName - the name of the tag being reported.
  60. InitialAllocations - initial number of open allocations for this tag.
  61. FinalAllocations - final number fo open allocations for this tag.
  62. InitialBytes - initial number of bytes allocated for this tag.
  63. FinalBytes - final number of bytes allocated for this tag.
  64. Return value:
  65. None.
  66. --*/
  67. {
  68. _TCHAR AllocationsString[64];
  69. _TCHAR BytesString[64];
  70. if(((!ReportIncreasesOnly) &&
  71. (abs(FinalAllocations - InitialAllocations) >=
  72. MinimumAllocationsChangeToReport)) ||
  73. (FinalAllocations - InitialAllocations >=
  74. MinimumAllocationsChangeToReport)) {
  75. _stprintf(AllocationsString, _T("%10d->%10d"), InitialAllocations, FinalAllocations);
  76. } else {
  77. _tcscpy(AllocationsString, _T(" "));
  78. }
  79. if(((!ReportIncreasesOnly) &&
  80. (abs(FinalBytes - InitialBytes) >=
  81. MinimumBytesChangeToReport)) ||
  82. (FinalBytes - InitialBytes >=
  83. MinimumBytesChangeToReport)) {
  84. _stprintf(BytesString, _T("%10d->%10d"), InitialBytes, FinalBytes);
  85. } else {
  86. _tcscpy(BytesString, _T(" "));
  87. }
  88. _tprintf(_T("%c%c %s %s %s\n"),
  89. (AllocationsAlwaysGrow && (FinalAllocations != InitialAllocations) ? _T('!') : _T(' ')),
  90. (BytesAlwaysGrow && (FinalBytes != InitialBytes) ? _T('!') : _T(' ')),
  91. TagName, AllocationsString, BytesString);
  92. }
  93. LONG _cdecl
  94. _tmain(
  95. IN LONG argc,
  96. IN LPTSTR argv[]
  97. )
  98. /*++
  99. Routine Description:
  100. This routine parses program arguments, reads the input file, and outputs the result.
  101. Arguments:
  102. argc - Number of command line arguments.
  103. argv - Command line arguments.
  104. Return value:
  105. 0 if filtering is successful, 1 otherwise.
  106. --*/
  107. {
  108. try {
  109. _TCHAR LineBuffer[256];
  110. _TCHAR PoolTag[11];
  111. LONG CurrentState = PF_NEW_TAG;
  112. LONG InitialAllocations = 0;
  113. LONG FinalAllocations = 0;
  114. LONG NewAllocations = 0;
  115. LONG InitialBytes = 0;
  116. LONG FinalBytes = 0;
  117. LONG NewBytes = 0;
  118. BOOLEAN AllocationsAlwaysGrow = TRUE;
  119. BOOLEAN BytesAlwaysGrow = TRUE;
  120. LPTSTR InputFileName = NULL;
  121. BOOLEAN InterpretedArgument = FALSE;
  122. FILE *InputFile = NULL;
  123. TCHAR * ReadResult;
  124. int ScanResult;
  125. // make sure PoolTag is properly terminated
  126. PoolTag[10]=_T('\0');
  127. // process arguments
  128. for(LONG n = 1; n < argc; n++) {
  129. InterpretedArgument = FALSE;
  130. switch(argv[n][0]) {
  131. case _T('-'):
  132. case _T('/'):
  133. // it's a switch
  134. if(!_tcsnicmp(argv[n]+1, _T("minallocs:"), 10)) {
  135. MinimumAllocationsChangeToReport = _ttoi(argv[n]+11);
  136. InterpretedArgument = TRUE;
  137. }
  138. if(!_tcsnicmp(argv[n]+1, _T("minbytes:"), 9)) {
  139. MinimumBytesChangeToReport = _ttoi(argv[n]+10);
  140. InterpretedArgument = TRUE;
  141. }
  142. if(!_tcsicmp(argv[n]+1, _T("all"))) {
  143. ReportIncreasesOnly = FALSE;
  144. InterpretedArgument = TRUE;
  145. }
  146. break;
  147. default:
  148. // it's a filename
  149. if(InputFileName != NULL) {
  150. // already have the filename
  151. PrintUsage();
  152. return 1;
  153. }
  154. InputFileName = argv[n];
  155. InterpretedArgument = TRUE;
  156. break;
  157. }
  158. if(!InterpretedArgument) {
  159. PrintUsage();
  160. return 1;
  161. }
  162. }
  163. if(InputFileName == NULL) {
  164. // user didn't specify filename
  165. PrintUsage();
  166. return 1;
  167. }
  168. InputFile = _tfopen(InputFileName, _T("rt"));
  169. if(InputFile == NULL) {
  170. _ftprintf(stderr, _T("Cannot open input file."));
  171. return 1;
  172. }
  173. // get first line
  174. ReadResult = _fgetts(LineBuffer, 256, InputFile);
  175. if (ReadResult == NULL) {
  176. _ftprintf(stderr, _T("Input is not a sorted poolsnap log."));
  177. return 1;
  178. }
  179. // simple check for sorted poolsnap output
  180. if(_tcsncmp(LineBuffer, _T(" Tag Type Allocs Frees Diff Bytes Per Alloc"), 60)) {
  181. _ftprintf(stderr, _T("Input is not a sorted poolsnap log."));
  182. return 1;
  183. }
  184. // get next line
  185. ReadResult = _fgetts(LineBuffer, 256, InputFile);
  186. if (ReadResult == NULL) {
  187. _ftprintf(stderr, _T("Input is not a sorted poolsnap log."));
  188. return 1;
  189. }
  190. while(!feof(InputFile)) {
  191. if(!_tcscmp(LineBuffer,_T("\n"))) {
  192. CurrentState = PF_NEW_TAG;
  193. if(ReportIncreasesOnly) {
  194. if(((FinalAllocations - InitialAllocations) >= MinimumAllocationsChangeToReport)
  195. || ((FinalBytes - InitialBytes) >= MinimumBytesChangeToReport)) {
  196. PrintTagInformation(AllocationsAlwaysGrow, BytesAlwaysGrow,
  197. PoolTag, InitialAllocations, FinalAllocations,
  198. InitialBytes, FinalBytes);
  199. }
  200. } else {
  201. if((abs(FinalAllocations - InitialAllocations) >= MinimumAllocationsChangeToReport)
  202. || (abs(FinalBytes - InitialBytes) >= MinimumBytesChangeToReport)) {
  203. PrintTagInformation(AllocationsAlwaysGrow, BytesAlwaysGrow,
  204. PoolTag, InitialAllocations, FinalAllocations,
  205. InitialBytes, FinalBytes);
  206. }
  207. }
  208. } else {
  209. if(_tcslen(LineBuffer) <= 42) {
  210. _ftprintf(stderr, _T("Format violated.\n"));
  211. return 1;
  212. }
  213. switch(CurrentState) {
  214. case PF_NEW_TAG:
  215. // get tag and paged/non-paged
  216. _tcsncpy(PoolTag, LineBuffer+1, 10);
  217. // get allocs
  218. ScanResult = _stscanf(LineBuffer+32, _T("%d"), &InitialAllocations);
  219. if (ScanResult != 1) {
  220. _ftprintf(stderr, _T("Format violated.\n"));
  221. return 1;
  222. }
  223. // get bytes
  224. ScanResult = _stscanf(LineBuffer+42, _T("%d"), &InitialBytes);
  225. if (ScanResult != 1) {
  226. _ftprintf(stderr, _T("Format violated.\n"));
  227. return 1;
  228. }
  229. // assume this always grows until we find a counterexample
  230. AllocationsAlwaysGrow = TRUE;
  231. BytesAlwaysGrow = TRUE;
  232. // this is initial and final until we find another
  233. FinalAllocations = InitialAllocations;
  234. FinalBytes = InitialBytes;
  235. // keep updating this tag
  236. CurrentState = PF_UPDATE;
  237. break;
  238. case PF_UPDATE:
  239. // get allocs
  240. ScanResult = _stscanf(LineBuffer+32, _T("%d"), &NewAllocations);
  241. if (ScanResult != 1) {
  242. _ftprintf(stderr, _T("Format violated.\n"));
  243. return 1;
  244. }
  245. // get bytes
  246. ScanResult = _stscanf(LineBuffer+42, _T("%d"), &NewBytes);
  247. if (ScanResult != 1) {
  248. _ftprintf(stderr, _T("Format violated.\n"));
  249. return 1;
  250. }
  251. // did allocs decrease?
  252. if(NewAllocations < FinalAllocations) {
  253. AllocationsAlwaysGrow = FALSE;
  254. }
  255. // did bytes decrease?
  256. if(NewBytes < FinalBytes) {
  257. BytesAlwaysGrow = FALSE;
  258. }
  259. // copy new to final
  260. FinalAllocations = NewAllocations;
  261. FinalBytes = NewBytes;
  262. break;
  263. }
  264. }
  265. // get next line
  266. ReadResult = _fgetts(LineBuffer, 256, InputFile);
  267. if (ReadResult == NULL) {
  268. break;
  269. }
  270. }
  271. // done
  272. fclose(InputFile);
  273. return 0;
  274. } catch (...) {
  275. // this is mostly intended to catch out-of-memory conditions
  276. _tprintf(_T("\nAn exception was detected. POOLFILT aborted.\n"));
  277. return 1;
  278. }
  279. }