mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
260 lines
5.0 KiB
260 lines
5.0 KiB
/*++
|
|
|
|
Copyright (c) 1992, 1993 Digital Equipment Corporation
|
|
|
|
Module Name:
|
|
|
|
perfcntr.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the interfaces that access the system
|
|
performance counter and the calibrated stall. The functions implemented
|
|
in this module are suitable for uniprocessor systems only.
|
|
|
|
Author:
|
|
|
|
Jeff McLeman (mcleman) 05-June-1992
|
|
|
|
Environment:
|
|
|
|
Kernel mode
|
|
|
|
Revision History:
|
|
|
|
|
|
Rod Gamache [DEC] 9-Mar-1993
|
|
Fix profile clock.
|
|
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
#include "eisa.h"
|
|
|
|
//
|
|
// Define and initialize the 64-bit count of total system cycles used
|
|
// as the performance counter.
|
|
//
|
|
|
|
ULONGLONG HalpCycleCount = 0;
|
|
|
|
|
|
LARGE_INTEGER
|
|
KeQueryPerformanceCounter (
|
|
OUT PLARGE_INTEGER Frequency OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine returns the current performance counter value and the
|
|
performance counter frequency.
|
|
|
|
Arguments:
|
|
|
|
Frequency - Supplies an optional pointer to a variable which receives
|
|
the performance counter frequency in Hertz.
|
|
|
|
Return Value:
|
|
|
|
The current performance counter value is returned as the function
|
|
value.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
LARGE_INTEGER LocalRpccTime;
|
|
ULONG RpccValue;
|
|
|
|
//
|
|
// Obtain the current value of the processor cycle counter and adjust
|
|
// the upper 32 bits if a roll-over occurred since the last time the
|
|
// Rpcc value was checked (at least oncce per clock interrupt). This
|
|
// code may be interrupted so we must fetch HalpRpccTimec atomically.
|
|
//
|
|
|
|
*(PULONGLONG)&LocalRpccTime = HalpCycleCount;
|
|
RpccValue = HalpRpcc();
|
|
if (RpccValue < LocalRpccTime.LowPart) {
|
|
LocalRpccTime.HighPart += 1;
|
|
}
|
|
LocalRpccTime.LowPart = RpccValue;
|
|
|
|
|
|
//
|
|
// If the frequency parameter is specified, then return the performance
|
|
// counter frequency as the current system time frequency.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(Frequency) != FALSE) {
|
|
Frequency->LowPart = HalpClockFrequency;
|
|
Frequency->HighPart = 0;
|
|
}
|
|
|
|
//
|
|
// Return the current processor cycle counter as the function value.
|
|
//
|
|
|
|
return LocalRpccTime;
|
|
}
|
|
|
|
|
|
VOID
|
|
HalCalibratePerformanceCounter (
|
|
IN volatile PLONG Number
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine resets the performance counter value for the current
|
|
processor to zero. The reset is done such that the resulting value
|
|
is closely synchronized with other processors in the configuration.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies a pointer to count of the number of processors in
|
|
the configuration.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
//
|
|
// ****** Warning ******
|
|
//
|
|
// This is a stub routine. It should clear the current value of the
|
|
// performance counter. It is really only needed in an MP system where,
|
|
// close, but not exact synchronization of the performance counters
|
|
// are needed. See MIPS code in halfxs\mips\j4prof.c for a method of
|
|
// synchronizing.
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
HalpCheckPerformanceCounter(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called every system clock interrupt in order to
|
|
check for wrap of the performance counter. The function must handle
|
|
a wrap if it is detected.
|
|
|
|
N.B. - This function must be called at CLOCK_LEVEL.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
LARGE_INTEGER LocalRpccTime;
|
|
ULONG RpccValue;
|
|
|
|
//
|
|
// Update the low part of the performance counter directly from the
|
|
// rpcc count. Check for wrap of the rpcc count, if wrap has occurred
|
|
// then increment the high part of the performance counter.
|
|
//
|
|
|
|
LocalRpccTime.QuadPart = HalpCycleCount;
|
|
RpccValue = HalpRpcc();
|
|
|
|
if (RpccValue < LocalRpccTime.LowPart) {
|
|
LocalRpccTime.HighPart += 1;
|
|
}
|
|
|
|
LocalRpccTime.LowPart = RpccValue;
|
|
|
|
HalpCycleCount = LocalRpccTime.QuadPart;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
VOID
|
|
KeStallExecutionProcessor (
|
|
IN ULONG Microseconds
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function stalll execution of the current processor for the specified
|
|
number of microseconds.
|
|
|
|
Arguments:
|
|
|
|
Microseconds - Supplies the number of microseconds to stall.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
LONG StallCyclesRemaining; // signed value
|
|
ULONG PreviousRpcc, CurrentRpcc;
|
|
|
|
//
|
|
// Get the value of the RPCC as soon as we enter
|
|
//
|
|
|
|
PreviousRpcc = HalpRpcc();
|
|
|
|
//
|
|
// Compute the number of cycles to stall
|
|
//
|
|
|
|
StallCyclesRemaining = Microseconds * HalpClockMegaHertz;
|
|
|
|
//
|
|
// Wait while there are stall cycles remaining.
|
|
// The accuracy of this routine is limited by the
|
|
// length of this while loop.
|
|
//
|
|
|
|
while (StallCyclesRemaining > 0) {
|
|
|
|
CurrentRpcc = HalpRpcc();
|
|
|
|
//
|
|
// The subtraction always works because the Rpcc
|
|
// is a wrapping long-word. If it wraps, we still
|
|
// get the positive number we want.
|
|
//
|
|
|
|
StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc);
|
|
|
|
//
|
|
// remember this RPCC value
|
|
//
|
|
|
|
PreviousRpcc = CurrentRpcc;
|
|
}
|
|
|
|
}
|
|
|