windows-nt/Source/XPSP1/NT/sdktools/memsnap/poolfilt.cpp

426 lines
9.6 KiB
C++
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
poolfilt.cpp
Abstract:
This module filters out the useful information from a sorted poolsnap output file.
Author:
Matt Bandy (t-mattba) 27-Jul-1998
Revision History:
27-Jul-1998 t-mattba
Modified module to conform to coding standards.
--*/
#include <nt.h>
#include <tchar.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define PF_NEW_TAG 0
#define PF_UPDATE 1
// globals
LONG MinimumAllocationsChangeToReport=1;
LONG MinimumBytesChangeToReport=1;
BOOLEAN ReportIncreasesOnly = TRUE;
VOID
PrintUsage(
)
/*++
Routine Description:
This routine prints an informational message about the proper usage of POOLFILT.
Arguments:
None.
Return value:
None.
--*/
{
_ftprintf(stderr, _T("Summarizes possible leaks in a sorted poolsnap output file.\n\n"));
_ftprintf(stderr, _T("POOLFILT file [/MINALLOCS:n] [/MINBYTES:n] [/ALL]\n\n"));
_ftprintf(stderr, _T("file The sorted poolsnap output file to summarize.\n"));
_ftprintf(stderr, _T("/MINALLOCS:n Reports only tags where open allocations change by at least n.\n"));
_ftprintf(stderr, _T("/MINBYTES:n Reports only tags where bytes allocated change by at least n.\n"));
_ftprintf(stderr, _T("/ALL Reports decreases as well as increases.\n"));
}
VOID
PrintTagInformation(
IN BOOLEAN AllocationsAlwaysGrow,
IN BOOLEAN BytesAlwaysGrow,
IN LPTSTR TagName,
IN LONG InitialAllocations,
IN LONG FinalAllocations,
IN LONG InitialBytes,
IN LONG FinalBytes
)
/*++
Routine Description:
This routine reports the memory usage of a single process.
Arguments:
AllocationsAlwaysGrow - TRUE if number of open allocations monotonically increases.
BytesAlwaysGrow - TRUE if number of bytes allocated monotonically increases.
TagName - the name of the tag being reported.
InitialAllocations - initial number of open allocations for this tag.
FinalAllocations - final number fo open allocations for this tag.
InitialBytes - initial number of bytes allocated for this tag.
FinalBytes - final number of bytes allocated for this tag.
Return value:
None.
--*/
{
_TCHAR AllocationsString[64];
_TCHAR BytesString[64];
if(((!ReportIncreasesOnly) &&
(abs(FinalAllocations - InitialAllocations) >=
MinimumAllocationsChangeToReport)) ||
(FinalAllocations - InitialAllocations >=
MinimumAllocationsChangeToReport)) {
_stprintf(AllocationsString, _T("%10d->%10d"), InitialAllocations, FinalAllocations);
} else {
_tcscpy(AllocationsString, _T(" "));
}
if(((!ReportIncreasesOnly) &&
(abs(FinalBytes - InitialBytes) >=
MinimumBytesChangeToReport)) ||
(FinalBytes - InitialBytes >=
MinimumBytesChangeToReport)) {
_stprintf(BytesString, _T("%10d->%10d"), InitialBytes, FinalBytes);
} else {
_tcscpy(BytesString, _T(" "));
}
_tprintf(_T("%c%c %s %s %s\n"),
(AllocationsAlwaysGrow && (FinalAllocations != InitialAllocations) ? _T('!') : _T(' ')),
(BytesAlwaysGrow && (FinalBytes != InitialBytes) ? _T('!') : _T(' ')),
TagName, AllocationsString, BytesString);
}
LONG _cdecl
_tmain(
IN LONG argc,
IN LPTSTR argv[]
)
/*++
Routine Description:
This routine parses program arguments, reads the input file, and outputs the result.
Arguments:
argc - Number of command line arguments.
argv - Command line arguments.
Return value:
0 if filtering is successful, 1 otherwise.
--*/
{
try {
_TCHAR LineBuffer[256];
_TCHAR PoolTag[11];
LONG CurrentState = PF_NEW_TAG;
LONG InitialAllocations = 0;
LONG FinalAllocations = 0;
LONG NewAllocations = 0;
LONG InitialBytes = 0;
LONG FinalBytes = 0;
LONG NewBytes = 0;
BOOLEAN AllocationsAlwaysGrow = TRUE;
BOOLEAN BytesAlwaysGrow = TRUE;
LPTSTR InputFileName = NULL;
BOOLEAN InterpretedArgument = FALSE;
FILE *InputFile = NULL;
// make sure PoolTag is properly terminated
PoolTag[10]=_T('\0');
// process arguments
for(LONG n = 1; n < argc; n++) {
InterpretedArgument = FALSE;
switch(argv[n][0]) {
case _T('-'):
case _T('/'):
// it's a switch
if(!_tcsnicmp(argv[n]+1, _T("minallocs:"), 10)) {
MinimumAllocationsChangeToReport = _ttoi(argv[n]+11);
InterpretedArgument = TRUE;
}
if(!_tcsnicmp(argv[n]+1, _T("minbytes:"), 9)) {
MinimumBytesChangeToReport = _ttoi(argv[n]+10);
InterpretedArgument = TRUE;
}
if(!_tcsicmp(argv[n]+1, _T("all"))) {
ReportIncreasesOnly = FALSE;
InterpretedArgument = TRUE;
}
break;
default:
// it's a filename
if(InputFileName != NULL) {
// already have the filename
PrintUsage();
return 1;
}
InputFileName = argv[n];
InterpretedArgument = TRUE;
break;
}
if(!InterpretedArgument) {
PrintUsage();
return 1;
}
}
if(InputFileName == NULL) {
// user didn't specify filename
PrintUsage();
return 1;
}
InputFile = _tfopen(InputFileName, _T("rt"));
if(InputFile == NULL) {
_ftprintf(stderr, _T("Cannot open input file."));
return 1;
}
// get first line
_fgetts(LineBuffer, 256, InputFile);
// simple check for sorted poolsnap output
if(_tcsncmp(LineBuffer, _T(" Tag Type Allocs Frees Diff Bytes Per Alloc"), 60)) {
_ftprintf(stderr, _T("Input is not a sorted poolsnap log."));
return 1;
}
// get next line
_fgetts(LineBuffer, 256, InputFile);
while(!feof(InputFile)) {
if(!_tcscmp(LineBuffer,_T("\n"))) {
CurrentState = PF_NEW_TAG;
if(ReportIncreasesOnly) {
if(((FinalAllocations - InitialAllocations) >= MinimumAllocationsChangeToReport)
|| ((FinalBytes - InitialBytes) >= MinimumBytesChangeToReport)) {
PrintTagInformation(AllocationsAlwaysGrow, BytesAlwaysGrow,
PoolTag, InitialAllocations, FinalAllocations,
InitialBytes, FinalBytes);
}
} else {
if((abs(FinalAllocations - InitialAllocations) >= MinimumAllocationsChangeToReport)
|| (abs(FinalBytes - InitialBytes) >= MinimumBytesChangeToReport)) {
PrintTagInformation(AllocationsAlwaysGrow, BytesAlwaysGrow,
PoolTag, InitialAllocations, FinalAllocations,
InitialBytes, FinalBytes);
}
}
} else {
if(_tcslen(LineBuffer) <= 42) {
_ftprintf(stderr, _T("Format violated.\n"));
return 1;
}
switch(CurrentState) {
case PF_NEW_TAG:
// get tag and paged/non-paged
_tcsncpy(PoolTag, LineBuffer+1, 10);
// get allocs
_stscanf(LineBuffer+32, _T("%d"), &InitialAllocations);
// get bytes
_stscanf(LineBuffer+42, _T("%d"), &InitialBytes);
// assume this always grows until we find a counterexample
AllocationsAlwaysGrow = TRUE;
BytesAlwaysGrow = TRUE;
// this is initial and final until we find another
FinalAllocations = InitialAllocations;
FinalBytes = InitialBytes;
// keep updating this tag
CurrentState = PF_UPDATE;
break;
case PF_UPDATE:
// get allocs
_stscanf(LineBuffer+32, _T("%d"), &NewAllocations);
// get bytes
_stscanf(LineBuffer+42, _T("%d"), &NewBytes);
// did allocs decrease?
if(NewAllocations < FinalAllocations) {
AllocationsAlwaysGrow = FALSE;
}
// did bytes decrease?
if(NewBytes < FinalBytes) {
BytesAlwaysGrow = FALSE;
}
// copy new to final
FinalAllocations = NewAllocations;
FinalBytes = NewBytes;
break;
}
}
// get next line
_fgetts(LineBuffer, 256, InputFile);
}
// done
fclose(InputFile);
return 0;
} catch (...) {
// this is mostly intended to catch out-of-memory conditions
_tprintf(_T("\nAn exception was detected. POOLFILT aborted.\n"));
return 1;
}
}