426 lines
9.6 KiB
C++
426 lines
9.6 KiB
C++
|
/*++
|
|||
|
|
|||
|
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;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|