261 lines
5.0 KiB
C
261 lines
5.0 KiB
C
/*++
|
||
|
||
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;
|
||
}
|
||
|
||
}
|
||
|