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