windows-nt/Source/XPSP1/NT/sdktools/pfmon/pfmon.c
2020-09-26 16:20:57 +08:00

274 lines
8 KiB
C

/*++
Copyright (c) 1995 Microsoft Corporation
Module Name:
pfmon.c
Abstract:
USAGE: pfmon [pfmon switches] command-line-of-application
Author:
Mark Lucovsky (markl) 26-Jan-1995
--*/
#include "pfmonp.h"
#define WORKING_SET_BUFFER_ENTRYS 4096
PSAPI_WS_WATCH_INFORMATION WorkingSetBuffer[WORKING_SET_BUFFER_ENTRYS];
#define MAX_SYMNAME_SIZE 1024
CHAR PcSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
PIMAGEHLP_SYMBOL PcSymbol = (PIMAGEHLP_SYMBOL) PcSymBuffer;
CHAR VaSymBuffer[sizeof(IMAGEHLP_SYMBOL)+MAX_SYMNAME_SIZE];
PIMAGEHLP_SYMBOL VaSymbol = (PIMAGEHLP_SYMBOL) VaSymBuffer;
#if defined (_WIN64)
#define ZERO_PTR "%016I64x"
#define ZEROD_PTR "%I64u"
#else
#define ZERO_PTR "%08x"
#define ZEROD_PTR "%u"
#endif
int
WINAPI
WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nShowCmd
)
{
CHAR Line[256];
if (!InitializePfmon()) {
ExitProcess( 1 );
}
else {
DebugEventLoop();
sprintf(Line,"\n PFMON: Total Faults %d (KM %d UM %d Soft %d, Hard %d, Code %d, Data %d)\n",
TotalSoftFaults + TotalHardFaults,
TotalKernelFaults,
TotalUserFaults,
TotalSoftFaults,
TotalHardFaults,
TotalCodeFaults,
TotalDataFaults
);
fprintf(stdout,"%s",Line);
if ( LogFile ) {
fprintf(LogFile,"%s",Line);
fclose(LogFile);
}
ExitProcess( 0 );
}
return 0;
}
VOID
ProcessPfMonData(
VOID
)
{
BOOL b;
BOOL DidOne;
INT i;
PMODULE_INFO PcModule;
PMODULE_INFO VaModule;
ULONG_PTR PcOffset;
DWORD_PTR VaOffset;
CHAR PcLine[256];
CHAR VaLine[256];
CHAR PcModuleStr[256];
CHAR VaModuleStr[256];
LPVOID Pc;
LPVOID Va;
BOOL SoftFault;
BOOL CodeFault;
BOOL KillLog;
static int cPfCnt = 0;
PcSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
PcSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
VaSymbol->SizeOfStruct = sizeof(IMAGEHLP_SYMBOL);
VaSymbol->MaxNameLength = MAX_SYMNAME_SIZE;
//Get the buffer of recent page faults from the process's data structure
b = GetWsChanges(hProcess,&WorkingSetBuffer[0],sizeof(WorkingSetBuffer));
if ( b ) {
DidOne = FALSE;
i = 0;
while (WorkingSetBuffer[i].FaultingPc) {
if ( WorkingSetBuffer[i].FaultingVa ) {
Pc = WorkingSetBuffer[i].FaultingPc;
Va = WorkingSetBuffer[i].FaultingVa;
if ( (ULONG_PTR)Pc >= SystemRangeStart ) {
TotalKernelFaults++;
if ( !fKernel ) {
i++;
continue;
}
}
else {
TotalUserFaults++;
if ( fKernelOnly ) {
i++;
continue;
}
}
//Check least sig bit which stores whether it was a hard
//or soft fault
if ( (ULONG_PTR)Va & 1 ) {
TotalSoftFaults++;
SoftFault = TRUE;
}
else {
TotalHardFaults++;
SoftFault = FALSE;
}
Va = (LPVOID)( (ULONG_PTR)Va & ~1);
if ( (LPVOID)((ULONG_PTR)Pc & ~1) == Va ) {
CodeFault = TRUE;
TotalCodeFaults++;
}
else {
TotalDataFaults++;
CodeFault = FALSE;
}
PcModule = FindModuleContainingAddress(Pc);
VaModule = FindModuleContainingAddress(Va);
if ( PcModule ) {
PcModule->NumberCausedFaults++;
sprintf(PcModuleStr, "%s", PcModule->ModuleName);
}
else {
sprintf(PcModuleStr,"not found %p",Pc);
PcModuleStr[0] = '\0';
}
//Va was either a code reference or global
//reference as opposed to a heap reference
if ( VaModule ) {
if ( SoftFault ) {
VaModule->NumberFaultedSoftVas++;
}
else {
VaModule->NumberFaultedHardVas++;
}
sprintf(VaModuleStr, "%s", VaModule->ModuleName);
}
else
VaModuleStr[0] = '\0';
if (SymGetSymFromAddr(hProcess, (ULONG_PTR)Pc, &PcOffset, PcSymbol)) {
if ( PcOffset ) {
sprintf(PcLine,"%s+0x%x",PcSymbol->Name,PcOffset);
}
else {
sprintf(PcLine,"%s",PcSymbol->Name);
}
}
else {
sprintf(PcLine,""ZERO_PTR"",Pc);
}
if (SymGetSymFromAddr(hProcess, (ULONG_PTR)Va, &VaOffset, VaSymbol)) {
if ( VaOffset ) {
sprintf(VaLine,"%s+0x%p",VaSymbol->Name,VaOffset);
}
else {
sprintf(VaLine,"%s",VaSymbol->Name);
}
}
else {
sprintf(VaLine,""ZERO_PTR"",Va);
}
KillLog = FALSE;
if ( fCodeOnly && !CodeFault ) {
KillLog = TRUE;
}
if ( fHardOnly && SoftFault ) {
KillLog = TRUE;
}
if ( !KillLog ) {
if ( !fLogOnly ) {
if (!fDatabase) {
fprintf(stdout,"%s%s : %s\n",SoftFault ? "SOFT: " : "HARD: ",PcLine,VaLine);
}
else {
//Addresses are printed out in decimal
//because most databases don't support
//hex formats
fprintf(stdout,"%8d\t%s\t%s\t%s\t"ZEROD_PTR"\t%s\t%s\t"ZEROD_PTR"\n",
cPfCnt,
SoftFault ? "SOFT" : "HARD",
PcModuleStr,
PcLine,
(DWORD_PTR) Pc,
VaModuleStr,
VaLine,
(DWORD_PTR) Va);
}
}
if ( LogFile ) {
if (!fDatabase) {
fprintf(LogFile,"%s%s : %s\n",SoftFault ? "SOFT: " : "HARD: ",PcLine,VaLine);
}
else {
fprintf(LogFile,"%8d\t%s\t%s\t%s\t"ZEROD_PTR"\t%s\t%s\t"ZEROD_PTR"\n",
cPfCnt,
SoftFault ? "SOFT" : "HARD",
PcModuleStr,
PcLine,
(DWORD_PTR) Pc,
VaModuleStr,
VaLine,
(DWORD_PTR) Va);
}
}
DidOne = TRUE;
cPfCnt++;
}
}
i++;
}
if ( DidOne ) {
if ( !fLogOnly && !fDatabase) {
fprintf(stdout,"\n");
}
}
//If the buffer overflowed then a non-zero value for
//the Va was stored in the last record.
if (WorkingSetBuffer[i].FaultingVa)
fprintf(stdout,"Warning: Page fault buffer has overflowed\n");
}
}