NT4/private/ntos/nthals/halalpha/ev4prof.c
2020-09-30 17:12:29 +02:00

592 lines
14 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
Copyright (c) 1994 Digital Equipment Corporation
Module Name:
ev4prof.c
Abstract:
This module implements the Profile Counter using the performance
counters within the EV4 core. This module is appropriate for all
machines based on microprocessors using the EV4 core.
N.B. - This module assumes that all processors in a multiprocessor
system are running the microprocessor at the same clock speed.
Author:
Joe Notarangelo 22-Feb-1994
Environment:
Kernel mode
Revision History:
--*/
#include "halp.h"
#include "axp21064.h"
//
// Define space in the HAL-reserved part of the PCR structure for each
// performance counter's interval count
//
// Note that ev4ints.s depends on these positions in the PCR.
//
#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount))
#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload))
//
// Define the currently selected profile source for each counter
//
KPROFILE_SOURCE HalpProfileSource0;
KPROFILE_SOURCE HalpProfileSource1;
#define INTERVAL_DELTA (10)
//
// Define the mapping between possible profile sources and the
// CPU-specific settings.
//
typedef struct _HALP_PROFILE_MAPPING {
BOOLEAN Supported;
ULONG MuxControl;
ULONG Counter;
ULONG EventCount;
ULONG NumberOfTicks;
} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING;
HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] =
{
{TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
{FALSE, 0, 0, 0, 0},
{TRUE, Ev4TotalIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{TRUE, Ev4PipelineDry, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{TRUE, Ev4LoadInstruction, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
{TRUE, Ev4PipelineFrozen, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{TRUE, Ev4BranchInstructions, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
{TRUE, Ev4TotalNonIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{TRUE, Ev4DcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{TRUE, Ev4IcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{FALSE, 0, 0, 0, 0},
{TRUE, Ev4BranchMispredicts, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{TRUE, Ev4StoreInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{TRUE, Ev4FPInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{TRUE, Ev4IntegerOperate, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{TRUE, Ev4DualIssues, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
{FALSE, 0, 0, 0, 0},
{FALSE, 0, 0, 0, 0},
{TRUE, Ev4PalMode, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
{FALSE, 0, 0, 0, 0},
{FALSE, 0, 0, 0, 0}
};
BOOLEAN
HalQueryProfileInterval(
IN KPROFILE_SOURCE Source
);
NTSTATUS
HalSetProfileSourceInterval(
IN KPROFILE_SOURCE ProfileSource,
IN OUT ULONG *Interval
);
NTSTATUS
HalpProfileSourceInformation (
OUT PVOID Buffer,
IN ULONG BufferLength,
OUT PULONG ReturnedLength
)
/*++
Routine Description:
Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
Arguments:
Buffer - output buffer
BufferLength - length of buffer on input
ReturnedLength - The length of data returned
Return Value:
STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
currently needed.
--*/
{
PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
NTSTATUS Status;
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
return Status;
}
SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
if (SourceInfo->Supported) {
SourceInfo->Interval =
HalpProfileMapping[SourceInfo->Source].EventCount *
HalpProfileMapping[SourceInfo->Source].NumberOfTicks;
if (SourceInfo->Source == ProfileTotalIssues) {
//
// Convert total issues/2 back into total issues
//
SourceInfo->Interval = SourceInfo->Interval * 2;
}
}
Status = STATUS_SUCCESS;
return Status;
}
NTSTATUS
HalpProfileSourceInterval (
OUT PVOID Buffer,
IN ULONG BufferLength
)
/*++
Routine Description:
Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
Arguments:
Buffer - output buffer
BufferLength - length of buffer on input
Return Value:
STATUS_SUCCESS
STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
currently needed.
--*/
{
PHAL_PROFILE_SOURCE_INTERVAL Interval;
NTSTATUS Status;
if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
Status = STATUS_INFO_LENGTH_MISMATCH;
return Status;
}
Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
Status = HalSetProfileSourceInterval(Interval->Source,
&Interval->Interval);
return Status;
}
VOID
HalpInitializeProfiler(
VOID
)
/*++
Routine Description:
This routine is called during initialization to initialize profiling
for each processor in the system.
Arguments:
None.
Return Value:
None.
--*/
{
PKINTERRUPT InterruptObject;
KIRQL Irql;
PKPRCB Prcb = PCR->Prcb;
ULONG Vector;
//
// Establish the profile interrupt as the interrupt handler for
// all performance counter interrupts.
//
PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt;
PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt;
return;
}
BOOLEAN
HalQueryProfileInterval(
IN KPROFILE_SOURCE Source
)
/*++
Routine Description:
Given a profile source, returns whether or not that source is
supported.
Arguments:
Source - Supplies the profile source
Return Value:
TRUE - Profile source is supported
FALSE - Profile source is not supported
--*/
{
if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) {
return(FALSE);
}
return(HalpProfileMapping[Source].Supported);
}
NTSTATUS
HalSetProfileSourceInterval(
IN KPROFILE_SOURCE ProfileSource,
IN OUT ULONG *Interval
)
/*++
Routine Description:
Sets the profile interval for a specified profile source
Arguments:
ProfileSource - Supplies the profile source
Interval - Supplies the specified profile interval
Returns the actual profile interval
Return Value:
NTSTATUS
--*/
{
ULONG FastTickPeriod;
ULONG SlowTickPeriod;
ULONG TickPeriod;
ULONGLONG CountEvents;
ULONG FastCountEvents;
ULONG SlowCountEvents;
ULONGLONG TempInterval;
if (!HalQueryProfileInterval(ProfileSource)) {
return(STATUS_NOT_IMPLEMENTED);
}
if (ProfileSource == ProfileTime) {
//
// Convert the clock tick period (in 100ns units ) into
// a cycle count period
//
CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod;
} else if (ProfileSource == ProfileTotalIssues) {
//
// Convert the total issue events into the wonky
// total issues/2 form implemented by EV4.
//
CountEvents = (ULONGLONG)(*Interval / 2);
} else {
CountEvents = (ULONGLONG)*Interval;
}
if (HalpProfileMapping[ProfileSource].Counter == Ev4PerformanceCounter1) {
FastCountEvents = Ev4CountEvents2xx8;
SlowCountEvents = Ev4CountEvents2xx12;
} else {
FastCountEvents = Ev4CountEvents2xx12;
SlowCountEvents = Ev4CountEvents2xx16;
}
//
// Limit the interval to the smallest interval we can time.
//
if (CountEvents < FastCountEvents) {
CountEvents = (ULONGLONG)FastCountEvents;
}
//
// Assume we will use the fast event count
//
HalpProfileMapping[ProfileSource].EventCount = FastCountEvents;
HalpProfileMapping[ProfileSource].NumberOfTicks =
(ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents);
//
// See if we can successfully use the slower period. If the requested
// interval is greater than the slower tick period and the difference
// between the requested interval and the interval that we can deliver
// with the slower clock is acceptable, then use the slower clock.
// We define an acceptable difference as a difference of less than
// INTERVAL_DELTA of the requested interval.
//
if (CountEvents > SlowCountEvents) {
ULONG NewInterval;
NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) /
SlowCountEvents) * SlowCountEvents);
if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) {
HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents;
HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents;
}
}
*Interval = HalpProfileMapping[ProfileSource].EventCount *
HalpProfileMapping[ProfileSource].NumberOfTicks;
if (ProfileSource == ProfileTime) {
//
// Convert cycle count back into 100ns clock ticks
//
// Use 64-bit integer to prevent overflow.
//
TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod);
*Interval = (ULONG)(TempInterval / 100000);
} else if (ProfileSource == ProfileTotalIssues) {
//
// Convert issues/2 count back into issues
//
TempInterval = (ULONGLONG)(*Interval) * 2;
*Interval = (ULONG)TempInterval;
}
return(STATUS_SUCCESS);
}
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.
--*/
{
ULONG NewInterval;
NewInterval = Interval;
HalSetProfileSourceInterval(ProfileTime, &NewInterval);
return(NewInterval);
}
VOID
HalStartProfileInterrupt (
KPROFILE_SOURCE ProfileSource
)
/*++
Routine Description:
This routine turns on the profile interrupt.
N.B. This routine must be called at PROCLK_LEVEL while holding the
profile lock.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG PerformanceCounter;
ULONG MuxControl;
ULONG EventCount;
//
// Check input to see if we are turning on a source that is
// supported. If it is unsupported, just return.
//
if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
(!HalpProfileMapping[ProfileSource].Supported)) {
return;
}
//
// Set the performance counter within the processor to begin
// counting total cycles.
//
PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
MuxControl = HalpProfileMapping[ProfileSource].MuxControl;
if (PerformanceCounter == Ev4PerformanceCounter0) {
HalpProfileSource0 = ProfileSource;
EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
Ev4EventCountHigh :
Ev4EventCountLow;
HalpWritePerformanceCounter( PerformanceCounter,
TRUE,
MuxControl,
EventCount );
PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
//
// Enable the performance counter interrupt.
//
HalEnableSystemInterrupt ( PC0_VECTOR,
PROFILE_LEVEL,
LevelSensitive );
} else {
HalpProfileSource1 = ProfileSource;
EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
Ev4EventCountLow :
Ev4EventCountHigh;
HalpWritePerformanceCounter( PerformanceCounter,
TRUE,
MuxControl,
EventCount );
PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
//
// Enable the performance counter interrupt.
//
HalEnableSystemInterrupt ( PC1_VECTOR,
PROFILE_LEVEL,
LevelSensitive );
}
return;
}
VOID
HalStopProfileInterrupt (
KPROFILE_SOURCE ProfileSource
)
/*++
Routine Description:
This routine turns off the profile interrupt.
N.B. This routine must be called at PROCLK_LEVEL while holding the
profile lock.
Arguments:
None.
Return Value:
None.
--*/
{
ULONG PerformanceCounter;
ULONG Vector;
//
// Check input to see if we are turning off a source that is
// supported. If it is unsupported, just return.
//
if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
(!HalpProfileMapping[ProfileSource].Supported)) {
return;
}
//
// Stop the performance counter from interrupting.
//
PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
HalpWritePerformanceCounter( PerformanceCounter,
FALSE,
0,
0 );
//
// Disable the performance counter interrupt.
//
if (PerformanceCounter == Ev4PerformanceCounter0) {
HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL );
//
// Clear the current profile count. Can't clear value in PCR
// since a profile interrupt could be pending or in progress
// so clear the reload counter.
//
PCRProfileCountReload[0] = 0;
} else {
HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL );
//
// Clear the current profile count. Can't clear value in PCR
// since a profile interrupt could be pending or in progress
// so clear the reload counter.
//
PCRProfileCountReload[0] = 0;
}
return;
}