268 lines
7.8 KiB
C
268 lines
7.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;
|
|
|
|
|
|
|
|
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;
|
|
DWORD PcOffset;
|
|
DWORD 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 ( (DWORD)Pc & 0x80000000 ) {
|
|
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)Va & 1 ) {
|
|
TotalSoftFaults++;
|
|
SoftFault = TRUE;
|
|
}
|
|
else {
|
|
TotalHardFaults++;
|
|
SoftFault = FALSE;
|
|
}
|
|
|
|
Va = (LPVOID)( (ULONG)Va & 0xfffffffe);
|
|
if ( (LPVOID)((ULONG)Pc & 0xfffffffe) == Va ) {
|
|
CodeFault = TRUE;
|
|
TotalCodeFaults++;
|
|
}
|
|
else {
|
|
TotalDataFaults++;
|
|
CodeFault = FALSE;
|
|
}
|
|
|
|
|
|
PcModule = FindModuleContainingAddress(Pc);
|
|
VaModule = FindModuleContainingAddress(Va);
|
|
|
|
if ( PcModule ) {
|
|
PcModule->NumberCausedFaults++;
|
|
sprintf(PcModuleStr, "%s", PcModule->DebugInfo->ImageFileName);
|
|
}
|
|
else {
|
|
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->DebugInfo->ImageFileName);
|
|
}
|
|
else
|
|
VaModuleStr[0] = '\0';
|
|
|
|
if (SymGetSymFromAddr(hProcess, (DWORD)Pc, &PcOffset, PcSymbol)) {
|
|
if ( PcOffset ) {
|
|
sprintf(PcLine,"%s+0x%x",PcSymbol->Name,PcOffset);
|
|
}
|
|
else {
|
|
sprintf(PcLine,"%s",PcSymbol->Name);
|
|
}
|
|
}
|
|
else {
|
|
sprintf(PcLine,"0x%08x : ",Pc);
|
|
}
|
|
|
|
if (SymGetSymFromAddr(hProcess, (DWORD)Va, &VaOffset, VaSymbol)) {
|
|
if ( VaOffset ) {
|
|
sprintf(VaLine,"%s+0x%x",VaSymbol->Name,VaOffset);
|
|
}
|
|
else {
|
|
sprintf(VaLine,"%s",VaSymbol->Name);
|
|
}
|
|
}
|
|
else {
|
|
sprintf(VaLine,"0x%08x",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%u\t%s\t%s\t%u\n",
|
|
cPfCnt,
|
|
SoftFault ? "SOFT" : "HARD",
|
|
PcModuleStr,
|
|
PcLine,
|
|
(DWORD) Pc,
|
|
VaModuleStr,
|
|
VaLine,
|
|
(DWORD) 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%u\t%s\t%s\t%u\n",
|
|
cPfCnt,
|
|
SoftFault ? "SOFT" : "HARD",
|
|
PcModuleStr,
|
|
PcLine,
|
|
(DWORD) Pc,
|
|
VaModuleStr,
|
|
VaLine,
|
|
(DWORD) 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 ((ULONG)WorkingSetBuffer[i].FaultingVa)
|
|
fprintf(stdout,"Warning: Page fault buffer has overflowed\n");
|
|
|
|
|
|
}
|
|
}
|