274 lines
8 KiB
C
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");
|
|
}
|
|
}
|