252 lines
6.4 KiB
C
252 lines
6.4 KiB
C
|
/* Copyright (c) 1999-2000 Microsoft Corporation */
|
||
|
///======================================================================
|
||
|
//
|
||
|
// Perf.c
|
||
|
//
|
||
|
// This file contains the performance counter initialization
|
||
|
// and dump routines. The only part of this file you
|
||
|
// must modify is the performance counter name table. Match
|
||
|
// the names with the counters you define in perf.h
|
||
|
//
|
||
|
///======================================================================
|
||
|
|
||
|
#include "wdm.h"
|
||
|
#include "perf.h"
|
||
|
|
||
|
#include "debug.h"
|
||
|
|
||
|
#if PERFORMANCE
|
||
|
|
||
|
//**********************************************************************
|
||
|
//
|
||
|
// Modify this section for your counters
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// The names that correspond to the performance
|
||
|
// counter indexes in perf.h
|
||
|
//
|
||
|
static char CounterNames[NUM_PERF_COUNTERS][32] = {
|
||
|
//
|
||
|
// Write path
|
||
|
//
|
||
|
"Write",
|
||
|
"WriteComplete",
|
||
|
"WriteTimeout",
|
||
|
|
||
|
//
|
||
|
// Read path
|
||
|
//
|
||
|
"StartUsbReadWorkItem",
|
||
|
"UsbRead",
|
||
|
"UsbReadCompletion",
|
||
|
"CheckForQueuedUserReads",
|
||
|
"GetUserData",
|
||
|
"PutUserData",
|
||
|
"CancelUsbReadIrp",
|
||
|
"Read",
|
||
|
"StartOrQueueIrp",
|
||
|
"StartUserRead",
|
||
|
"GetNextUserIrp",
|
||
|
"CancelCurrentRead",
|
||
|
"CancelQueuedIrp",
|
||
|
"ReadTimeout",
|
||
|
"IntervalReadTimeout",
|
||
|
"CancelUsbReadWorkItem",
|
||
|
|
||
|
//
|
||
|
// USB Path
|
||
|
//
|
||
|
"UsbReadWritePacket",
|
||
|
|
||
|
//
|
||
|
// Serial path
|
||
|
//
|
||
|
"ProcessSerialWaits",
|
||
|
|
||
|
//
|
||
|
// Utils
|
||
|
//
|
||
|
"TryToCompleteCurrentIrp",
|
||
|
"RundownIrpRefs",
|
||
|
"RecycleIrp",
|
||
|
"ReuseIrp",
|
||
|
"CalculateTimeout",
|
||
|
|
||
|
};
|
||
|
|
||
|
//
|
||
|
// End of user-modified portion
|
||
|
//
|
||
|
//**********************************************************************
|
||
|
|
||
|
|
||
|
// print macro that only turns on when debugging is on
|
||
|
|
||
|
//#if DBG
|
||
|
#define PerfPrint(arg) DbgPrint arg
|
||
|
//#else
|
||
|
//#define PerfPrint(arg)
|
||
|
//#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// The array of performance counters
|
||
|
//
|
||
|
PERF_COUNTER PerfCounter[NUM_PERF_COUNTERS];
|
||
|
|
||
|
//
|
||
|
// Number of cycles for a PERF_ENTRY and PERF_EXIT
|
||
|
//
|
||
|
static LARGE_INTEGER PerfEntryExitCycles;
|
||
|
|
||
|
//
|
||
|
// Number of cycles per second
|
||
|
//
|
||
|
static LARGE_INTEGER PerfCyclesPerSecond;
|
||
|
|
||
|
//
|
||
|
// The resolution of the NT-supplied performance
|
||
|
// counter
|
||
|
//
|
||
|
static LARGE_INTEGER PerfFreq;
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
//
|
||
|
// InitPerfCounters
|
||
|
//
|
||
|
// This function initializes the performance counter statistic
|
||
|
// array, estimates how many cycles on this processor equal a second,
|
||
|
// and determines how many cycles it takes to execute a
|
||
|
// PERF_ENTRY/PERF_EXIT pair.
|
||
|
//
|
||
|
//----------------------------------------------------------------------
|
||
|
VOID
|
||
|
InitPerfCounters()
|
||
|
{
|
||
|
#if PERFORMANCE
|
||
|
volatile ULONG i;
|
||
|
LARGE_INTEGER calStart;
|
||
|
LARGE_INTEGER calEnd;
|
||
|
LARGE_INTEGER perfStart, perfEnd;
|
||
|
LARGE_INTEGER seconds;
|
||
|
KIRQL prevIrql;
|
||
|
|
||
|
//
|
||
|
// Number of calibration loops
|
||
|
//
|
||
|
#define CALIBRATION_LOOPS 500000
|
||
|
|
||
|
//
|
||
|
// This define is for a dummy performance counter that we
|
||
|
// use just to calibrate the performance macro overhead
|
||
|
//
|
||
|
#define TEST 0
|
||
|
|
||
|
//
|
||
|
// Calibrate the overhead of PERF_ENTRY and PERF_EXIT, so that
|
||
|
// they can be subtracted from the output
|
||
|
//
|
||
|
DbgDump(DBG_INIT, ("CALIBRATING PEFORMANCE TIMER....\n"));
|
||
|
KeRaiseIrql( DISPATCH_LEVEL, &prevIrql );
|
||
|
perfStart = KeQueryPerformanceCounter( &PerfFreq );
|
||
|
RDTSC(calStart);
|
||
|
for( i = 0; i < CALIBRATION_LOOPS; i++ ) {
|
||
|
PERF_ENTRY(TEST);
|
||
|
PERF_EXIT(TEST);
|
||
|
}
|
||
|
RDTSC(calEnd);
|
||
|
perfEnd = KeQueryPerformanceCounter(NULL);
|
||
|
KeLowerIrql( prevIrql );
|
||
|
|
||
|
//
|
||
|
// Calculate the cycles/PERF_ENTRY, and the number of cycles/second
|
||
|
//
|
||
|
PerfEntryExitCycles.QuadPart = (calEnd.QuadPart - calStart.QuadPart)/CALIBRATION_LOOPS;
|
||
|
|
||
|
seconds.QuadPart = ((perfEnd.QuadPart - perfStart.QuadPart) * 1000 )/ PerfFreq.QuadPart;
|
||
|
|
||
|
PerfCyclesPerSecond.QuadPart =
|
||
|
seconds.QuadPart ? ((calEnd.QuadPart - calStart.QuadPart) * 1000) / seconds.QuadPart : 0;
|
||
|
|
||
|
DbgDump(DBG_INIT, ("Machine's Cycles Per Second : %I64d\n", PerfCyclesPerSecond.QuadPart ));
|
||
|
DbgDump(DBG_INIT, ("Machine's Cycles in PERF_XXXX : %I64d\n", PerfEntryExitCycles.QuadPart ));
|
||
|
DbgDump(DBG_INIT, ("Machine's NT Performance counter frequency: %I64d\n", PerfFreq.QuadPart ));
|
||
|
|
||
|
//
|
||
|
// Initialize the array
|
||
|
//
|
||
|
for( i = 0; i < NUM_PERF_COUNTERS; i++ ) {
|
||
|
PerfCounter[i].Count = 0;
|
||
|
KeInitializeSpinLock( &PerfCounter[i].Lock );
|
||
|
PerfCounter[i].TotalCycles.QuadPart = 0;
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
// *******************************************************************
|
||
|
// Name:
|
||
|
// DumpPerfCounters()
|
||
|
//
|
||
|
// Description:
|
||
|
// Dumps the performance counters
|
||
|
//
|
||
|
// Assumptions:
|
||
|
//
|
||
|
// Returns:
|
||
|
//
|
||
|
// *******************************************************************
|
||
|
VOID
|
||
|
DumpPerfCounters()
|
||
|
{
|
||
|
#if PERFORMANCE
|
||
|
int i;
|
||
|
LARGE_INTEGER totCycles;
|
||
|
LARGE_INTEGER totLengthMs;
|
||
|
LARGE_INTEGER avgLengthMs;
|
||
|
|
||
|
if (DebugLevel & DBG_PERF ) {
|
||
|
|
||
|
PerfPrint(("\n"));
|
||
|
PerfPrint(("Machine's Cycles Per Second : %I64d\n", PerfCyclesPerSecond.QuadPart ));
|
||
|
PerfPrint(("Machine's Cycles in PERF_XXXX : %I64d\n", PerfEntryExitCycles.QuadPart ));
|
||
|
PerfPrint(("Machine's NT Performance counter frequency: %I64d\n", PerfFreq.QuadPart ));
|
||
|
PerfPrint(("\n===================================================================================\n"));
|
||
|
PerfPrint((" %-30s Count TTL Time Avg Time (uS)\n", "Function" ));
|
||
|
PerfPrint(("===================================================================================\n"));
|
||
|
|
||
|
for( i = 0; i < NUM_PERF_COUNTERS; i++ ) {
|
||
|
|
||
|
totCycles = PerfCounter[i].TotalCycles;
|
||
|
totCycles.QuadPart -= (PerfCounter[i].Count * PerfEntryExitCycles.QuadPart);
|
||
|
totLengthMs.QuadPart = PerfCyclesPerSecond.QuadPart ? (totCycles.QuadPart * 1000000)/
|
||
|
PerfCyclesPerSecond.QuadPart : 0;
|
||
|
avgLengthMs.QuadPart = PerfCounter[i].Count ? totLengthMs.QuadPart / PerfCounter[i].Count : 0;
|
||
|
|
||
|
PerfPrint((" %-30s %10d %15I64d %14I64d\n",
|
||
|
CounterNames[i], PerfCounter[i].Count,
|
||
|
totLengthMs.QuadPart, avgLengthMs.QuadPart ));
|
||
|
|
||
|
/*
|
||
|
PerfPrint((" %-30s %10s %15I64d %14I64d (CY)\n",
|
||
|
"", "",
|
||
|
totCycles.QuadPart,
|
||
|
totCycles.QuadPart ? totCycles.QuadPart / PerfCounter[i].Count: 0 ));
|
||
|
|
||
|
PerfPrint(("------------------------------------------------------------------------------\n"));
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
PerfPrint(("------------------------------------------------------------------------------\n"));
|
||
|
}
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|