/*++ Copyright (c) 1997-2000 Microsoft Corporation Module Name: report.c Abstract: Manipulation routines for cpdata structures. Author: Melur Raghuraman (mraghu) 03-Oct-1997 Environment: Revision History: --*/ #include #include #include "cpdata.h" #include "tracectr.h" #include #include "item.h" #define BREAK_LINE "+-----------------------------------------------------------------------------------------------------------------------------------+\n" extern PTRACE_CONTEXT_BLOCK TraceContext; extern ULONG TotalEventsLost; extern ULONG TotalEventCount; extern ULONG TimerResolution; extern ULONGLONG StartTime; extern ULONGLONG EndTime; extern __int64 ElapseTime; extern ULONG TotalBuffersRead; static FILE* procFile; static void PrintDiskTotals(); static void PrintProcessCpuTime(); static void PrintProcessData(); static void PrintPerThreadPerDiskTable(); static void WriteTransactionStatistics(); static void WriteTransactionCPUTime(); static void PrintProcessSubDataInclusive(); static void PrintProcessSubDataExclusive(); void TransInclusive( PLIST_ENTRY TrHead, ULONG level ); static void ReportPageFaultInfo(PCPD_USER_CONTEXT_MM pUserContext); static void ReportHardFaultInfo(void); static void ReportHotFileInfo(ULONG NumEntry); static void ReportJobInfo(void); extern GUID PrintJobGuid; PWCHAR CpdiGuidToString( PWCHAR s, LPGUID piid ); char* Month[] = { "", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; char* Day[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" }; ULONG ReportFlags = 0; void CollapseTree( PLIST_ENTRY OldTree, PLIST_ENTRY NewTree, BOOL flat ) { PLIST_ENTRY OldNext; PTRANS_RECORD pTrans; PTRANS_RECORD pNewTrans; OldNext = OldTree->Flink; while (OldNext != OldTree) { pTrans = CONTAINING_RECORD(OldNext, TRANS_RECORD, Entry); OldNext = OldNext->Flink; pNewTrans = FindTransByList(NewTree, pTrans->pGuid, 0); if( NULL != pNewTrans ){ pNewTrans->KCpu += pTrans->KCpu; pNewTrans->UCpu += pTrans->UCpu; pNewTrans->RefCount += pTrans->RefCount; pNewTrans->RefCount1 += pTrans->RefCount1; if (flat) { CollapseTree(&pTrans->SubTransListHead, NewTree, TRUE ); } else { CollapseTree(& pTrans->SubTransListHead, & pNewTrans->SubTransListHead, FALSE); } }else{ // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); } } } #define BARLEN 70 char* TimeWindowBar( char* buffer, ULONGLONG min, ULONGLONG max ) { double unit; ULONGLONG duration; int pre, bar, count; if(buffer == NULL){ return NULL; } duration = ((CurrentSystem.EndTime - CurrentSystem.StartTime) / 10000000); unit = (double)BARLEN/(ULONG)duration; pre = (int)((ULONG)((min - CurrentSystem.StartTime)/10000000) * unit); bar = (int)((ULONG)((max - min)/10000000) * unit); strcpy( buffer, "" ); count = 0; while(count++ < pre){ strcat(buffer, " "); } strcat( buffer, "|" ); count = 0; while(count++ < bar){ strcat(buffer, "_"); } strcat(buffer, "|" ); return buffer; } void WriteProc( LPWSTR ProcFileName, ULONG flags, PVOID pUserContext ) { ULONGLONG duration; FILETIME StTm, EndTm, StlTm, EndlTm; LARGE_INTEGER LargeTmp; SYSTEMTIME tmf; PLIST_ENTRY Next, Head; PPROCESS_FILE_RECORD pFileRec; char buffer[MAXSTR]; BOOL bResult; ReportFlags = flags; procFile = _wfopen(ProcFileName, L"w"); if (procFile == NULL) return; LargeTmp.QuadPart = CurrentSystem.StartTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); bResult = FileTimeToSystemTime ( &StlTm, &tmf ); if( ! bResult || tmf.wMonth > 12 ){ ZeroMemory( &tmf, sizeof(SYSTEMTIME) ); } fprintf(procFile, BREAK_LINE "| Windows Event Trace Session Report %83s\n" "| Version : %4d %82s\n" "| Type : %-20s %68s\n" BREAK_LINE "| %75s\n" "| Build : %-8d %79s\n" "| Processors: %-8d %79s\n" "| Start Time: %2d %3s %4d %2d:%02d:%02d.%03d %-80s |\n", "|", VER_PRODUCTBUILD, "|", ( ReportFlags & TRACE_LOG_REPORT_TOTALS ) ? "Total" : "Default", "|", "|", CurrentSystem.BuildNumber, "|", CurrentSystem.NumberOfProcessors, "|", tmf.wDay, Month[tmf.wMonth], tmf.wYear, tmf.wHour, tmf.wMinute, tmf.wSecond, tmf.wMilliseconds, "|______________________________________________________________________|" ); LargeTmp.QuadPart = CurrentSystem.EndTime; EndTm.dwHighDateTime = LargeTmp.HighPart; EndTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&EndTm, &EndlTm); FileTimeToSystemTime ( &EndlTm, &tmf ); fprintf(procFile, "| End Time : %2d %3s %4d %2d:%02d:%02d.%03d %87s\n", tmf.wDay, Month[tmf.wMonth], tmf.wYear, tmf.wHour, tmf.wMinute, tmf.wSecond, tmf.wMilliseconds, "|"); duration = (CurrentSystem.EndTime - CurrentSystem.StartTime) / 10000000; fprintf(procFile, "| Duration : %-15I64u sec %70s\n" "| %77s\n", duration, "|", "|" ); Head = &CurrentSystem.ProcessFileListHead; Next = Head->Flink; while (Next != Head) { pFileRec = CONTAINING_RECORD( Next, PROCESS_FILE_RECORD, Entry ); Next = Next->Flink; fprintf(procFile, "| Trace Name: %-43ws %60s\n" "| File Name : %-101ws %2s\n", pFileRec->TraceName ? pFileRec->TraceName : L"-", "|", pFileRec->FileName ? pFileRec->FileName : L"-", "|" ); if (pFileRec->StartTime == 0) pFileRec->StartTime = CurrentSystem.StartTime; if (pFileRec->EndTime == 0) pFileRec->EndTime = CurrentSystem.EndTime; LargeTmp.QuadPart = pFileRec->StartTime; EndTm.dwHighDateTime = LargeTmp.HighPart; EndTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&EndTm, &EndlTm); FileTimeToSystemTime ( &EndlTm, &tmf ); fprintf(procFile, "| Start Time: %2d %3s %4d %2d:%02d:%02d.%03d %-80s |\n", tmf.wDay, Month[tmf.wMonth], tmf.wYear, tmf.wHour, tmf.wMinute, tmf.wSecond, tmf.wMilliseconds, TimeWindowBar(buffer, pFileRec->StartTime, pFileRec->EndTime) ); LargeTmp.QuadPart = pFileRec->EndTime; EndTm.dwHighDateTime = LargeTmp.HighPart; EndTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&EndTm, &EndlTm); FileTimeToSystemTime ( &EndlTm, &tmf ); duration = (pFileRec->EndTime - pFileRec->StartTime) / 10000000; fprintf(procFile, "| End Time : %2d %3s %4d %2d:%02d:%02d.%03d %81s\n" "| Duration : %-15I64u sec %68s\n" "| %75s\n", tmf.wDay, Month[tmf.wMonth], tmf.wYear, tmf.wHour, tmf.wMinute, tmf.wSecond, tmf.wMilliseconds, "|", duration, "|","|" ); } fprintf(procFile, BREAK_LINE "\n\n" ); if (flags & (TRACE_LOG_REPORT_BASIC|TRACE_LOG_REPORT_TOTALS)){ PMOF_INFO pMofInfo; WriteTransactionStatistics(); WriteTransactionCPUTime(); pMofInfo = GetMofInfoHead ((LPCGUID)&PrintJobGuid); if( pMofInfo != NULL ){ if (pMofInfo->EventCount > 0) { ReportJobInfo(); } } // PrintProcessData() must be run before others to set the process // time from the added thread times PrintProcessData(); PrintProcessSubDataExclusive(); PrintProcessSubDataInclusive(); // PrintProcessCpuTime(); PrintDiskTotals(); PrintPerThreadPerDiskTable(); } if (flags & TRACE_LOG_REPORT_MEMORY) { ReportPageFaultInfo((PCPD_USER_CONTEXT_MM) pUserContext); } if (flags & TRACE_LOG_REPORT_HARDFAULT ){ // ReportHardFaultInfo(); } if (flags & TRACE_LOG_REPORT_FILE) { // ReportHotFileInfo(PtrToUlong(pUserContext)); } fclose(procFile); } static void PrintDiskTotals() { // Print the Disk Table. PTDISK_RECORD pDisk; PLIST_ENTRY Next, Head; ULONG rio, wio; Head = &CurrentSystem.GlobalDiskListHead; Next = Head->Flink; if( Next == Head ){ return; } fprintf(procFile, BREAK_LINE "| Disk Totals %115s\n" BREAK_LINE "| Disk Name Reads Kb Writes Kb %62s\n" BREAK_LINE, "|", "|" ); Head = &CurrentSystem.GlobalDiskListHead; Next = Head->Flink; while (Next != Head) { pDisk = CONTAINING_RECORD( Next, TDISK_RECORD, Entry ); rio = pDisk->ReadCount + pDisk->HPF; wio = pDisk->WriteCount; fprintf(procFile, "| %6d %6d %6d %6d %6d %61s\n", pDisk->DiskNumber, rio, (rio == 0) ? 0 : (pDisk->ReadSize + pDisk->HPFSize) / rio, wio, (wio == 0) ? 0 : pDisk->WriteSize / wio, "|" ); Next = Next->Flink; } fprintf(procFile, BREAK_LINE "\n\n" ); } void TotalTransChildren( PLIST_ENTRY Head, ULONG *Kernel, ULONG *User, LONG level ) { PTRANS_RECORD pTrans; PLIST_ENTRY Next; Next = Head->Flink; while( Next != Head ){ pTrans = CONTAINING_RECORD( Next, TRANS_RECORD, Entry ); Next = Next->Flink; TotalTransChildren( &pTrans->SubTransListHead, Kernel, User, level+1 ); *Kernel += pTrans->KCpu; *User += pTrans->UCpu; } } void PrintTransList( PLIST_ENTRY TrHead, LONG level ) { PTRANS_RECORD pTrans; PMOF_INFO pMofInfo; ULONG Kernel; ULONG User; WCHAR str[1024]; WCHAR buffer[MAXSTR]; PLIST_ENTRY TrNext = TrHead->Flink; while( TrNext != TrHead ){ int count = 0; pTrans = CONTAINING_RECORD( TrNext, TRANS_RECORD, Entry ); TrNext = TrNext->Flink; Kernel = pTrans->KCpu; User = pTrans->UCpu; pMofInfo = GetMofInfoHead( pTrans->pGuid); if (pMofInfo == NULL) { return; } wcscpy(buffer,L""); while( (count++ < level) && (lstrlenW(buffer) < MAXSTR)){ wcscat(buffer, L" "); } wcscat( buffer, ( pMofInfo->strDescription ? pMofInfo->strDescription : CpdiGuidToString( str, &pMofInfo->Guid ) )); TotalTransChildren( &pTrans->SubTransListHead, &Kernel, &User, 0 ); fprintf( procFile, "| %-17S %6d %7d %7d %5s %5s %5s %5s %5s %5s %5s %5s %6s %6s\n", buffer, pTrans->RefCount, Kernel, User, "-", "-", "-", "-", "-", "-", "-", "-", "-", "|" ); if( level <= MAX_TRANS_LEVEL ){ PrintTransList( &pTrans->SubTransListHead, level+1 ); } } } static void PrintProcessCpuTime() { PTHREAD_RECORD pThread; PPROCESS_RECORD pProcess; ULONGLONG lLifeTime; ULONG TotalUserTime = 0; ULONG TotalKernelTime = 0; ULONG TotalCPUTime = 0; PLIST_ENTRY Next, Head; PLIST_ENTRY ThNext, ThHead; BOOL titled; ULONG usedThreadCount; ULONG ThreadCount; ULONG ProcessUTime; ULONG ProcessKTime; ULONG ThreadKCPU; ULONG ThreadUCPU; Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; if( Head == Next ){ return; } // Walk through the Process List and Print the report. fprintf(procFile, BREAK_LINE "| Process/Thread CPU Time Statistics %93s\n" BREAK_LINE "| Image Name ID Trans Inclusive CPU(ms) Disk Total Tcp Total Duration |\n" "| Kernel User Reads Kb/Op Writes Kb/Op Send Kb/Op Recv Kb/Op |\n" BREAK_LINE, "|" ); Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); lLifeTime = CalculateProcessLifeTime(pProcess); fprintf(procFile, "| %-15ws 0x%04X %6s %7d %7d %5d %5.2f %5d %5.2f %5d %8.2f %5d %8.2f %6I64u %6s\n", (pProcess->ImageName) ? pProcess->ImageName : L"Idle", pProcess->PID, "-", CalculateProcessKCPU(pProcess), CalculateProcessUCPU(pProcess), pProcess->ReadIO + pProcess->HPF, (pProcess->ReadIO + pProcess->HPF) ? (double)(pProcess->ReadIOSize + pProcess->HPFSize)/ (double)(pProcess->ReadIO + pProcess->HPF) : 0, pProcess->WriteIO, pProcess->WriteIO ? (double)pProcess->WriteIOSize/(double)pProcess->WriteIO : 0, pProcess->SendCount, pProcess->SendCount ? (double)(pProcess->SendSize / 1024)/(double)pProcess->SendCount : 0, pProcess->RecvCount, pProcess->RecvCount ? (double)(pProcess->RecvSize / 1024) / (double)pProcess->RecvCount : 0, (lLifeTime / 10000000 ), "|" ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; titled = FALSE; usedThreadCount = 0; ThreadCount = 0; ProcessUTime = 0; ProcessKTime = 0; while (ThNext != ThHead) { pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); ThreadKCPU = (pThread->KCPUEnd - pThread->KCPUStart) * CurrentSystem.TimerResolution; ThreadUCPU = (pThread->UCPUEnd - pThread->UCPUStart) * CurrentSystem.TimerResolution; if( pThread->ReadIO || pThread->WriteIO || ThreadKCPU || ThreadUCPU || pThread->SendCount || pThread->RecvCount || pThread->HPF ){ fprintf(procFile, "| 0x%04I64X %13s %5s %7d %7d %5d %5.2f %5d %5.2f %5d %8.2f %5d %8.2f %6I64u %6s\n", pThread->TID, " ", "-", ThreadKCPU, ThreadUCPU, pThread->ReadIO + pThread->HPF, pThread->ReadIO + pThread->HPF ? (double)(pThread->ReadIOSize + pThread->HPFSize)/ (double)(pThread->ReadIO + pThread->HPF) : 0, pThread->WriteIO, pThread->WriteIO ? (double)pThread->WriteIOSize/ (double)pThread->WriteIO : 0, pThread->SendCount, pThread->SendCount ? (double)(pThread->SendSize / 1024)/(double)pThread->SendCount : 0, pThread->RecvCount, pThread->RecvCount ? (double)(pThread->RecvSize / 1024)/(double)pThread->RecvCount : 0, ((pThread->TimeEnd - pThread->TimeStart) / 10000000), "|" ); } PrintTransList( &pThread->TransListHead, 0 ); TotalUserTime += ThreadUCPU; TotalKernelTime += ThreadKCPU; TotalCPUTime += ThreadKCPU + ThreadUCPU; ThNext = ThNext->Flink; } Next = Next->Flink; } fprintf(procFile, BREAK_LINE "\n\n" ); } static void PrintProcessData() { PTHREAD_RECORD pThread; PPROCESS_RECORD pProcess; PTRANS_RECORD pTrans; PLIST_ENTRY Next, Head; PLIST_ENTRY ThNext, ThHead; PLIST_ENTRY TrNext, TrHead; ULONG usedThreadCount; ULONG ThreadCount; ULONG TotalusedThreadCount = 0; ULONG TotalThreadCount = 0; ULONG ThreadUTime; ULONG ThreadKTime; ULONG ThreadUTimeTrans; ULONG ThreadKTimeTrans; ULONG ThreadUTimeNoTrans; ULONG ThreadKTimeNoTrans; ULONG CountThreadNoTrans; ULONG TotalKCPUThreadNoTrans; ULONG TotalUCPUThreadNoTrans; double PercentThreadNoTrans; ULONG CountThreadTrans; ULONG TotalKCPUThreadTrans; ULONG TotalUCPUThreadTrans; double PercentThreadTrans; ULONG TransUTime; ULONG TransKTime; ULONG Processors; ULONG TotalKThread = 0; ULONG TotalUThread = 0; ULONG TotalKTrans = 0; ULONG TotalUTrans = 0; double PerTotal = 0.0; double IdlePercent = 0.0; double percent; double percentTrans; double lDuration; Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; if( Head == Next ){ return; } Processors = CurrentSystem.NumberOfProcessors ? CurrentSystem.NumberOfProcessors : 1; lDuration = ((double)((LONGLONG)(CurrentSystem.EndTime - CurrentSystem.StartTime))) / 10000000.00; // Walk through the Process List and Print the report. fprintf(procFile, BREAK_LINE "| Image Statistics %111s\n" BREAK_LINE "| Image Name PID Threads Threads Process Transaction CPU%% %22s\n" "| Launched Used KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) %28s\n" BREAK_LINE, "|", "|", "|" ); Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; usedThreadCount = 0; ThreadCount = 0; ThreadUTime = 0; ThreadKTime = 0; ThreadUTimeTrans = 0; ThreadKTimeTrans = 0; ThreadUTimeNoTrans = 0; ThreadKTimeNoTrans = 0; TransKTime = 0; TransUTime = 0; percent = 0; CountThreadNoTrans = 0; TotalKCPUThreadNoTrans = 0; TotalUCPUThreadNoTrans = 0; CountThreadTrans = 0; TotalKCPUThreadTrans = 0; TotalUCPUThreadTrans = 0; while (ThNext != ThHead) { LIST_ENTRY NewTransList; pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); if( pThread->ReadIO || pThread->WriteIO || pThread->KCPUEnd > pThread->KCPUStart || pThread->UCPUEnd > pThread->UCPUStart || pThread->SendCount || pThread->RecvCount || pThread->HPF ) { usedThreadCount++; TotalusedThreadCount++; } ThreadCount++; TotalThreadCount++; ThreadUTime += (pThread->UCPUEnd - pThread->UCPUStart) * CurrentSystem.TimerResolution; ThreadKTime += (pThread->KCPUEnd - pThread->KCPUStart) * CurrentSystem.TimerResolution; ThreadKTimeTrans += pThread->KCPU_Trans * CurrentSystem.TimerResolution; ThreadUTimeTrans += pThread->UCPU_Trans * CurrentSystem.TimerResolution; ThreadKTimeNoTrans += pThread->KCPU_NoTrans * CurrentSystem.TimerResolution; ThreadUTimeNoTrans += pThread->UCPU_NoTrans * CurrentSystem.TimerResolution; if (pThread->KCPU_Trans + pThread->UCPU_Trans == 0) { CountThreadNoTrans ++; TotalKCPUThreadNoTrans += pThread->KCPU_NoTrans * CurrentSystem.TimerResolution; TotalUCPUThreadNoTrans += pThread->UCPU_NoTrans * CurrentSystem.TimerResolution; } else { CountThreadTrans ++; TotalKCPUThreadTrans += ( pThread->KCPU_Trans + pThread->KCPU_NoTrans) * CurrentSystem.TimerResolution; TotalUCPUThreadTrans += ( pThread->UCPU_Trans + pThread->UCPU_NoTrans) * CurrentSystem.TimerResolution; } InitializeListHead(& NewTransList); CollapseTree(& pThread->TransListHead, & NewTransList, TRUE); TrHead = & NewTransList; TrNext = TrHead->Flink; while( TrNext != TrHead ){ pTrans = CONTAINING_RECORD( TrNext, TRANS_RECORD, Entry ); TransUTime += pTrans->UCpu; TransKTime += pTrans->KCpu; TrNext = TrNext->Flink; } DeleteTransList(& NewTransList, 0); ThNext = ThNext->Flink; } TotalKThread += ThreadKTime; TotalUThread += ThreadUTime; TotalKTrans += TransKTime; TotalUTrans += TransUTime; percent = (((ThreadKTime + ThreadUTime + 0.0)/lDuration)/1000.0) * 100.0; if (ThreadKTime + ThreadUTime == 0) { percentTrans = 0.0; PercentThreadTrans = 0.0; PercentThreadNoTrans = 0.0; } else { percentTrans = ( (ThreadKTimeTrans + ThreadUTimeTrans + 0.0) / (ThreadKTime + ThreadUTime + 0.0)) * 100.00; PercentThreadTrans = ((TotalKCPUThreadTrans + TotalUCPUThreadTrans + 0.0) / (ThreadKTime + ThreadUTime + 0.0)) * 100.00; PercentThreadNoTrans = ((TotalKCPUThreadNoTrans + TotalUCPUThreadNoTrans + 0.0) / (ThreadKTime + ThreadUTime + 0.0)) * 100.00; } PerTotal += percent; fprintf(procFile, "| %-15ws 0x%08X %7d %7d %9d %9d %9d %9d %7.2f %22s\n", (pProcess->ImageName) ? pProcess->ImageName : L"Idle", pProcess->PID, ThreadCount, usedThreadCount, ThreadKTime, ThreadUTime, ThreadKTimeTrans, ThreadUTimeTrans, (percent / Processors), /*percentTrans,*/ "|" ); #if 0 fprintf(procFile, "| %6d(%10d,%10d)%7.2f%% %6d(%10d,%10d)%7.2f%% |\n", CountThreadTrans, TotalKCPUThreadTrans, TotalUCPUThreadTrans, PercentThreadTrans, CountThreadNoTrans, TotalKCPUThreadNoTrans, TotalUCPUThreadNoTrans, PercentThreadNoTrans); #endif if(pProcess->PID == 0){ IdlePercent += (percent / Processors ); } Next = Next->Flink; } fprintf(procFile, BREAK_LINE "| %-15s %8s %7d %7d %9d %9d %9d %9d Total:%7.2f%% |\n", " ", " ", TotalThreadCount, TotalusedThreadCount, TotalKThread, TotalUThread, TotalKTrans, TotalUTrans, (PerTotal/Processors) ); fprintf(procFile, BREAK_LINE "\n\n" ); } void TransInclusive( PLIST_ENTRY TrHead, ULONG level ) { ULONG Kernel, User; PLIST_ENTRY TrNext = TrHead->Flink; PMOF_INFO pMofInfo; PTRANS_RECORD pTrans; WCHAR buffer[MAXSTR]; WCHAR str[MAXSTR]; while( TrNext != TrHead ){ ULONG count = 0; pTrans = CONTAINING_RECORD( TrNext, TRANS_RECORD, Entry ); TrNext = TrNext->Flink; pMofInfo = GetMofInfoHead( pTrans->pGuid); if (pMofInfo == NULL) { return; } Kernel = pTrans->KCpu; User = pTrans->UCpu; TotalTransChildren( &pTrans->SubTransListHead, &Kernel, &User, 0 ); wcscpy(buffer,L""); while( (count++ < level) && (lstrlenW(buffer) < MAXSTR)){ wcscat(buffer, L" "); } wcscat( buffer, ( pMofInfo->strDescription ? pMofInfo->strDescription : CpdiGuidToString( str, &pMofInfo->Guid ) )); fprintf(procFile, "| %-30ws %5d %8d %8d %57s\n", buffer, pTrans->RefCount, Kernel, User, "|" ); TransInclusive( &pTrans->SubTransListHead, level+1 ); } } static void PrintProcessSubDataInclusive() { PPROCESS_RECORD pProcess; PTHREAD_RECORD pThread; PLIST_ENTRY Next, Head; PLIST_ENTRY TrNext; PLIST_ENTRY ThNext, ThHead; LIST_ENTRY NewHead; BOOL bTable = FALSE; Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head && !bTable ) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; if( pProcess->PID == 0 ){ continue; } // Total up all the threads into one list InitializeListHead( &NewHead ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; while( ThNext != ThHead ){ pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); ThNext = ThNext->Flink; CollapseTree(&pThread->TransListHead, &NewHead, FALSE ); } TrNext = NewHead.Flink; if( TrNext != &NewHead ){ bTable = TRUE; } DeleteTransList( &NewHead, 0 ); } if( !bTable ){ return; } // Walk through the Process List and Print the report. fprintf(procFile, BREAK_LINE "| Inclusive Transactions Per Process %96s\n" BREAK_LINE "| Inclusive %39s\n" "| Name PID Count KCPU(ms) UCPU(ms) %51s\n" BREAK_LINE, "|", "|", "|" ); Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; if( pProcess->PID == 0 ){ continue; } // Total up all the threads into one list InitializeListHead( &NewHead ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; while( ThNext != ThHead ){ pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); ThNext = ThNext->Flink; CollapseTree(&pThread->TransListHead, &NewHead, FALSE ); } TrNext = NewHead.Flink; if( TrNext != &NewHead ){ fprintf(procFile, "| %-30ws 0x%04X %90s\n", (pProcess->ImageName) ? pProcess->ImageName : L"Idle", pProcess->PID, "|" ); TransInclusive( &NewHead, 0 ); } DeleteTransList( &NewHead, 0 ); } fprintf(procFile, BREAK_LINE "\n\n" ); } static void PrintProcessSubDataExclusive() { PPROCESS_RECORD pProcess; PTRANS_RECORD pTrans; PTHREAD_RECORD pThread; PLIST_ENTRY ThNext, ThHead; PMOF_INFO pMofInfo; PLIST_ENTRY Next, Head; PLIST_ENTRY TrNext; LIST_ENTRY NewHead; double percent, percentCPU, totalPerCPU; double processPart; double transPart; double totalPercent; double trans, KCPU, UCPU; WCHAR str[1024]; double duration = ((double)((LONGLONG)(CurrentSystem.EndTime - CurrentSystem.StartTime))) / 10000000.00; BOOL bTable = FALSE; Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head && !bTable ) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; if( pProcess->PID == 0 ){ continue; } InitializeListHead( &NewHead ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; while( ThNext != ThHead ){ pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); ThNext = ThNext->Flink; CollapseTree(&pThread->TransListHead, &NewHead, TRUE ); } TrNext = NewHead.Flink; if( TrNext != &NewHead ){ bTable = TRUE; } DeleteTransList( &NewHead, 0 ); } if( !bTable ){ return; } // Walk through the Process List and Print the report. if( ReportFlags & TRACE_LOG_REPORT_TOTALS ){ fprintf(procFile, BREAK_LINE "| Exclusive Transactions Per Process %96s\n" BREAK_LINE "| Exclusive %54s\n" "| Name PID Trans Trans/sec KCPU(ms) UCPU(ms) Process CPU%% CPU%% %20s\n" BREAK_LINE, "|", "|", "|" ); }else{ fprintf(procFile, BREAK_LINE "| Exclusive Transactions Per Process %96s\n" BREAK_LINE "| Exclusive/Trans %54s\n" "| Name PID Trans Trans/sec KCPU(ms) UCPU(ms) Process CPU%% CPU%% %20s\n" BREAK_LINE, "|", "|", "|" ); } Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { BOOL titled = FALSE; pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); Next = Next->Flink; if( pProcess->PID == 0 ){ continue; } InitializeListHead( &NewHead ); ThHead = &pProcess->ThreadListHead; ThNext = ThHead->Flink; while( ThNext != ThHead ){ pThread = CONTAINING_RECORD( ThNext, THREAD_RECORD, Entry ); ThNext = ThNext->Flink; CollapseTree(&pThread->TransListHead, &NewHead, TRUE ); } TrNext = NewHead.Flink; totalPercent = 0.0; totalPerCPU = 0.0; while( TrNext != &NewHead ){ if(!titled){ fprintf(procFile, "| %-15ws 0x%04X %105s\n", (pProcess->ImageName) ? pProcess->ImageName : L"Idle", pProcess->PID, "|" ); titled = TRUE; } pTrans = CONTAINING_RECORD( TrNext, TRANS_RECORD, Entry ); TrNext = TrNext->Flink; pMofInfo = GetMofInfoHead( pTrans->pGuid); if (pMofInfo == NULL) { return; } transPart = pTrans->UCpu + pTrans->KCpu; processPart = CalculateProcessKCPU(pProcess) + CalculateProcessUCPU(pProcess); percentCPU = ((((double)pTrans->KCpu + (double)pTrans->UCpu ) / 10.0 ) / duration) / ((double) CurrentSystem.NumberOfProcessors); totalPerCPU += percentCPU; if(processPart) percent = (transPart/processPart) * 100.0; else percent = 0; totalPercent += percent; if (!(ReportFlags & TRACE_LOG_REPORT_TOTALS) ){ if (pTrans->RefCount == 0 && pTrans->RefCount1 == 0) KCPU = UCPU = 0.0; else if (pTrans->RefCount == 0) { KCPU = (double) pTrans->KCpu; UCPU = (double) pTrans->UCpu; } else { KCPU = (double) pTrans->KCpu / (double) pTrans->RefCount; UCPU = (double) pTrans->UCpu / (double) pTrans->RefCount; } } else{ KCPU = (double)pTrans->KCpu; UCPU = (double)pTrans->UCpu; } trans = (double)pTrans->RefCount / duration; fprintf(procFile, "| %-30ws %5d %7.2f %8.0f %8.0f %7.2f %7.2f %19s\n", (pMofInfo->strDescription != NULL) ? pMofInfo->strDescription : CpdiGuidToString( str, &pMofInfo->Guid ), pTrans->RefCount, trans, KCPU, UCPU, percent, percentCPU, "|" ); } if( titled ){ fprintf( procFile, "| %84s ------- ------ %20s\n" "| %84s %7.2f%% %7.2f%% %19s\n", " ", "|", " ", totalPercent, totalPerCPU, "|" ); } DeleteTransList( &NewHead, 0 ); } fprintf(procFile, BREAK_LINE "\n\n" ); } static void PrintPerThreadPerDiskTable( ) { PPROCESS_RECORD pProcess; PTDISK_RECORD pDisk; PLIST_ENTRY Next, Head; PLIST_ENTRY GNext, GHead; PLIST_ENTRY DiNext, DiHead; ULONG rio, wio, DiskNumber; BOOL bTable = FALSE; // Walk through the Process List and Print the report. GHead = &CurrentSystem.GlobalDiskListHead; GNext = GHead->Flink; while (GNext != GHead && !bTable) { pDisk = CONTAINING_RECORD( GNext, TDISK_RECORD, Entry); DiskNumber = pDisk->DiskNumber; Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); DiHead = &pProcess->DiskListHead; DiNext = DiHead->Flink; while (DiNext != DiHead && !bTable) { pDisk = CONTAINING_RECORD( DiNext, TDISK_RECORD, Entry ); if (DiskNumber != pDisk->DiskNumber) { DiNext = DiNext->Flink; continue; }else{ bTable = TRUE; break; } } Next = Next->Flink; } GNext = GNext->Flink; } if( !bTable ){ return; } GHead = &CurrentSystem.GlobalDiskListHead; GNext = GHead->Flink; while (GNext != GHead) { pDisk = CONTAINING_RECORD( GNext, TDISK_RECORD, Entry); DiskNumber = pDisk->DiskNumber; fprintf(procFile, BREAK_LINE "| Disk %3d %116s\n" BREAK_LINE "| Authority PID Image Name Read Kb Write Kb %50s\n" "| Count Count %50s\n" BREAK_LINE, DiskNumber, "|", "|", "|" ); Head = &CurrentSystem.ProcessListHead; Next = Head->Flink; while (Next != Head) { pProcess = CONTAINING_RECORD( Next, PROCESS_RECORD, Entry ); DiHead = &pProcess->DiskListHead; DiNext = DiHead->Flink; while (DiNext != DiHead) { pDisk = CONTAINING_RECORD( DiNext, TDISK_RECORD, Entry ); if (DiskNumber != pDisk->DiskNumber) { DiNext = DiNext->Flink; continue; } rio = pDisk->ReadCount + pDisk->HPF; wio = pDisk->WriteCount; fprintf(procFile, "| %-22ws 0x%04X %-16ws", (pProcess->UserName) ? pProcess->UserName : L"-", pProcess->PID, pProcess->ImageName ? pProcess->ImageName : L"-" ); fprintf(procFile, "%6d %6d %6d %6d %52s\n", rio, (rio == 0) ? 0 : (pDisk->ReadSize + pDisk->HPFSize) / rio, wio, (wio == 0) ? 0 : pDisk->WriteSize / wio, "|"); DiNext = DiNext->Flink; } Next = Next->Flink; } fprintf(procFile, BREAK_LINE "\n\n" ); GNext = GNext->Flink; } } static void WriteTransactionStatistics() { PLIST_ENTRY Head, Next; PLIST_ENTRY Dhead, DNext; ULONG trans; double KCPU, UCPU, PerCpu; double RIO, WIO, Send, Recv; PMOF_INFO pMofInfo; PMOF_DATA pMofData; double AvgRT; double TransRate; WCHAR str[1024]; double duration = ((double)((LONGLONG)(CurrentSystem.EndTime - CurrentSystem.StartTime))) / 10000000.00; BOOL bTable = FALSE; Head = &CurrentSystem.EventListHead; Next = Head->Flink; while (Head != Next && !bTable ) { pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Dhead = &pMofInfo->DataListHead; DNext = Dhead->Flink; while(DNext!=Dhead){ pMofData = CONTAINING_RECORD(DNext, MOF_DATA, Entry); trans = pMofData->CompleteCount; if (trans > 0) { bTable = TRUE; break; } DNext = DNext->Flink; } Next = Next->Flink; } if( !bTable ){ return; } if( ReportFlags & TRACE_LOG_REPORT_TOTALS ){ fprintf( procFile, BREAK_LINE "| Transaction Statistics %103s\n" BREAK_LINE "| Transaction Trans Response Transaction CPU %% Disk Total Tcp Total %20s\n" "| Time(ms) Rate/sec Reads Writes Sends Recieves %16s\n" BREAK_LINE, "|", "|", "|" ); }else{ fprintf( procFile, BREAK_LINE "| Transaction Statistics %103s\n" BREAK_LINE "| Transaction Trans Response Transaction CPU %% Disk/Trans Tcp/Trans %22s\n" "| Time(ms) Rate/sec Reads Writes Sends Recieves %17s\n" BREAK_LINE, "|", "|", "|" ); } Head = &CurrentSystem.EventListHead; Next = Head->Flink; while (Head != Next) { pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Dhead = &pMofInfo->DataListHead; DNext = Dhead->Flink; while(DNext!=Dhead){ pMofData = CONTAINING_RECORD(DNext, MOF_DATA, Entry); trans = pMofData->CompleteCount; if (trans > 0) { UCPU = pMofData->UserCPU; KCPU = pMofData->KernelCPU; PerCpu = (((UCPU + KCPU)/1000.0)/duration) * 100.0; UCPU /= trans; KCPU /= trans; if(CurrentSystem.NumberOfProcessors) PerCpu/=CurrentSystem.NumberOfProcessors; if( ReportFlags & TRACE_LOG_REPORT_TOTALS ){ RIO = pMofData->ReadCount; WIO = pMofData->WriteCount; Send = pMofData->SendCount; Recv = pMofData->RecvCount; }else{ RIO = pMofData->ReadCount / trans; WIO = pMofData->WriteCount / trans; Send = pMofData->SendCount / trans; Recv = pMofData->RecvCount / trans; } AvgRT = (double)pMofData->TotalResponseTime; AvgRT /= trans; TransRate = ( (float)trans / duration ); fprintf(procFile, "| %-28ws %7d %7.0f ", (pMofInfo->strDescription) ? pMofInfo->strDescription : CpdiGuidToString( str, &pMofInfo->Guid ), pMofData->CompleteCount, AvgRT ); fprintf(procFile, " %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %21s\n", TransRate, PerCpu, RIO, WIO, Send, Recv, "|" ); } DNext = DNext->Flink; } Next = Next->Flink; } fprintf(procFile, BREAK_LINE "\n\n" ); } static void WriteTransactionCPUTime() { PLIST_ENTRY Head, Next; PLIST_ENTRY Dhead, DNext; double KCPU, UCPU; PMOF_INFO pMofInfo; PMOF_DATA pMofData; double trans; double PerCpu; WCHAR str[1024]; double duration = ((double)((LONGLONG)(CurrentSystem.EndTime - CurrentSystem.StartTime))) / 10000000.00; BOOL bTable = FALSE; Head = &CurrentSystem.EventListHead; Next = Head->Flink; while (Head != Next && !bTable ) { pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Dhead = &pMofInfo->DataListHead; DNext = Dhead->Flink; while(DNext!=Dhead){ pMofData = CONTAINING_RECORD(DNext, MOF_DATA, Entry); trans = (double)pMofData->CompleteCount; if (trans > 0) { bTable = TRUE; break; } DNext = DNext->Flink; } Next = Next->Flink; } if( !bTable ){ return; } if( !(ReportFlags & TRACE_LOG_REPORT_TOTALS) ){ fprintf( procFile, BREAK_LINE "| Transaction CPU Utilization |\n" BREAK_LINE "| Transaction Trans/sec Minimum Maximum Per Transaction Total CPU%% |\n" "| KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) |\n" BREAK_LINE ); }else{ fprintf( procFile, BREAK_LINE "| Transaction CPU Utilization |\n" BREAK_LINE "| Transaction Trans Minimum Maximum Per Transaction Total CPU%% |\n" "| KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) KCPU(ms) UCPU(ms) |\n" BREAK_LINE ); } Head = &CurrentSystem.EventListHead; Next = Head->Flink; while (Head != Next) { pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Dhead = &pMofInfo->DataListHead; DNext = Dhead->Flink; while(DNext!=Dhead){ pMofData = CONTAINING_RECORD(DNext, MOF_DATA, Entry); trans = (double)pMofData->CompleteCount; if (trans > 0) { UCPU = pMofData->UserCPU; UCPU /= trans; KCPU = pMofData->KernelCPU; KCPU /= trans; PerCpu = (((pMofData->UserCPU + pMofData->KernelCPU + 0.0)/1000.0)/duration) * 100.0; if( !(ReportFlags & TRACE_LOG_REPORT_TOTALS) ){ trans /= duration; } if(CurrentSystem.NumberOfProcessors) PerCpu/=CurrentSystem.NumberOfProcessors; fprintf(procFile, "| %-28ws %7.2f %7d %7d %7d %7d %7.0f %7.0f %7d %7d %6.2f |\n", (pMofInfo->strDescription) ? pMofInfo->strDescription : CpdiGuidToString( str, &pMofInfo->Guid ), trans, pMofData->MinKCpu, pMofData->MinUCpu, pMofData->MaxKCpu, pMofData->MaxUCpu, KCPU, UCPU, pMofData->KernelCPU, pMofData->UserCPU, PerCpu ); } DNext = DNext->Flink; } Next = Next->Flink; } fprintf(procFile, BREAK_LINE "\n\n" ); } PWCHAR CpdiGuidToString( PWCHAR s, LPGUID piid ) { swprintf(s, L"{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}", piid->Data1, piid->Data2, piid->Data3, piid->Data4[0], piid->Data4[1], piid->Data4[2], piid->Data4[3], piid->Data4[4], piid->Data4[5], piid->Data4[6], piid->Data4[7]); return(s); } /*============================================================================= */ #define MAX_RECORDS 65536 #define MAX_LOGS 1024 * 1024 typedef struct _PTR_RECORD { PVOID ptrRecord; ULONG keySort; } PTR_RECORD, * PPTR_RECORD; static PPTR_RECORD PtrBuffer = NULL; static ULONG PtrMax = MAX_LOGS; static ULONG PtrTotal = 0; static ULONG PtrIndex; static PPROCESS_RECORD * ProcessList = NULL; static WCHAR ** ModuleList = NULL; static ULONG lCurrentMax = MAX_RECORDS; static ULONG lTotal = 0; void OutputTitle( MM_REPORT_TYPE reportNow, MM_REPORT_SORT_KEY sortNow, PWCHAR strImgName ) { switch (reportNow) { case REPORT_SUMMARY_PROCESS: fprintf(procFile, "Page Fault Summary for Processes, "); break; case REPORT_SUMMARY_MODULE: fprintf(procFile, "Page Fault Summary for Loaded Modules, "); break; case REPORT_LIST_PROCESS: fprintf(procFile, "Page Fault Rundown for "); if (strImgName) { fprintf(procFile, "process '%ws', ", strImgName); } else { fprintf(procFile, "all processes, "); } break; case REPORT_LIST_MODULE: fprintf(procFile, "Page Fault rundown for "); if (strImgName) { fprintf(procFile, "loaded module '%ws', ", strImgName); } else { fprintf(procFile, "all loaded modules, "); } break; } switch (sortNow) { case REPORT_SORT_ALL: fprintf(procFile, "sorted by all page faults total."); break; case REPORT_SORT_HPF: fprintf(procFile, "sorted by HardPageFault total."); break; case REPORT_SORT_TF: fprintf(procFile, "sorted by TransitionFault total."); break; case REPORT_SORT_DZF: fprintf(procFile, "sorted by DemandZeroFault total."); break; case REPORT_SORT_COW: fprintf(procFile, "sorted by CopyOnWrite total."); break; } fprintf(procFile, "\n"); } void OutputModuleHeader() { fprintf(procFile, "=======================================================================================\n"); fprintf(procFile, " Module Name Base Module Fault Outside Image Fault Inside Image \n"); fprintf(procFile, " Address Size HPF TF DZF COW HPF TF DZF COW\n"); fprintf(procFile, "=======================================================================================\n"); } void OutputModuleRecord(PMODULE_RECORD pModule) { fprintf(procFile, "%-12ws 0x%08x%8d %6d %6d %6d %6d %6d %6d %6d %6d\n", pModule->strModuleName, pModule->lBaseAddress, pModule->lModuleSize, pModule->lDataFaultHF, pModule->lDataFaultTF, pModule->lDataFaultDZF, pModule->lDataFaultCOW, pModule->lCodeFaultHF, pModule->lCodeFaultTF, pModule->lCodeFaultDZF, pModule->lCodeFaultCOW); } void OutputTotal( BOOLEAN fIsModule, ULONG totalDataFaultHF, ULONG totalDataFaultTF, ULONG totalDataFaultDZF, ULONG totalDataFaultCOW, ULONG totalCodeFaultHF, ULONG totalCodeFaultTF, ULONG totalCodeFaultDZF, ULONG totalCodeFaultCOW ) { if (fIsModule) { fprintf(procFile, "=======================================================================================\n"); fprintf(procFile, "Total %6d %6d %6d %6d %6d %6d %6d %6d\n", totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); fprintf(procFile, "=======================================================================================\n"); } else { fprintf(procFile, "=============================================================================\n"); fprintf(procFile, "Total %6d %6d %6d %6d %6d %6d %6d %6d\n", totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); fprintf(procFile, "=============================================================================\n"); } } void OutputProcessHeader() { fprintf(procFile, "=============================================================================\n"); fprintf(procFile, " Process Image Name Fault Outside Image Fault Inside Image \n"); fprintf(procFile, " ID HPF TF DZF COW HPF TF DZF COW\n"); fprintf(procFile, "=============================================================================\n"); } void OutputProcessRecord(PPROCESS_RECORD pProcess) { fprintf(procFile, "0x%06x %-12ws %6d %6d %6d %6d %6d %6d %6d %6d\n", pProcess->PID, pProcess->ImageName, pProcess->lDataFaultHF, pProcess->lDataFaultTF, pProcess->lDataFaultDZF, pProcess->lDataFaultCOW, pProcess->lCodeFaultHF, pProcess->lCodeFaultTF, pProcess->lCodeFaultDZF, pProcess->lCodeFaultCOW); } void OutputModuleProcessRecord(PPROCESS_RECORD pProcess, PMODULE_RECORD pModule) { fprintf(procFile, "0x%06x %-12ws %6d %6d %6d %6d %6d %6d %6d %6d\n", pProcess->PID, pProcess->ImageName, pModule->lDataFaultHF, pModule->lDataFaultTF, pModule->lDataFaultDZF, pModule->lDataFaultCOW, pModule->lCodeFaultHF, pModule->lCodeFaultTF, pModule->lCodeFaultDZF, pModule->lCodeFaultCOW); } BOOLEAN ModuleHasPageFault(PMODULE_RECORD pModule) { return (BOOLEAN) (pModule->lDataFaultHF + pModule->lDataFaultTF + pModule->lDataFaultDZF + pModule->lDataFaultCOW + pModule->lCodeFaultHF + pModule->lCodeFaultTF + pModule->lCodeFaultDZF + pModule->lCodeFaultCOW != 0); } BOOLEAN ProcessHasPageFault(PPROCESS_RECORD pProcess) { return (BOOLEAN) (pProcess->lDataFaultHF + pProcess->lDataFaultTF + pProcess->lDataFaultDZF + pProcess->lDataFaultCOW + pProcess->lCodeFaultHF + pProcess->lCodeFaultTF + pProcess->lCodeFaultDZF + pProcess->lCodeFaultCOW != 0); } ULONG GetModuleSortKey(PMODULE_RECORD pModule, MM_REPORT_SORT_KEY keySort) { ULONG keyValue = 0; switch (keySort) { case REPORT_SORT_ALL: keyValue = pModule->lDataFaultHF + pModule->lCodeFaultHF + pModule->lDataFaultTF + pModule->lCodeFaultTF + pModule->lDataFaultDZF + pModule->lCodeFaultDZF + pModule->lDataFaultCOW + pModule->lCodeFaultCOW; break; case REPORT_SORT_HPF: keyValue = pModule->lDataFaultHF + pModule->lCodeFaultHF; break; case REPORT_SORT_TF: keyValue = pModule->lDataFaultTF + pModule->lCodeFaultTF; break; case REPORT_SORT_DZF: keyValue = pModule->lDataFaultDZF + pModule->lCodeFaultDZF; break; case REPORT_SORT_COW: keyValue = pModule->lDataFaultCOW + pModule->lCodeFaultCOW; break; } return keyValue; } ULONG GetProcessSortKey(PPROCESS_RECORD pProcess, MM_REPORT_SORT_KEY keySort) { ULONG keyValue = 0; switch (keySort) { case REPORT_SORT_ALL: keyValue = pProcess->lDataFaultHF + pProcess->lCodeFaultHF + pProcess->lDataFaultTF + pProcess->lCodeFaultTF + pProcess->lDataFaultDZF + pProcess->lCodeFaultDZF + pProcess->lDataFaultCOW + pProcess->lCodeFaultCOW; break; case REPORT_SORT_HPF: keyValue = pProcess->lDataFaultHF + pProcess->lCodeFaultHF; break; case REPORT_SORT_TF: keyValue = pProcess->lDataFaultTF + pProcess->lCodeFaultTF; break; case REPORT_SORT_DZF: keyValue = pProcess->lDataFaultDZF + pProcess->lCodeFaultDZF; break; case REPORT_SORT_COW: keyValue = pProcess->lDataFaultCOW + pProcess->lCodeFaultCOW; break; } return keyValue; } ULONG GetModuleListIndex(PWCHAR strModuleName) { ULONG lIndex; for (lIndex = 0; lIndex < lTotal; lIndex ++) { if (_wcsicmp(ModuleList[lIndex], strModuleName) == 0) { break; } } return (lIndex); } ULONG GetProcessListIndex(PPROCESS_RECORD pProcess) { ULONG lIndex; for (lIndex = 0; lIndex < lTotal; lIndex ++) { if (ProcessList[lIndex] == pProcess) { break; } } return (lIndex); } int __cdecl CompareModuleRecord(const void * p1, const void * p2) { PPTR_RECORD pp1 = (PPTR_RECORD) p1; PPTR_RECORD pp2 = (PPTR_RECORD) p2; PMODULE_RECORD pModule1 = pp1->ptrRecord; PMODULE_RECORD pModule2 = pp2->ptrRecord; LONG diffFault = pp2->keySort - pp1->keySort; if (diffFault == 0) { diffFault = wcscmp(pModule1->strModuleName, pModule2->strModuleName); } return diffFault; } int __cdecl CompareProcessRecord(const void * p1, const void * p2) { PPTR_RECORD pp1 = (PPTR_RECORD) p1; PPTR_RECORD pp2 = (PPTR_RECORD) p2; PPROCESS_RECORD pProcess1 = pp1->ptrRecord; PPROCESS_RECORD pProcess2 = pp2->ptrRecord; LONG diffFault = pp2->keySort - pp1->keySort; if (diffFault == 0) { diffFault = _wcsicmp(pProcess1->ImageName, pProcess2->ImageName); } return diffFault; } int __cdecl CompareProcessModuleRecord(const void * p1, const void * p2) { PPTR_RECORD pp1 = (PPTR_RECORD) p1; PPTR_RECORD pp2 = (PPTR_RECORD) p2; PMODULE_RECORD pModule1 = pp1->ptrRecord; PMODULE_RECORD pModule2 = pp2->ptrRecord; LONG diffFault = GetProcessListIndex(pModule1->pProcess) - GetProcessListIndex(pModule2->pProcess); if (diffFault == 0) { diffFault = pp2->keySort - pp1->keySort; if (diffFault == 0) { diffFault = wcscmp(pModule1->strModuleName, pModule2->strModuleName); } } return diffFault; } int __cdecl CompareModuleProcessRecord(const void * p1, const void * p2) { PPTR_RECORD pp1 = (PPTR_RECORD) p1; PPTR_RECORD pp2 = (PPTR_RECORD) p2; PMODULE_RECORD pModule1 = pp1->ptrRecord; PMODULE_RECORD pModule2 = pp2->ptrRecord; LONG diffFault = GetModuleListIndex(pModule1->strModuleName) - GetModuleListIndex(pModule2->strModuleName); if (diffFault == 0) { diffFault = pp2->keySort - pp1->keySort; if (diffFault == 0) { if (pModule1->pProcess && pModule2->pProcess) { diffFault = (int) ( pModule1->pProcess->PID - pModule2->pProcess->PID); } else if (pModule1->pProcess) { diffFault = -1; } else if (pModule2->pProcess) { diffFault = 1; } else { diffFault = 0; } } } return diffFault; } BOOLEAN GetModuleSummary(WCHAR * strModuleName, MM_REPORT_SORT_KEY sortNow) { PLIST_ENTRY pHead = & CurrentSystem.GlobalModuleListHead; PLIST_ENTRY pNext = pHead->Flink; PMODULE_RECORD pModule; BOOLEAN fDone = FALSE; while (!fDone) { for (PtrTotal = 0, fDone = TRUE; pNext != pHead; pNext = pNext->Flink) { if (PtrTotal == PtrMax) { fDone = FALSE; break; } pModule = CONTAINING_RECORD(pNext, MODULE_RECORD, Entry); if ( (!strModuleName || (pModule->strModuleName && !_wcsicmp(strModuleName, pModule->strModuleName))) && (ModuleHasPageFault(pModule))) { PtrBuffer[PtrTotal].ptrRecord = (PVOID) pModule; PtrBuffer[PtrTotal].keySort = GetModuleSortKey(pModule, sortNow); PtrTotal ++; } } if (!fDone) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); PtrMax += MAX_LOGS; PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if (PtrBuffer == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } if (PtrTotal > 1) { qsort((void *) PtrBuffer, (size_t) PtrTotal, (size_t) sizeof(PTR_RECORD), CompareModuleRecord); } Cleanup: return fDone; } BOOLEAN GetProcessSummary(WCHAR * strImgName, MM_REPORT_SORT_KEY sortNow) { PLIST_ENTRY pHead = & CurrentSystem.ProcessListHead; PLIST_ENTRY pNext = pHead->Flink; PPROCESS_RECORD pProcess; BOOLEAN fDone = FALSE; while (!fDone) { for (fDone = TRUE, PtrTotal = 0; pNext != pHead; pNext = pNext->Flink) { if (PtrTotal == PtrMax) { fDone = FALSE; break; } pProcess = CONTAINING_RECORD(pNext, PROCESS_RECORD, Entry); if ( (!strImgName || (pProcess->ImageName && !_wcsicmp(strImgName, pProcess->ImageName))) && (ProcessHasPageFault(pProcess))) { PtrBuffer[PtrTotal].ptrRecord = (PVOID) pProcess; PtrBuffer[PtrTotal].keySort = GetProcessSortKey(pProcess, sortNow); PtrTotal ++; } } if (!fDone) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); PtrMax += MAX_LOGS; PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if (PtrBuffer == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } if (PtrTotal > 1) { qsort((void *) PtrBuffer, (size_t) PtrTotal, (size_t) sizeof(PTR_RECORD), CompareProcessRecord); } Cleanup: return fDone; } BOOLEAN GoThroughAllProcessModule( BOOLEAN fProcessList, MM_REPORT_SORT_KEY sortNow ) { BOOLEAN fDone = FALSE; PLIST_ENTRY pProcessHead = & CurrentSystem.ProcessListHead; PLIST_ENTRY pProcessNext = pProcessHead->Flink; PLIST_ENTRY pModuleHead; PLIST_ENTRY pModuleNext; PPROCESS_RECORD pProcess; PMODULE_RECORD pModule; while (!fDone) { for (PtrTotal = 0, fDone = TRUE; fDone && pProcessNext != pProcessHead; pProcessNext = pProcessNext->Flink) { pProcess = CONTAINING_RECORD(pProcessNext, PROCESS_RECORD, Entry); if (fProcessList && GetProcessListIndex(pProcess) == lTotal) { continue; } pModuleHead = & pProcess->ModuleListHead; for (pModuleNext = pModuleHead->Flink; pModuleNext != pModuleHead; pModuleNext = pModuleNext->Flink) { if (PtrTotal == PtrMax) { fDone = FALSE; break; } pModule = CONTAINING_RECORD(pModuleNext, MODULE_RECORD, Entry); if ( !fProcessList && GetModuleListIndex(pModule->strModuleName) == lTotal) { continue; } if (ModuleHasPageFault(pModule)) { PtrBuffer[PtrTotal].ptrRecord = (PVOID) pModule; PtrBuffer[PtrTotal].keySort = GetModuleSortKey(pModule, sortNow); PtrTotal ++; } } } if (!fDone) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); PtrMax += MAX_LOGS; PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if (PtrBuffer == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } Cleanup: return fDone; } BOOLEAN GetModuleList(WCHAR * strImgName, MM_REPORT_SORT_KEY sortNow) { PMODULE_RECORD pModule; BOOLEAN fResult = GetModuleSummary(strImgName, sortNow); ULONG lAllocSize = sizeof(ULONG) * lCurrentMax; ULONG lIndex; if (!fResult) { goto Cleanup; } // collect information from ModuleSummary and store in ModuleList array // ASSERT(!ModuleList); ModuleList = (PWCHAR *) VirtualAlloc( NULL, lAllocSize, MEM_COMMIT, PAGE_READWRITE); if (ModuleList == NULL) { fResult = FALSE; goto Cleanup; } for (fResult = FALSE; !fResult;) { for (fResult = TRUE, lTotal = 0, PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++, lTotal ++) { if (lTotal == MAX_RECORDS) { fResult = FALSE; break; } pModule = (PMODULE_RECORD) PtrBuffer[PtrIndex].ptrRecord; ModuleList[lTotal] = (PWCHAR) VirtualAlloc( NULL, sizeof(WCHAR) * (lstrlenW(pModule->strModuleName) + 1), MEM_COMMIT, PAGE_READWRITE); if (ModuleList[lTotal] == NULL) { fResult = FALSE; break; } wcscpy(ModuleList[lTotal], pModule->strModuleName); } if (!fResult) { for (lIndex = 0; lIndex < lTotal; lIndex ++) { VirtualFree(ModuleList[lIndex], 0, MEM_RELEASE); } VirtualFree(ModuleList, 0, MEM_RELEASE); lCurrentMax += MAX_RECORDS; lAllocSize = sizeof(ULONG) * lCurrentMax; ModuleList = VirtualAlloc(NULL, lAllocSize, MEM_COMMIT, PAGE_READWRITE); if (ModuleList == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } // go through ModuleList of each PROCESS_RECORD based on the information // from ModuleList array // fResult = GoThroughAllProcessModule(FALSE, sortNow); if (fResult && PtrTotal > 1) { qsort((void *) PtrBuffer, (size_t) PtrTotal, (size_t) sizeof(PTR_RECORD), CompareModuleProcessRecord); } Cleanup: if (ModuleList) { for (lIndex = 0; lIndex < lTotal; lIndex ++) { VirtualFree(ModuleList[lIndex], 0, MEM_RELEASE); } VirtualFree(ModuleList, 0, MEM_RELEASE); ModuleList = NULL; } return fResult; } BOOLEAN GetProcessList(WCHAR * strImgName, MM_REPORT_SORT_KEY sortNow) { PPROCESS_RECORD pProcess; BOOLEAN fResult = GetProcessSummary(strImgName, sortNow); ULONG lAllocSize = sizeof(PPROCESS_RECORD) * lCurrentMax; if (!fResult) { goto Cleanup; } // collect information from ProcessSummary and store in ProcessList array // ASSERT(!ProcessList); ProcessList = (PPROCESS_RECORD *) VirtualAlloc( NULL, lAllocSize, MEM_COMMIT, PAGE_READWRITE); if (ProcessList == NULL) { fResult = FALSE; goto Cleanup; } for (fResult = FALSE; !fResult;) { for (fResult = TRUE, lTotal = 0, PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++, lTotal ++) { if (lTotal == MAX_RECORDS) { fResult = FALSE; break; } pProcess = (PPROCESS_RECORD) PtrBuffer[PtrIndex].ptrRecord; ProcessList[lTotal] = pProcess; } if (!fResult) { VirtualFree(ProcessList, 0, MEM_RELEASE); lCurrentMax += MAX_RECORDS; lAllocSize = sizeof(ULONG) * lCurrentMax; ProcessList = VirtualAlloc(NULL, lAllocSize, MEM_COMMIT, PAGE_READWRITE); if (ProcessList == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } // go through ModuleList of each PROCESS_RECORD based on the information // from ProcessList // fResult = GoThroughAllProcessModule(TRUE, sortNow); if (fResult && PtrTotal > 1) { qsort((void *) PtrBuffer, (size_t) PtrTotal, (size_t) sizeof(PTR_RECORD), CompareProcessModuleRecord); } Cleanup: if (ProcessList) { VirtualFree(ProcessList, 0, MEM_RELEASE); ProcessList = NULL; } return fResult; } void ReportPageFaultInfo(PCPD_USER_CONTEXT_MM pUserContext) { PPROCESS_RECORD pProcessPrev = NULL; WCHAR Module_Prev[256]; MM_REPORT_TYPE reportNow = REPORT_SUMMARY_PROCESS; MM_REPORT_SORT_KEY sortNow = REPORT_SORT_ALL; PWCHAR strImgName = NULL; ULONG totalDataFaultHF = 0; ULONG totalDataFaultTF = 0; ULONG totalDataFaultDZF = 0; ULONG totalDataFaultCOW = 0; ULONG totalCodeFaultHF = 0; ULONG totalCodeFaultTF = 0; ULONG totalCodeFaultDZF = 0; ULONG totalCodeFaultCOW = 0; PPROCESS_RECORD pProcess; PMODULE_RECORD pModule; return; ASSERT(!PtrBuffer); PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if (PtrBuffer == NULL) { goto Cleanup; } if (pUserContext) { reportNow = pUserContext->reportNow; sortNow = pUserContext->sortNow; strImgName = pUserContext->strImgName; } OutputTitle(reportNow, sortNow, strImgName); switch (reportNow) { case REPORT_SUMMARY_MODULE: if( FALSE == GetModuleSummary(NULL, sortNow) ){ break; } OutputModuleHeader(); totalDataFaultHF = totalDataFaultTF = totalDataFaultDZF = totalDataFaultCOW = totalCodeFaultHF = totalCodeFaultTF = totalCodeFaultDZF = totalCodeFaultCOW = 0; for (PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++) { pModule = (PMODULE_RECORD) PtrBuffer[PtrIndex].ptrRecord; OutputModuleRecord(pModule); totalDataFaultHF += pModule->lDataFaultHF; totalDataFaultTF += pModule->lDataFaultTF; totalDataFaultDZF += pModule->lDataFaultDZF; totalDataFaultCOW += pModule->lDataFaultCOW; totalCodeFaultHF += pModule->lCodeFaultHF; totalCodeFaultTF += pModule->lCodeFaultTF; totalCodeFaultDZF += pModule->lCodeFaultDZF; totalCodeFaultCOW += pModule->lCodeFaultCOW; } OutputTotal(TRUE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); break; case REPORT_SUMMARY_PROCESS: if( FALSE == GetProcessSummary(NULL, sortNow) ){ break; } OutputProcessHeader(); totalDataFaultHF = totalDataFaultTF = totalDataFaultDZF = totalDataFaultCOW = totalCodeFaultHF = totalCodeFaultTF = totalCodeFaultDZF = totalCodeFaultCOW = 0; for (PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++) { pProcess = (PPROCESS_RECORD) PtrBuffer[PtrIndex].ptrRecord; OutputProcessRecord(pProcess); totalDataFaultHF += pProcess->lDataFaultHF; totalDataFaultTF += pProcess->lDataFaultTF; totalDataFaultDZF += pProcess->lDataFaultDZF; totalDataFaultCOW += pProcess->lDataFaultCOW; totalCodeFaultHF += pProcess->lCodeFaultHF; totalCodeFaultTF += pProcess->lCodeFaultTF; totalCodeFaultDZF += pProcess->lCodeFaultDZF; totalCodeFaultCOW += pProcess->lCodeFaultCOW; } OutputTotal(FALSE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); break; case REPORT_LIST_PROCESS: if( FALSE == GetProcessList(strImgName, sortNow) ){ break; } if (PtrTotal > 0) { for (PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++) { pModule = (PMODULE_RECORD) PtrBuffer[PtrIndex].ptrRecord; pProcess = pModule->pProcess; ASSERT(pProcess); if (PtrIndex == 0 || pProcessPrev != pProcess) { if (PtrIndex != 0) { OutputTotal(TRUE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); } totalDataFaultHF = totalDataFaultTF = totalDataFaultDZF = totalDataFaultCOW = totalCodeFaultHF = totalCodeFaultTF = totalCodeFaultDZF = totalCodeFaultCOW = 0; pProcessPrev = pModule->pProcess; fprintf(procFile, "\nProcess 0x%08x Image: %-20ws\n", pProcess->PID, pProcess->ImageName); OutputModuleHeader(); } OutputModuleRecord(pModule); totalDataFaultHF += pModule->lDataFaultHF; totalDataFaultTF += pModule->lDataFaultTF; totalDataFaultDZF += pModule->lDataFaultDZF; totalDataFaultCOW += pModule->lDataFaultCOW; totalCodeFaultHF += pModule->lCodeFaultHF; totalCodeFaultTF += pModule->lCodeFaultTF; totalCodeFaultDZF += pModule->lCodeFaultDZF; totalCodeFaultCOW += pModule->lCodeFaultCOW; } OutputTotal(TRUE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); } break; case REPORT_LIST_MODULE: if( FALSE == GetModuleList(strImgName, sortNow) ){ break; } if (PtrTotal > 0) { for (PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++) { pModule = (PMODULE_RECORD) PtrBuffer[PtrIndex].ptrRecord; if( pModule == NULL ){ break; } pProcess = pModule->pProcess; ASSERT(pProcess); if ( PtrIndex == 0 || _wcsicmp(Module_Prev, pModule->strModuleName)) { if (PtrIndex != 0) { OutputTotal(FALSE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); } totalDataFaultHF = totalDataFaultTF = totalDataFaultDZF = totalDataFaultCOW = totalCodeFaultHF = totalCodeFaultTF = totalCodeFaultDZF = totalCodeFaultCOW = 0; wcscpy(Module_Prev, pModule->strModuleName); fprintf(procFile, "\nModule Name: %-20ws, BaseAddress: 0x%08x, Size:%10d\n", pModule->strModuleName, pModule->lBaseAddress, pModule->lModuleSize); OutputProcessHeader(); } OutputModuleProcessRecord(pProcess, pModule); totalDataFaultHF += pModule->lDataFaultHF; totalDataFaultTF += pModule->lDataFaultTF; totalDataFaultDZF += pModule->lDataFaultDZF; totalDataFaultCOW += pModule->lDataFaultCOW; totalCodeFaultHF += pModule->lCodeFaultHF; totalCodeFaultTF += pModule->lCodeFaultTF; totalCodeFaultDZF += pModule->lCodeFaultDZF; totalCodeFaultCOW += pModule->lCodeFaultCOW; } OutputTotal(FALSE, totalDataFaultHF, totalDataFaultTF, totalDataFaultDZF, totalDataFaultCOW, totalCodeFaultHF, totalCodeFaultTF, totalCodeFaultDZF, totalCodeFaultCOW); } break; } Cleanup: if (PtrBuffer) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); } ASSERT(!ProcessList && !ModuleList); } /*============================================================================= */ extern PMODULE_RECORD SearchModuleByAddr( PLIST_ENTRY pModuleListHead, ULONG lAddress); extern PMODULE_RECORD SearchSysModule( PPROCESS_RECORD pProcess, ULONG lAddress, BOOLEAN fActive); BOOLEAN RundownHPFFileList( BOOLEAN fRead, PLIST_ENTRY pHPFFileListHead ) { PLIST_ENTRY pNext = pHPFFileListHead->Flink; PHPF_FILE_RECORD pHPFFileRecord; PFILE_OBJECT pFileObj; PTDISK_RECORD pDiskRecord; BOOLEAN fResult = (BOOLEAN)(pNext != pHPFFileListHead); while (pNext != pHPFFileListHead) { pHPFFileRecord = CONTAINING_RECORD(pNext, HPF_FILE_RECORD, Entry); pNext = pNext->Flink; pDiskRecord = FindGlobalDiskById(pHPFFileRecord->DiskNumber); pFileObj = FindFileInTable(pHPFFileRecord->fDO); if (pDiskRecord != NULL) { fprintf(procFile, "\t\t%c%04d,%03d,%-8ws,0x%012I64x,%6d,0x%08p\n", (fRead) ? ('R') : ('W'), pHPFFileRecord->RecordID, pHPFFileRecord->DiskNumber, pDiskRecord->DiskName, pHPFFileRecord->ByteOffset, pHPFFileRecord->BytesCount, pHPFFileRecord->fDO); } if (pFileObj && pFileObj->fileRec) { fprintf(procFile, "\t\t\t%ws\n", pFileObj->fileRec->FileName); } //else //{ // fprintf(procFile,"\n"); //} } return fResult; } void ReportHardFaultInfo() { PLIST_ENTRY pProcessHead = & CurrentSystem.ProcessListHead; PLIST_ENTRY pProcessNext = pProcessHead->Flink; PPROCESS_RECORD pProcess; PLIST_ENTRY pHPFHead; PLIST_ENTRY pHPFNext; PHPF_RECORD pHPF; PMODULE_RECORD pModule; PLIST_ENTRY pThreadHead; PLIST_ENTRY pThreadNext; PTHREAD_RECORD pThread; BOOLEAN fRecord; fprintf(procFile, "\nHardPageFault Rundown Report\n"); while (pProcessNext != pProcessHead) { pProcess = CONTAINING_RECORD(pProcessNext, PROCESS_RECORD, Entry); pProcessNext = pProcessNext->Flink; fprintf(procFile, "-------------------------------------------------------------------------------\n"); fprintf(procFile, "Process 0x%08x Image: %-20ws\n", pProcess->PID, pProcess->ImageName); pHPFHead = & pProcess->HPFListHead; pHPFNext = pHPFHead->Flink; while (pHPFNext != pHPFHead) { pHPF = CONTAINING_RECORD(pHPFNext, HPF_RECORD, Entry); pHPFNext = pHPFNext->Flink; fprintf(procFile, "\t%04d,0x%08x,", pHPF->RecordID, pHPF->lProgramCounter); pModule = SearchModuleByAddr( & pProcess->ModuleListHead, pHPF->lProgramCounter); if (pModule) { fprintf(procFile, "%-16ws,0x%08x,%010d\n", pModule->strModuleName, pModule->lBaseAddress, pModule->lModuleSize); } else { fprintf(procFile, "None\n"); } fprintf(procFile, "\t0x%08x,0x%08p,0x%010I64x,", pHPF->lFaultAddress, pHPF->fDO, pHPF->lByteOffset); pModule = SearchModuleByAddr( & pProcess->ModuleListHead, pHPF->lFaultAddress); if (!pModule) { pModule = SearchSysModule( pProcess, pHPF->lFaultAddress, FALSE); } if (pModule) { fprintf(procFile, "%-16ws,0x%08x,%010d\n", pModule->strModuleName, pModule->lBaseAddress, pModule->lModuleSize); } else { fprintf(procFile, "None\n"); } RundownHPFFileList(TRUE, & pHPF->HPFReadListHead); fprintf(procFile, "\n"); } pThreadHead = & CurrentSystem.GlobalThreadListHead; pThreadNext = pThreadHead->Flink; fprintf(procFile, "\tDisk I/O Wite Page Records:\n"); fRecord = FALSE; while (pThreadNext != pThreadHead) { pThread = CONTAINING_RECORD(pThreadNext, THREAD_RECORD, Entry); pThreadNext = pThreadNext->Flink; if (pThread->pProcess == pProcess) { if (RundownHPFFileList(FALSE, & pThread->HPFWriteListHead)) { fRecord = TRUE; } } } if (!fRecord) { fprintf(procFile, "\t\tNone\n"); } pThreadHead = & CurrentSystem.GlobalThreadListHead; pThreadNext = pThreadHead->Flink; fprintf(procFile, "\tUnresolved Disk I/O Read Page Records:\n"); fRecord = FALSE; while (pThreadNext != pThreadHead) { pThread = CONTAINING_RECORD(pThreadNext, THREAD_RECORD, Entry); pThreadNext = pThreadNext->Flink; if (pThread->pProcess == pProcess) { if (RundownHPFFileList(TRUE, & pThread->HPFReadListHead)) { fRecord = TRUE; } } } if (!fRecord) { fprintf(procFile, "\t\tNone\n"); } } fprintf(procFile, "-------------------------------------------------------------------------------\n"); } int __cdecl CompareFileRecord(const void * p1, const void * p2) { PPTR_RECORD pp1 = (PPTR_RECORD) p1; PPTR_RECORD pp2 = (PPTR_RECORD) p2; PFILE_RECORD pFile1 = (PFILE_RECORD) pp1->ptrRecord; PFILE_RECORD pFile2 = (PFILE_RECORD) pp2->ptrRecord; LONG diffFault = pp2->keySort - pp1->keySort; if (diffFault == 0) { diffFault = pFile1->DiskNumber - pFile2->DiskNumber; if (diffFault == 0) { diffFault = wcscmp(pFile1->FileName, pFile2->FileName); } } return diffFault; } void ReportHotFileInfo(ULONG NumEntry) { PLIST_ENTRY pHead = & CurrentSystem.HotFileListHead; PLIST_ENTRY pNext = pHead->Flink; PFILE_RECORD pFile; BOOLEAN fDone = FALSE; ASSERT(!PtrBuffer); PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if( NULL == PtrBuffer ){ goto Cleanup; } while (!fDone) { for (PtrTotal = 0, fDone = TRUE; pNext != pHead; pNext = pNext->Flink) { if (PtrTotal == PtrMax) { fDone = FALSE; break; } pFile = CONTAINING_RECORD(pNext, FILE_RECORD, Entry); if (pFile->ReadCount + pFile->WriteCount > 0) { PtrBuffer[PtrTotal].ptrRecord = (PVOID) pFile; PtrBuffer[PtrTotal].keySort = pFile->ReadCount + pFile->WriteCount; PtrTotal ++; } } if (!fDone) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); PtrMax += MAX_LOGS; PtrBuffer = (PPTR_RECORD) VirtualAlloc( NULL, sizeof(PTR_RECORD) * PtrMax, MEM_COMMIT, PAGE_READWRITE); if (PtrBuffer == NULL) { // fprintf(stderr, "(PDH.DLL) Memory Commit Failure.\n"); goto Cleanup; } } } if (PtrTotal > 1) { qsort((void *) PtrBuffer, (size_t) PtrTotal, (size_t) sizeof(PTR_RECORD), CompareFileRecord); } // output HotFile report title // fprintf(procFile, "File Name Read Read Write Write\n"); fprintf(procFile, " Process Information Count Size Count Size\n"); fprintf(procFile, "================================================================================================================================\n"); PtrTotal = (PtrTotal > NumEntry) ? (NumEntry) : (PtrTotal); for (PtrIndex = 0; PtrIndex < PtrTotal; PtrIndex ++) { PLIST_ENTRY pProtoHead; PLIST_ENTRY pProtoNext; PPROTO_PROCESS_RECORD pProto; pFile = (PFILE_RECORD) PtrBuffer[PtrIndex].ptrRecord; fprintf(procFile, "(%04d)%-90ws %5d %8d %5d %8d\n", pFile->DiskNumber, pFile->FileName, pFile->ReadCount, pFile->ReadSize, pFile->WriteCount, pFile->WriteSize); pProtoHead = & pFile->ProtoProcessListHead; pProtoNext = pProtoHead->Flink; while (pProtoNext != pProtoHead) { pProto = CONTAINING_RECORD(pProtoNext, PROTO_PROCESS_RECORD, Entry); pProtoNext = pProtoNext->Flink; if (pProto->ReadCount + pProto->WriteCount > 0) { fprintf(procFile, " 0x%08X %-74ws %5d %8d %5d %8d\n", pProto->ProcessRecord->PID, pProto->ProcessRecord->ImageName, pProto->ReadCount, pProto->ReadSize, pProto->WriteCount, pProto->WriteSize); } } fprintf(procFile, "\n"); } fprintf(procFile, "================================================================================================================================\n"); Cleanup: if (PtrBuffer) { VirtualFree(PtrBuffer, 0, MEM_RELEASE); } } #define CHECKTOK( x ) if( NULL == x ) { continue; } static void ReportJobInfo2(void) { JOB_RECORD Job, *pJob; char* s; char line[MAXSTR]; ULONG TotalCount = 0; ULONGLONG TotalRT = 0; ULONG TotalCPUTime = 0; pJob = &Job; if( NULL == CurrentSystem.TempFile ){ return; } rewind( CurrentSystem.TempFile ); while ( fgets(line, MAXSTR, CurrentSystem.TempFile) != NULL ) { s = strtok( line, (",")); CHECKTOK( s ); pJob->JobId = atol(s); if (pJob == NULL){ return; } } fprintf(procFile, BREAK_LINE ); fprintf(procFile, "| Spooler Transaction Instance (Job) Data |\n"); fprintf(procFile, BREAK_LINE ); fprintf(procFile, "| Job Id Type JobSize Pages PPS Files GdiSize Color XRes YRes Qlty Copy TTOpt Threads |\n"); fprintf(procFile, BREAK_LINE ); RtlZeroMemory(pJob, sizeof(JOB_RECORD)); RtlZeroMemory(line, MAXSTR * sizeof(char)); rewind( CurrentSystem.TempFile ); while ( fgets(line, MAXSTR, CurrentSystem.TempFile) != NULL ) { s = strtok( line, (",")); CHECKTOK( s ); pJob->JobId = atol(s); if (pJob == NULL){ continue; } s = strtok( NULL, (",")); CHECKTOK( s ); pJob->KCPUTime = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->UCPUTime = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->ReadIO = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->StartTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->EndTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->ResponseTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->PrintJobTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->WriteIO = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->DataType = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->JobSize = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Pages = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->PagesPerSide = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->FilesOpened = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->GdiJobSize = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Color = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->XRes = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->YRes = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Quality = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Copies = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->TTOption = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->NumberOfThreads = atol(s); fprintf(procFile, "| %6d %8d %8d %4d %6d %6hd %8d %5hd %4hd %4hd %4hd %6hd %5hd %5d %27s\n", pJob->JobId, pJob->DataType, pJob->JobSize, pJob->Pages, pJob->PagesPerSide, pJob->FilesOpened, pJob->GdiJobSize, pJob->Color, pJob->XRes, pJob->YRes, pJob->Quality, pJob->Copies, pJob->TTOption, pJob->NumberOfThreads, "|" ); } fprintf(procFile, BREAK_LINE "\n\n" ); } static void ReportJobInfo(void) { JOB_RECORD Job, *pJob; char* s; char line[MAXSTR]; FILETIME StTm, StlTm; LARGE_INTEGER LargeTmp; SYSTEMTIME stStart, stEnd, stDequeue; ULONG TotalCount = 0; ULONGLONG TotalRT = 0; ULONG TotalCPUTime = 0; if( NULL == CurrentSystem.TempFile ){ return; } pJob = &Job; rewind( CurrentSystem.TempFile ); while ( fgets(line, MAXSTR, CurrentSystem.TempFile) != NULL ) { s = strtok( line, (",")); CHECKTOK( s ); pJob->JobId = atol(s); if (pJob == NULL){ return; } } fprintf(procFile, BREAK_LINE ); fprintf(procFile, "| Transaction Instance (Job) Statistics |\n"); fprintf(procFile, BREAK_LINE ); fprintf(procFile, "| Job Id StartTime DequeueTime EndTime RespTime CPUTime %60s \n", "|"); fprintf(procFile, BREAK_LINE ); RtlZeroMemory(pJob, sizeof(JOB_RECORD)); RtlZeroMemory(line, MAXSTR * sizeof(char)); rewind( CurrentSystem.TempFile ); while ( fgets(line, MAXSTR, CurrentSystem.TempFile) != NULL ) { s = strtok( line, (",")); CHECKTOK( s ); pJob->JobId = atol(s); if (pJob == NULL){ continue; } s = strtok( NULL, (",")); CHECKTOK( s ); pJob->KCPUTime = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->UCPUTime = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->ReadIO = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->StartTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->EndTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->ResponseTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->PrintJobTime = _atoi64(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->WriteIO = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->DataType = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->JobSize = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Pages = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->PagesPerSide = atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->FilesOpened = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->GdiJobSize = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Color = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->XRes = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->YRes = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Quality = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->Copies = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->TTOption = (SHORT) atol(s); s = strtok( NULL, (",")); CHECKTOK( s ); pJob->NumberOfThreads = atol(s); LargeTmp.QuadPart = pJob->StartTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); FileTimeToSystemTime ( &StlTm, &stStart ); LargeTmp.QuadPart = pJob->EndTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); FileTimeToSystemTime ( &StlTm, &stEnd ); LargeTmp.QuadPart = pJob->PrintJobTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); FileTimeToSystemTime ( &StlTm, &stDequeue ); fprintf(procFile, "| %4d %2d:%02d:%02d.%03d %2d:%02d:%02d.%03d %2d:%02d:%02d.%03d %6I64u %5d %63s\n", pJob->JobId, stStart.wHour, stStart.wMinute, stStart.wSecond, stStart.wMilliseconds, stDequeue.wHour, stDequeue.wMinute, stDequeue.wSecond, stDequeue.wMilliseconds, stEnd.wHour, stEnd.wMinute, stEnd.wSecond, stEnd.wMilliseconds, pJob->ResponseTime, pJob->KCPUTime + pJob->UCPUTime, "|" ); TotalCount++; TotalRT += pJob->ResponseTime; TotalCPUTime += (pJob->KCPUTime + pJob->UCPUTime); } if (TotalCount > 0) { TotalRT /= TotalCount; TotalCPUTime /= TotalCount; } fprintf(procFile, BREAK_LINE ); fprintf(procFile, "| %4d %6I64u %5d %63s\n", TotalCount, TotalRT, TotalCPUTime, "|"); fprintf(procFile, BREAK_LINE "\n\n" ); ReportJobInfo2(); } void WriteSummary() { FILE* SummaryFile; PLIST_ENTRY Head, Next; PMOF_INFO pMofInfo; ULONG i; FILETIME StTm, StlTm; LARGE_INTEGER LargeTmp; SYSTEMTIME tmf, emf; BOOL bResult; if( NULL == TraceContext->SummaryFileName ){ return; } if( 0 == TotalEventCount ){ return; } SummaryFile = _wfopen( TraceContext->SummaryFileName, L"w" ); if (SummaryFile == NULL){ return; } fwprintf(SummaryFile,L"Files Processed:\n"); for (i=0; iLogFileCount; i++) { fwprintf(SummaryFile,L"\t%s\n",TraceContext->LogFileName[i]); } LargeTmp.QuadPart = StartTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); bResult = FileTimeToSystemTime ( &StlTm, &tmf ); if ( !bResult || tmf.wMonth > 12) { ZeroMemory( &tmf, sizeof(SYSTEMTIME) ); } LargeTmp.QuadPart = EndTime; StTm.dwHighDateTime = LargeTmp.HighPart; StTm.dwLowDateTime = LargeTmp.LowPart; FileTimeToLocalFileTime(&StTm, &StlTm); bResult = FileTimeToSystemTime ( &StlTm, &emf ); if ( !bResult ) { ZeroMemory( &emf, sizeof(SYSTEMTIME) ); } ElapseTime = EndTime - StartTime; fwprintf(SummaryFile, L"Total Buffers Processed %d\n" L"Total Events Processed %d\n" L"Total Events Lost %d\n" L"Start Time %2d %3S %4d %2d:%02d:%02d.%03d\n" L"End Time %2d %3S %4d %2d:%02d:%02d.%03d\n" L"Elapsed Time %I64d sec\n", TotalBuffersRead, TotalEventCount, TotalEventsLost, tmf.wDay, Month[tmf.wMonth], tmf.wYear, tmf.wHour, tmf.wMinute, tmf.wSecond, tmf.wMilliseconds, emf.wDay, Month[emf.wMonth], emf.wYear,emf.wHour, emf.wMinute, emf.wSecond, emf.wMilliseconds, (ElapseTime / 10000000) ); fwprintf(SummaryFile, L"+-------------------------------------------------------------------------------------+\n" L"|%10s %-20s %-10s %-38s|\n" L"+-------------------------------------------------------------------------------------+\n", L"Event Count", L"Event Name", L"Event Type", L"Guid" ); Head = &CurrentSystem.EventListHead; Next = Head->Flink; while (Head != Next) { WCHAR wstr[MAXSTR]; PWCHAR str; WCHAR s[64]; PLIST_ENTRY vHead, vNext; PMOF_VERSION pMofVersion; RtlZeroMemory(&wstr, MAXSTR); pMofInfo = CONTAINING_RECORD(Next, MOF_INFO, Entry); Next = Next->Flink; if (pMofInfo->EventCount > 0) { str = CpdiGuidToString(&s[0], (LPGUID)&pMofInfo->Guid); if( pMofInfo->strDescription != NULL ){ wcscpy( wstr, pMofInfo->strDescription ); } // // Get event count by type from MOF_VERSION structure // vHead = &pMofInfo->VersionHeader; vNext = vHead->Flink; while (vHead != vNext) { pMofVersion = CONTAINING_RECORD(vNext, MOF_VERSION, Entry); vNext = vNext->Flink; if (pMofVersion->EventCountByType != 0) { fwprintf(SummaryFile,L"| %10d %-20s %-10s %38s|\n", pMofVersion->EventCountByType, wstr, pMofVersion->strType ? pMofVersion->strType : GUID_TYPE_DEFAULT, str); } } } } fwprintf(SummaryFile, L"+-------------------------------------------------------------------------------------+\n" ); fclose( SummaryFile ); }