windows-nt/Source/XPSP1/NT/sdktools/memsnap/memfilt.cpp
2020-09-26 16:20:57 +08:00

405 lines
9.3 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
memfilt.cpp
Abstract:
This module filters out the useful information from a sorted memsnap 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 MF_NEW_PROCESS 0
#define MF_UPDATE 1
// globals
LONG MinimumCommitChangeToReport = 1;
LONG MinimumHandleChangeToReport = 1;
BOOLEAN ReportIncreasesOnly = TRUE;
VOID
PrintUsage(
)
/*++
Routine Description:
This routine prints an informational message about the proper usage of MEMFILT.
Arguments:
None.
Return value:
None.
--*/
{
_ftprintf(stderr, _T("Summarizes possible leaks in a sorted MEMSNAP output file.\n\n"));
_ftprintf(stderr, _T("MEMFILT file [/MINCOMMIT:n] [/MINHANDLES:n] [/ALL]\n\n"));
_ftprintf(stderr, _T("file A sorted memsnap output file.\n"));
_ftprintf(stderr, _T("/MINCOMMIT:n Reports only processes where commit charge increased by\n"));
_ftprintf(stderr, _T(" at least n.\n"));
_ftprintf(stderr, _T("/MINHANDLES:n Reports only processes where handle count increased by\n"));
_ftprintf(stderr, _T(" at least n.\n"));
_ftprintf(stderr, _T("/ALL Reports decreases as well as increases.\n"));
}
VOID
PrintProcessInformation(
IN BOOLEAN CommitAlwaysGrows,
IN BOOLEAN HandlesAlwaysGrow,
IN LPTSTR ProcessName,
IN LONG InitialCommit,
IN LONG FinalCommit,
IN LONG InitialHandles,
IN LONG FinalHandles
)
/*++
Routine Description:
This routine reports the memory usage of a single process.
Arguments:
CommitAlwaysGrows - TRUE if commit monotonically increases.
HandlesAlwaysGrow - TRUE if handles monotonically increase.
ProcessName - the name of the process being reported.
InitialCommit - initial commit charge for this process.
FinalCommit - final commit charge for this process.
InitialHandles - initial handle count for this process.
FinalHandles - final handle count for this process.
Return value:
None.
--*/
{
_TCHAR CommitString[64];
_TCHAR HandlesString[64];
if(((!ReportIncreasesOnly) &&
(abs(FinalCommit - InitialCommit) >=
MinimumCommitChangeToReport)) ||
(FinalCommit - InitialCommit >=
MinimumCommitChangeToReport)) {
_stprintf(CommitString, _T("%10d->%10d"), InitialCommit, FinalCommit);
} else {
_tcscpy(CommitString, _T(" "));
}
if(((!ReportIncreasesOnly) &&
(abs(FinalHandles - InitialHandles) >=
MinimumHandleChangeToReport)) ||
(FinalHandles - InitialHandles >=
MinimumHandleChangeToReport)) {
_stprintf(HandlesString, _T("%10d->%10d"), InitialHandles, FinalHandles);
} else {
_tcscpy(HandlesString, _T(" "));
}
_tprintf(_T("%c%c %s %s %s\n"),
(CommitAlwaysGrows && (FinalCommit != InitialCommit) ? _T('!') : _T(' ')),
(HandlesAlwaysGrow && (FinalHandles != InitialHandles) ? _T('!') : _T(' ')),
ProcessName, CommitString, HandlesString);
}
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 {
FILE *InputFile = NULL;
_TCHAR LineBuffer[256];
_TCHAR ProcessName[64];
LONG CurrentState = MF_NEW_PROCESS;
LONG InitialCommit = 0;
LONG FinalCommit = 0;
LONG NewCommit = 0;
LONG InitialHandles = 0;
LONG FinalHandles = 0;
LONG NewHandles = 0;
LONG MonotonicallyIncreasing = 0;
BOOLEAN CommitAlwaysGrows = TRUE;
BOOLEAN HandlesAlwaysGrow = TRUE;
BOOLEAN InterpretedArgument = FALSE;
LONG Processes = 0;
LPTSTR InputFileName = NULL;
// make sure ProcessName is properly terminated
ProcessName[30]=_T('\0');
// parse command line arguments
if(argc < 2) {
PrintUsage();
return 1;
}
for(LONG n=1; n<argc; n++) {
InterpretedArgument = FALSE;
switch(argv[n][0]) {
case _T('-'):
case _T('/'):
// it's a switch
if(!_tcsicmp(argv[n]+1, _T("all"))) {
ReportIncreasesOnly = FALSE;
InterpretedArgument = TRUE;
}
if(!_tcsnicmp(argv[n]+1, _T("mincommit:"), 10)) {
MinimumCommitChangeToReport = _ttoi(argv[n]+10);
InterpretedArgument = TRUE;
}
if(!_tcsnicmp(argv[n]+1, _T("minhandles:"), 11)) {
MinimumHandleChangeToReport = _ttoi(argv[n]+11);
InterpretedArgument = TRUE;
}
break;
default:
if(InputFileName != NULL) {
// too many filenames
PrintUsage();
return 1;
}
InputFileName = argv[n];
InterpretedArgument = TRUE;
break;
}
if(!InterpretedArgument) {
PrintUsage();
return 1;
}
}
if(InputFileName == NULL) {
// filename not specified
PrintUsage();
return 1;
}
InputFile = _tfopen(InputFileName, _T("rt"));
if(InputFile == NULL) {
_ftprintf(stderr, _T("Cannot open input file.\n"));
return 1;
}
// skip header
if (!_fgetts(LineBuffer, 256, InputFile)) {
_ftprintf(stderr, _T("Cannot read input file.\n"));
return 1;
}
if (!_fgetts(LineBuffer, 256, InputFile)) {
_ftprintf(stderr, _T("Cannot read input file.\n"));
return 1;
}
while(!feof(InputFile)) {
if(!_tcscmp(LineBuffer,_T("\n"))) {
// blank line indicates a new process
CurrentState = MF_NEW_PROCESS;
// does the most recent process meet the criteria to be reported?
if(ReportIncreasesOnly) {
if(((FinalCommit - InitialCommit) >= MinimumCommitChangeToReport) ||
((FinalHandles - InitialHandles) >= MinimumHandleChangeToReport)) {
PrintProcessInformation(CommitAlwaysGrows, HandlesAlwaysGrow,
ProcessName, InitialCommit, FinalCommit, InitialHandles,
FinalHandles);
}
} else {
if((abs(FinalCommit - InitialCommit) >= MinimumCommitChangeToReport) ||
(abs(FinalHandles - InitialHandles) >= MinimumHandleChangeToReport)) {
PrintProcessInformation(CommitAlwaysGrows, HandlesAlwaysGrow,
ProcessName, InitialCommit, FinalCommit, InitialHandles,
FinalHandles);
}
}
} else {
if(_tcslen(LineBuffer) <= 80) {
_ftprintf(stderr, _T("Format violated.\n"));
return 1;
}
switch(CurrentState) {
case MF_NEW_PROCESS:
_tcsncpy(ProcessName, LineBuffer, 30);
if (_stscanf(LineBuffer+70, _T("%d"), &InitialCommit) != 1) break;
if (_stscanf(LineBuffer+80, _T("%d"), &InitialHandles) != 1) break;
FinalCommit = 0;
FinalHandles = 0;
CommitAlwaysGrows = TRUE;
HandlesAlwaysGrow = TRUE;
CurrentState = MF_UPDATE;
break;
case MF_UPDATE:
if (_stscanf(LineBuffer+70, _T("%d"), &NewCommit) != 1) break;
if (_stscanf(LineBuffer+80, _T("%d"), &NewHandles) != 1) break;
if(NewCommit < FinalCommit) {
CommitAlwaysGrows = FALSE;
}
if(NewHandles < FinalHandles) {
HandlesAlwaysGrow = FALSE;
}
FinalCommit = NewCommit;
FinalHandles = NewHandles;
break;
}
}
if (!_fgetts(LineBuffer, 256, InputFile)) {
_ftprintf(stderr, _T("Cannot read input file.\n"));
return 1;
}
}
fclose(InputFile);
return 0;
} catch (...) {
// this is mostly intended to catch out-of-memory errors
_tprintf(_T("\nAn exception was detected. MEMFILT aborted.\n"));
return 1;
}
}