|
|
/* 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
}
|