588 lines
16 KiB
C++
588 lines
16 KiB
C++
//+-------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1993.
|
|
//
|
|
// File: PerfSnap.hxx
|
|
//
|
|
// Contents: Performace monitor. Snapshots system at user-defined time
|
|
//
|
|
// Classes: CPerfInfo, CPerformanceMonitor
|
|
//
|
|
// History: 30-Sep-93 KyleP Created
|
|
//
|
|
// Notes: These classes only do something interesting if PERFSNAP
|
|
// is defined.
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#if !defined(__PERFSNAP_HXX__)
|
|
#define __PERFSNAP_HXX__
|
|
|
|
#define USE_NEW_LARGE_INTEGERS
|
|
|
|
extern "C"
|
|
{
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#ifdef NEVER
|
|
#include <rpc.h>
|
|
#include <rpcdce.h>
|
|
#endif
|
|
}
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <windows.h>
|
|
#include <debnot.h>
|
|
#include <heapstat.h>
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CPerfInfo
|
|
//
|
|
// Purpose: Holds snapshot of performance data
|
|
//
|
|
// History: 30-Sep-93 KyleP Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
#if defined(PERFSNAP)
|
|
|
|
class CPerfInfo
|
|
{
|
|
public:
|
|
|
|
inline void Init(char const * pszTitle, int const level);
|
|
|
|
inline CPerfInfo & operator -(CPerfInfo const & piIn);
|
|
|
|
inline void Comment(FILE * pfOut,
|
|
char const * pszComment,
|
|
LARGE_INTEGER stime);
|
|
|
|
inline void Print(FILE * pfOut, LARGE_INTEGER stime);
|
|
|
|
inline void _Print(FILE * pfOut);
|
|
|
|
inline static void PrintHeader(FILE * pfOut);
|
|
|
|
private:
|
|
|
|
enum
|
|
{
|
|
_cbProcPerfXfer = 100 * sizeof(SYSTEM_PROCESS_INFORMATION) +
|
|
500 * sizeof(SYSTEM_THREAD_INFORMATION)
|
|
};
|
|
static unsigned char _ProcPerfXfer[_cbProcPerfXfer];
|
|
|
|
int _level;
|
|
char _szTitle[100];
|
|
LARGE_INTEGER _time;
|
|
SYSTEM_PERFORMANCE_INFORMATION _SysPerf;
|
|
SYSTEM_PROCESS_INFORMATION _ProcPerf;
|
|
HEAPSTATS _heapStats;
|
|
|
|
#ifdef NEVER
|
|
// DO NOT SEPARATE
|
|
RPC_STATS_VECTOR _rpcStats;
|
|
long _rpcExtraSpace[3];
|
|
// END OF DO NOT SEPARATE
|
|
#endif
|
|
};
|
|
|
|
# define IMPLEMENT_PERFSNAP() \
|
|
unsigned char CPerfInfo::_ProcPerfXfer[CPerfInfo::_cbProcPerfXfer];
|
|
|
|
#else // PERFSNAP
|
|
|
|
# define IMPLEMENT_PERFSNAP()
|
|
|
|
#endif // PERFSNAP
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Class: CPerformanceMonitor
|
|
//
|
|
// Purpose: Monitor performance of system/process at user-defined time.
|
|
//
|
|
// History: 30-Sep-93 KyleP Created
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
class CPerformanceMonitor
|
|
{
|
|
public:
|
|
|
|
inline CPerformanceMonitor(char const * szFile = 0);
|
|
|
|
inline ~CPerformanceMonitor();
|
|
|
|
inline void PrintHeader();
|
|
|
|
inline void Comment(char const * pszComment);
|
|
|
|
inline void Snap(char const * pszTitle, int const level);
|
|
|
|
inline void Delta(char const * pszTitle, int const level);
|
|
|
|
#if defined(PERFSNAP)
|
|
private:
|
|
|
|
FILE * _pfOut;
|
|
int _iLastSnap;
|
|
LARGE_INTEGER _time;
|
|
CPerfInfo _aSnap[2];
|
|
#endif // PERFSNAP
|
|
};
|
|
|
|
inline CPerformanceMonitor::CPerformanceMonitor(char const * szFile)
|
|
{
|
|
#if defined(PERFSNAP)
|
|
NtQuerySystemTime(&_time); // start time
|
|
|
|
_iLastSnap = 0;
|
|
if (szFile)
|
|
_pfOut = fopen(szFile, "a");
|
|
else
|
|
_pfOut = stdout;
|
|
fprintf(_pfOut, "\n----------------------------------------\n");
|
|
|
|
_aSnap[0].Init("Start0", 0);
|
|
_aSnap[1].Init("Start1", 0);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
inline CPerformanceMonitor::~CPerformanceMonitor()
|
|
{
|
|
#if defined(PERFSNAP)
|
|
fclose(_pfOut);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
inline void CPerformanceMonitor::PrintHeader()
|
|
{
|
|
#if defined(PERFSNAP)
|
|
_aSnap[0].PrintHeader(_pfOut);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
inline void CPerformanceMonitor::Comment(char const * pszComment)
|
|
{
|
|
#if defined(PERFSNAP)
|
|
_aSnap[_iLastSnap].Comment(_pfOut, pszComment, _time);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
inline void CPerformanceMonitor::Snap(char const * pszTitle, int const level)
|
|
{
|
|
#if defined(PERFSNAP)
|
|
_iLastSnap = (_iLastSnap + 1) % 2;
|
|
_aSnap[_iLastSnap].Init(pszTitle, level);
|
|
_aSnap[_iLastSnap].Print(_pfOut, _time);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
inline void CPerformanceMonitor::Delta(char const * pszTitle, int const level)
|
|
{
|
|
#if defined(PERFSNAP)
|
|
_iLastSnap = (_iLastSnap + 1) % 2;
|
|
_aSnap[_iLastSnap].Init(pszTitle, level);
|
|
|
|
CPerfInfo piDelta = _aSnap[_iLastSnap] - _aSnap[(_iLastSnap + 1) % 2];
|
|
|
|
// _aSnap[_iLastSnap].Print(_pfOut, _time);
|
|
piDelta.Print(_pfOut, _time);
|
|
#endif // PERFSNAP
|
|
}
|
|
|
|
#if defined(PERFSNAP)
|
|
|
|
inline void CPerfInfo::Init(char const * pszTitle, int const level)
|
|
{
|
|
//
|
|
// Get time
|
|
//
|
|
|
|
NtQuerySystemTime(&_time);
|
|
|
|
//
|
|
// Set level
|
|
//
|
|
|
|
_level = level;
|
|
|
|
//
|
|
// Copy title string
|
|
//
|
|
|
|
int len = strlen(pszTitle);
|
|
if (len > sizeof(_szTitle) - 1)
|
|
len = sizeof(_szTitle) - 1;
|
|
|
|
memcpy(_szTitle, pszTitle, len);
|
|
_szTitle[len] = 0;
|
|
|
|
//
|
|
// Get performance information
|
|
//
|
|
|
|
NTSTATUS Status = NtQuerySystemInformation (SystemPerformanceInformation,
|
|
&_SysPerf,
|
|
sizeof(_SysPerf),
|
|
0);
|
|
|
|
Win4Assert(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Process info. Comes back for *all* processes and threads!
|
|
//
|
|
|
|
Status = NtQuerySystemInformation (SystemProcessInformation,
|
|
_ProcPerfXfer,
|
|
_cbProcPerfXfer,
|
|
0);
|
|
|
|
Win4Assert(NT_SUCCESS(Status));
|
|
|
|
//
|
|
// Find the process we care about and copy it out.
|
|
//
|
|
|
|
HANDLE pid = (HANDLE)NtCurrentTeb()->ClientId.UniqueProcess;
|
|
|
|
unsigned char * pb = _ProcPerfXfer;
|
|
|
|
while (TRUE)
|
|
{
|
|
SYSTEM_PROCESS_INFORMATION * pProc = (SYSTEM_PROCESS_INFORMATION *)pb;
|
|
|
|
if (pProc->UniqueProcessId == pid)
|
|
{
|
|
memcpy(&_ProcPerf, pProc, sizeof(SYSTEM_PROCESS_INFORMATION));
|
|
break;
|
|
}
|
|
|
|
if (pProc->NextEntryOffset == 0)
|
|
{
|
|
printf("Couldn't find info for process 0x%x\n", pid);
|
|
break;
|
|
}
|
|
|
|
pb += pProc->NextEntryOffset;
|
|
}
|
|
|
|
#ifdef NEVER
|
|
//
|
|
// RPC Statistics
|
|
//
|
|
|
|
RPC_STATS_VECTOR *pStats;
|
|
|
|
RpcMgmtInqStats(NULL, &pStats);
|
|
memcpy(& _rpcStats, pStats, sizeof(_rpcStats) + sizeof(_rpcExtraSpace));
|
|
RpcMgmtStatsVectorFree(&pStats);
|
|
#endif
|
|
|
|
//
|
|
// (Cairo) Heap Statistics
|
|
//
|
|
|
|
GetHeapStats(&_heapStats);
|
|
}
|
|
|
|
inline CPerfInfo & CPerfInfo::operator -(CPerfInfo const & pi2)
|
|
{
|
|
CPerfInfo ret;
|
|
|
|
//
|
|
// Make a delta title
|
|
//
|
|
|
|
unsigned len = strlen(_szTitle);
|
|
memcpy(ret._szTitle, _szTitle, len);
|
|
if (len < sizeof(ret._szTitle)-4)
|
|
{
|
|
memcpy(ret._szTitle + len, " - ", 4);
|
|
len += 3;
|
|
}
|
|
unsigned len2 = strlen(pi2._szTitle);
|
|
if (len2 > sizeof(ret._szTitle) - len - 1)
|
|
len2 = sizeof(ret._szTitle) - len - 1;
|
|
|
|
memcpy(ret._szTitle + len, pi2._szTitle, len2);
|
|
ret._szTitle[len+len2] = 0;
|
|
|
|
ret._time = _time - pi2._time;
|
|
|
|
//
|
|
// 'Subtract' performance info
|
|
//
|
|
|
|
ret._SysPerf.AvailablePages = _SysPerf.AvailablePages -
|
|
pi2._SysPerf.AvailablePages;
|
|
ret._SysPerf.CommittedPages = _SysPerf.CommittedPages -
|
|
pi2._SysPerf.CommittedPages;
|
|
ret._SysPerf.PeakCommitment = max(_SysPerf.PeakCommitment,
|
|
pi2._SysPerf.PeakCommitment);
|
|
ret._SysPerf.PageFaultCount = _SysPerf.PageFaultCount -
|
|
pi2._SysPerf.PageFaultCount;
|
|
ret._SysPerf.PagedPoolPages = _SysPerf.PagedPoolPages -
|
|
pi2._SysPerf.PagedPoolPages;
|
|
ret._SysPerf.NonPagedPoolPages = _SysPerf.NonPagedPoolPages -
|
|
pi2._SysPerf.NonPagedPoolPages;
|
|
|
|
//
|
|
// System/LPC calls
|
|
//
|
|
|
|
ret._SysPerf.SystemCalls = _SysPerf.SystemCalls - pi2._SysPerf.SystemCalls;
|
|
#ifdef NEVER
|
|
ret._SysPerf.LpcCallOperationCount = _SysPerf.LpcCallOperationCount -
|
|
pi2._SysPerf.LpcCallOperationCount;
|
|
|
|
//
|
|
// RPC
|
|
//
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
ret._rpcStats.Stats[i] = _rpcStats.Stats[i] - pi2._rpcStats.Stats[i];
|
|
#endif
|
|
|
|
//
|
|
// CPU time
|
|
//
|
|
|
|
ret._ProcPerf.UserTime = _ProcPerf.UserTime - pi2._ProcPerf.UserTime;
|
|
ret._ProcPerf.KernelTime = _ProcPerf.KernelTime - pi2._ProcPerf.KernelTime;
|
|
|
|
//
|
|
// Memory
|
|
//
|
|
|
|
ret._ProcPerf.PagefileUsage = _ProcPerf.PagefileUsage -
|
|
pi2._ProcPerf.PagefileUsage;
|
|
ret._ProcPerf.PeakPagefileUsage = max(_ProcPerf.PeakPagefileUsage,
|
|
pi2._ProcPerf.PeakPagefileUsage);
|
|
ret._ProcPerf.PrivatePageCount = _ProcPerf.PrivatePageCount -
|
|
pi2._ProcPerf.PrivatePageCount;
|
|
ret._ProcPerf.QuotaPagedPoolUsage = _ProcPerf.QuotaPagedPoolUsage -
|
|
pi2._ProcPerf.QuotaPagedPoolUsage;
|
|
ret._ProcPerf.QuotaNonPagedPoolUsage = _ProcPerf.QuotaNonPagedPoolUsage -
|
|
pi2._ProcPerf.QuotaNonPagedPoolUsage;
|
|
ret._ProcPerf.PeakWorkingSetSize = max(_ProcPerf.PeakWorkingSetSize,
|
|
pi2._ProcPerf.PeakWorkingSetSize);
|
|
ret._ProcPerf.WorkingSetSize = _ProcPerf.WorkingSetSize -
|
|
pi2._ProcPerf.WorkingSetSize;
|
|
|
|
//
|
|
// Threads
|
|
//
|
|
|
|
ret._ProcPerf.NumberOfThreads = _ProcPerf.NumberOfThreads - pi2._ProcPerf.NumberOfThreads;
|
|
ret._ProcPerf.NumberOfThreads;
|
|
|
|
//
|
|
// (Cairo) Heap Stats
|
|
//
|
|
|
|
ret._heapStats.cNew =_heapStats.cNew -pi2._heapStats.cNew;
|
|
ret._heapStats.cZeroNew =_heapStats.cZeroNew -pi2._heapStats.cZeroNew;
|
|
ret._heapStats.cDelete =_heapStats.cDelete -pi2._heapStats.cDelete;
|
|
ret._heapStats.cZeroDelete=_heapStats.cZeroDelete -
|
|
pi2._heapStats.cZeroDelete;
|
|
ret._heapStats.cRealloc =_heapStats.cRealloc -pi2._heapStats.cRealloc;
|
|
ret._heapStats.cbNewed =_heapStats.cbNewed -pi2._heapStats.cbNewed;
|
|
ret._heapStats.cbDeleted =_heapStats.cbDeleted-pi2._heapStats.cbDeleted;
|
|
|
|
return(ret);
|
|
}
|
|
|
|
inline void CPerfInfo::PrintHeader(FILE * pfOut)
|
|
{
|
|
LARGE_INTEGER time;
|
|
SYSTEMTIME systime;
|
|
NtQuerySystemTime(&time);
|
|
FileTimeToSystemTime((FILETIME *)&time, &systime);
|
|
|
|
fprintf(pfOut,
|
|
"Performance Run %02d/%02d/%02d %02d:%02d:%02d\n",
|
|
systime.wMonth, systime.wDay, systime.wYear,
|
|
systime.wHour, systime.wMinute, systime.wSecond);
|
|
|
|
fprintf(pfOut,
|
|
"Abs/Rel\t"
|
|
"Level\t"
|
|
"System Time\t"
|
|
"System Time ms\t"
|
|
"Title\t"
|
|
"Physical Memory Available Kb\t"
|
|
"Virtual Memory Committed Kb\t"
|
|
"Virtual Memory Max Committed Kb\t"
|
|
"Virtual Memory Page Faults\t"
|
|
"System Total Paged Pool Kb\t"
|
|
"System Total Nonpaged Pool Kb\t"
|
|
"System Calls\t"
|
|
"Process User CPU Time ms\t"
|
|
"Process Kernel CPU Time ms\t"
|
|
"Process Page File Used pages\t"
|
|
"Process Page File Max Used pages\t"
|
|
"Process Page File Private pages\t"
|
|
"Process Paged Pool pages\t"
|
|
"Process Nonpaged Pool pages\t"
|
|
"Process #Threads\t"
|
|
"Working Set Peak Kb\t"
|
|
"Working Set Current Kb\t"
|
|
"Heap Allocs\t"
|
|
"0-len Heap Allocs\t"
|
|
"Heap Deletes\t"
|
|
"0-len Heap Deletes\t"
|
|
"Heap Reallocs\t"
|
|
"Heap Allocated bytes\t"
|
|
"Heap Freed bytes\t"
|
|
"Process ID\t"
|
|
"Thread ID\t"
|
|
"Time To Snap ms\t"
|
|
"System Time ms absolute\n");
|
|
}
|
|
|
|
|
|
inline void CPerfInfo::_Print(FILE * pfOut)
|
|
{
|
|
// LPCCallOperationsCount not printed: its bogus
|
|
// _rpcStats[0..3] not printed: never non-zero
|
|
// "RPC Calls In\tRPC Calls Out\tRPC Packets In\tRPC Packets Out\t"
|
|
|
|
fprintf(pfOut,
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%lu\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%ld\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%lu\t"
|
|
"%ld\t"
|
|
"%ld",
|
|
_SysPerf.AvailablePages * 4,
|
|
_SysPerf.CommittedPages * 4,
|
|
_SysPerf.PeakCommitment * 4,
|
|
_SysPerf.PageFaultCount,
|
|
_SysPerf.PagedPoolPages * 4,
|
|
_SysPerf.NonPagedPoolPages * 4,
|
|
_SysPerf.SystemCalls,
|
|
(_ProcPerf.UserTime.LowPart+5000) / 10000,
|
|
(_ProcPerf.KernelTime.LowPart+5000) / 10000,
|
|
(_ProcPerf.PagefileUsage+1023) / 1024,
|
|
(_ProcPerf.PeakPagefileUsage+1023) / 1024,
|
|
(_ProcPerf.PrivatePageCount+1023) / 1024,
|
|
(_ProcPerf.QuotaPagedPoolUsage+1023) / 1024,
|
|
(_ProcPerf.QuotaNonPagedPoolUsage+1023) / 1024,
|
|
_ProcPerf.NumberOfThreads,
|
|
(_ProcPerf.PeakWorkingSetSize+1023) / 1024,
|
|
(_ProcPerf.WorkingSetSize+1023) / 1024,
|
|
_heapStats.cNew,
|
|
_heapStats.cZeroNew,
|
|
_heapStats.cDelete,
|
|
_heapStats.cZeroDelete,
|
|
_heapStats.cRealloc,
|
|
_heapStats.cbNewed,
|
|
_heapStats.cbDeleted,
|
|
GetCurrentProcessId(),
|
|
GetCurrentThreadId()
|
|
);
|
|
|
|
}
|
|
|
|
#define CVT_TO_MS(t) (((t.wHour*60 + t.wMinute)*60 + t.wSecond)*1000 + t.wMilliseconds)
|
|
|
|
inline void CPerfInfo::Print(FILE * pfOut, LARGE_INTEGER stime)
|
|
{
|
|
LARGE_INTEGER time;
|
|
LARGE_INTEGER dtime;
|
|
SYSTEMTIME systime;
|
|
|
|
_szTitle[sizeof(_szTitle)-1] = '\0';
|
|
|
|
//
|
|
// Time is either a delta or absolute.
|
|
//
|
|
|
|
if (_time.HighPart > 0)
|
|
{
|
|
SYSTEMTIME systime;
|
|
FileTimeToSystemTime((FILETIME *)&_time, &systime);
|
|
dtime = _time - stime;
|
|
fprintf(pfOut,
|
|
"A\t%d\t%02d:%02d:%02d.%03d\t%u\t%s\t",
|
|
_level,
|
|
systime.wHour, systime.wMinute, systime.wSecond,
|
|
systime.wMilliseconds,
|
|
dtime.LowPart / 10000,
|
|
_szTitle);
|
|
}
|
|
else
|
|
{
|
|
// FILETIME is in units of 100 nanoseconds (== 0.1 ms)
|
|
fprintf(pfOut,
|
|
"R\t%d\t\t%u\t%s\t",
|
|
_level,
|
|
_time.LowPart / 10000,
|
|
_szTitle);
|
|
}
|
|
|
|
_Print(pfOut);
|
|
|
|
// A FILETIME is in units of 100 nanoseconds (== 0.1 ms)
|
|
NtQuerySystemTime(&time);
|
|
dtime = time - _time;
|
|
FileTimeToSystemTime((FILETIME*)&_time, &systime);
|
|
fprintf(pfOut, "\t%d\t%d\n", dtime.LowPart / 10000, CVT_TO_MS(systime));
|
|
}
|
|
|
|
|
|
inline void CPerfInfo::Comment(FILE * pfOut, char const * pszComment,
|
|
LARGE_INTEGER stime)
|
|
{
|
|
SYSTEMTIME systod;
|
|
LARGE_INTEGER time;
|
|
LARGE_INTEGER tod;
|
|
LARGE_INTEGER dtime;
|
|
|
|
NtQuerySystemTime(&tod);
|
|
FileTimeToSystemTime((FILETIME*)&tod, &systod);
|
|
dtime = tod - stime;
|
|
|
|
fprintf(pfOut, "C\t0\t%02d:%02d:%02d.%03d\t%d\t%s\t",
|
|
systod.wHour, systod.wMinute, systod.wSecond,
|
|
systod.wMilliseconds,
|
|
dtime.LowPart / 10000,
|
|
pszComment);
|
|
|
|
_Print(pfOut);
|
|
|
|
NtQuerySystemTime(&time);
|
|
dtime = time - tod;
|
|
fprintf(pfOut, "\t%d\t%d\n", dtime.LowPart / 10000, CVT_TO_MS(systod));
|
|
}
|
|
|
|
#endif // PERFSNAP
|
|
#endif // __PERFSNAP_HXX__
|