windows-nt/Source/XPSP1/NT/drivers/wdm/usb/driver/wceusbsh/perf.c

252 lines
6.4 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/* 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
}