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.
316 lines
6.6 KiB
316 lines
6.6 KiB
/*++
|
|
|
|
Copyright (c) 1991-1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
j4prof.c
|
|
|
|
Abstract:
|
|
|
|
This module contains the code to start and stop the profiling interrupt
|
|
and to compute the profiling interval for a MIPS R4000 Jazz system.
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
|
|
|
|
//
|
|
// Define one second and round values.
|
|
//
|
|
|
|
#define ONE_SECOND (10 * 1000 * 1000) // 1 second in 100ns units
|
|
#define ROUND_VALUE ((ONE_SECOND) - 1) // 1 second minus 100ns
|
|
|
|
//
|
|
// Define static data.
|
|
//
|
|
|
|
LARGE_INTEGER HalpPerformanceCounter[8];
|
|
ULONG HalpProfileInterval = DEFAULT_PROFILE_INTERVAL;
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
ULONG CurrentCount;
|
|
KIRQL OldIrql;
|
|
LARGE_INTEGER PerformanceCounter;
|
|
|
|
//
|
|
// Raise IRQL to PROFILE_LEVEL, read the current value of the count
|
|
// register, read the performance counter, and lower IRQL to its
|
|
// previous value.
|
|
//
|
|
// N.B. The minimum, maximum, and default values for the profile
|
|
// count are chosen such that count register only overflows
|
|
// after about 20 seconds at 50mhz. Therefore, there is never
|
|
// a problem with the counter wrapping in the following code.
|
|
//
|
|
|
|
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
|
CurrentCount = HalpReadCountRegister();
|
|
PerformanceCounter = HalpPerformanceCounter[KeGetCurrentPrcb()->Number];
|
|
KeLowerIrql(OldIrql);
|
|
|
|
//
|
|
// If the frequency parameter is specified, then return the performance
|
|
// counter frequency as the current system time frequency.
|
|
//
|
|
|
|
if (ARGUMENT_PRESENT(Frequency) != FALSE) {
|
|
Frequency->QuadPart = HalpProfileCountRate;
|
|
}
|
|
|
|
//
|
|
// Return the value of the performance counter.
|
|
//
|
|
|
|
PerformanceCounter.QuadPart += CurrentCount;
|
|
return PerformanceCounter;
|
|
}
|
|
|
|
|
|
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.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
KSPIN_LOCK Lock;
|
|
KIRQL OldIrql;
|
|
PKPRCB Prcb;
|
|
|
|
//
|
|
// Raise IRQL to HIGH_LEVEL, decrement the number of processors, and
|
|
// wait until the number is zero.
|
|
//
|
|
|
|
KeInitializeSpinLock(&Lock);
|
|
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
|
if (ExInterlockedDecrementLong(Number, &Lock) != RESULT_ZERO) {
|
|
do {
|
|
|
|
} while (*Number !=0);
|
|
}
|
|
|
|
//
|
|
// Write the compare register, clear the count register, and zero the
|
|
// performance counter for the current processor.
|
|
//
|
|
|
|
HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
|
|
Prcb = KeGetCurrentPrcb();
|
|
HalpPerformanceCounter[Prcb->Number].QuadPart = 0;
|
|
|
|
//
|
|
// Restore IRQL to its previous value and return.
|
|
//
|
|
|
|
KeLowerIrql(OldIrql);
|
|
return;
|
|
}
|
|
|
|
ULONG
|
|
HalSetProfileInterval (
|
|
IN ULONG Interval
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the profile interrupt interval.
|
|
|
|
Arguments:
|
|
|
|
Interval - Supplies the desired profile interval in 100ns units.
|
|
|
|
Return Value:
|
|
|
|
The actual profile interval.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
LARGE_INTEGER TempValue;
|
|
|
|
//
|
|
// If the specified profile interval is less that the minimum profile
|
|
// interval or greater than the maximum profile interval, then set the
|
|
// profile interval to the minimum or maximum as appropriate.
|
|
//
|
|
|
|
if (Interval < MINIMUM_PROFILE_INTERVAL) {
|
|
Interval = MINIMUM_PROFILE_INTERVAL;
|
|
|
|
} else if (Interval > MAXIMUM_PROFILE_INTERVAL) {
|
|
Interval = MAXIMUM_PROFILE_INTERVAL;
|
|
}
|
|
|
|
//
|
|
// First compute the profile count value and then back calculate the
|
|
// actual profile interval.
|
|
//
|
|
|
|
TempValue.QuadPart = Int32x32To64(HalpProfileCountRate, Interval);
|
|
TempValue.QuadPart += ROUND_VALUE;
|
|
TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL);
|
|
TempValue.QuadPart = Int32x32To64(TempValue.LowPart, ONE_SECOND);
|
|
TempValue = RtlExtendedLargeIntegerDivide(TempValue, HalpProfileCountRate, NULL);
|
|
HalpProfileInterval = TempValue.LowPart;
|
|
return HalpProfileInterval;
|
|
}
|
|
|
|
VOID
|
|
HalStartProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine computes the profile count value, writes the compare
|
|
register, clears the count register, and updates the performance
|
|
counter.
|
|
|
|
N.B. This routine must be called at PROFILE_LEVEL while holding the
|
|
profile lock.
|
|
|
|
Arguments:
|
|
|
|
Source - Supplies the profile source.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKPRCB Prcb;
|
|
ULONG PreviousCount;
|
|
LARGE_INTEGER TempValue;
|
|
|
|
//
|
|
// Compute the profile count from the current profile interval.
|
|
//
|
|
|
|
TempValue.QuadPart = Int32x32To64(HalpProfileCountRate,
|
|
HalpProfileInterval);
|
|
|
|
TempValue.QuadPart += ROUND_VALUE;
|
|
TempValue = RtlExtendedLargeIntegerDivide(TempValue, ONE_SECOND, NULL);
|
|
|
|
//
|
|
// Write the compare register and clear the count register.
|
|
//
|
|
|
|
PreviousCount = HalpWriteCompareRegisterAndClear(TempValue.LowPart);
|
|
|
|
//
|
|
// Update the performance counter by adding in the previous count value.
|
|
//
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount;
|
|
return;
|
|
}
|
|
|
|
VOID
|
|
HalStopProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the default count value, writes the compare
|
|
register, clears the count register, and updates the performance
|
|
counter.
|
|
|
|
N.B. This routine must be called at PROFILE_LEVEL while holding the
|
|
profile lock.
|
|
|
|
Arguments:
|
|
|
|
Source - Provides the profile source.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
PKPRCB Prcb;
|
|
ULONG PreviousCount;
|
|
|
|
//
|
|
// Write the compare register and clear the count register.
|
|
//
|
|
|
|
PreviousCount = HalpWriteCompareRegisterAndClear(DEFAULT_PROFILE_COUNT);
|
|
|
|
//
|
|
// Update the performance counter by adding in the previous count value.
|
|
//
|
|
|
|
Prcb = KeGetCurrentPrcb();
|
|
HalpPerformanceCounter[Prcb->Number].QuadPart += PreviousCount;
|
|
return;
|
|
}
|