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.
2048 lines
56 KiB
2048 lines
56 KiB
/*++
|
|
|
|
Copyright (c) 2000 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
i64prfle.c
|
|
|
|
Abstract:
|
|
|
|
|
|
This module implements the IA64 Hal Profiling using the performance
|
|
counters within the core of the first IA64 Processor Merced, aka Itanium.
|
|
This module is appropriate for all machines based on microprocessors using
|
|
the Merced core.
|
|
|
|
With the information known at this development time, this module tries to
|
|
consider the future IA64 processor cores by encapsulating the differences
|
|
in specific micro-architecture data structures.
|
|
|
|
Furthermore, with the implementation of the new NT ACPI Processor driver, this
|
|
implementation will certainly change in the coming months.
|
|
|
|
N.B. - This module assumes that all processors in a multiprocessor
|
|
system are running the microprocessor at the same clock speed.
|
|
|
|
Author:
|
|
|
|
Thierry Fevrier 08-Feb-2000
|
|
|
|
Environment:
|
|
|
|
Kernel mode only.
|
|
|
|
Revision History:
|
|
|
|
02-2002: Thierry for McKinley support.
|
|
|
|
--*/
|
|
|
|
#include "halp.h"
|
|
|
|
//
|
|
// Assumptions for the current implementation - 02/08/2000 :
|
|
// These assumptions will be re-evaluated and worked out if required.
|
|
//
|
|
// - Respect and satisfy as much possible the Profiling Sources interface
|
|
// already defined by NT and HAL.
|
|
//
|
|
// - All processors in a multiprocessor system are running the microprocessor
|
|
// at the same invariant clock speed.
|
|
//
|
|
// - All processors are configured with the same set of profiling counters.
|
|
// XXTF - 04/01/2000 - This assumption is being re-worked and will disappear.
|
|
//
|
|
// - Profiling is based on the processor monitored events and if possible
|
|
// on derived events.
|
|
//
|
|
// - A monitored event can only be enabled on one performance counter at a time.
|
|
//
|
|
|
|
//
|
|
// IA64 performance counters defintions:
|
|
// - event counters
|
|
// - EARS
|
|
// - BTBs
|
|
// - ...
|
|
//
|
|
|
|
#include "ia64prof.h"
|
|
#include "merced.h"
|
|
#include "mckinley.h"
|
|
|
|
//
|
|
// HALIA64 Processor PMC Reset definitions:
|
|
//
|
|
//
|
|
// PMC Reset value:
|
|
// Reg. Field Bits
|
|
// PMC* .plm - 3: 0 - Privilege Mask - 0 (Disable Counter)
|
|
// PMC* .ev - 4 - External Visibility - 0 (Disabled)
|
|
// PMC* .oi - 5 - Overflow Interrupt - 0 (Disabled)
|
|
// PMC* .pm - 6 - Privilege Monitor - 0 (user monitor)
|
|
// PMC* .ig - 7 - Ignored - 0
|
|
// PMC* .es - 14: 8 - Event Select - 0 (Warning - 0x0 = Real Event)
|
|
// PMC* .ig - 15 - Ignored - 0
|
|
// PMC* .umask - 19:16 - Unit Mask - 0 (event specific. ok for .es=0)
|
|
// PMC4,5 .threshold - 22:20 - Threshold - 0 (multi-occurence events threshold)
|
|
// PMC4 .pmu - 23 - enable PMU - 1
|
|
// PMC5 .ig - 23 - Ignored - 0
|
|
// PMC6,7 .threshold - 21:20 - Threshold - 0 (multi-occurence events threshold)
|
|
// PMC6,7 .ig - 23:22 - Ignored - 0
|
|
// PMC* .ism - 25:24 - Instruction Set Mask - 0 (IA64 & IA32 sets - 11:disables monitoring)
|
|
// PMC* .ig - 63:26 - Ignored
|
|
// ===
|
|
// HALP_PMC_RESET
|
|
// HALP_PMC4_RESET
|
|
//
|
|
|
|
#define HALP_PMC_RESET 0x0000000000000000ui64
|
|
#define HALP_PMC4_RESET 0x0000000000800000ui64 // PMC4.pmu{bit23} enabled.
|
|
|
|
//
|
|
// HALIA64 Processor PMC Clear Status Masks:
|
|
//
|
|
// Note - FIXFIX - Merced, McKinley specific definitions.
|
|
//
|
|
|
|
#define HALP_PMC0_CLEAR_STATUS_MASK 0xFFFFFFFFFFFFFF0Eui64
|
|
#define HALP_PMC1_CLEAR_STATUS_MASK 0xFFFFFFFFFFFFFFFFui64
|
|
#define HALP_PMC2_CLEAR_STATUS_MASK 0xFFFFFFFFFFFFFFFFui64
|
|
#define HALP_PMC3_CLEAR_STATUS_MASK 0xFFFFFFFFFFFFFFFFui64
|
|
|
|
////////////////
|
|
//
|
|
// HALIA64 Profile IA64 MicroArchitecture NameSpace
|
|
//
|
|
|
|
extern HALP_PROFILE_MAPPING HalpMercedProfileMapping[];
|
|
extern HALP_PROFILE_MAPPING HalpMcKinleyProfileMapping[];
|
|
|
|
#define HalpMercedPerfMonDataMaximumCount ((((ULONGLONG)1)<<32)-1)
|
|
#define HalpMcKinleyPerfMonDataMaximumCount ((((ULONGLONG)1)<<47)-1)
|
|
|
|
typedef enum _HALP_PROFILE_MICROARCHITECTURE {
|
|
HALP_PROFILE_IA64_MERCED = 0x0,
|
|
HALP_PROFILE_IA64_MCKINLEY = 0x1,
|
|
} HALP_PROFILE_MICROARCHITECTURE;
|
|
|
|
struct _HALP_PROFILE_INFO {
|
|
HALP_PROFILE_MICROARCHITECTURE ProfileMicroArchitecture;
|
|
BOOLEAN ProfilePerfMonCnfg0FreezeBitInterrupt;
|
|
BOOLEAN ProfileSpare0;
|
|
USHORT ProfilePerfMonGenericPairs;
|
|
HALP_PROFILE_MAPPING *ProfileMapping;
|
|
ULONG ProfileSourceMaximum;
|
|
ULONG ProfileSourceDerivedEventMinimum;
|
|
ULONGLONG ProfilePerfMonDataMaximumCount;
|
|
ULONGLONG ProfilePerfMonCnfg0ClearStatusMask;
|
|
ULONGLONG ProfilePerfMonCnfg1ClearStatusMask;
|
|
ULONGLONG ProfilePerfMonCnfg2ClearStatusMask;
|
|
ULONGLONG ProfilePerfMonCnfg3ClearStatusMask;
|
|
} HalpProfileInfo = {
|
|
//
|
|
// Default IA64 Profiling to McKinley-core
|
|
//
|
|
// Note that different models in a family might have different PMU implementations.
|
|
//
|
|
HALP_PROFILE_IA64_MCKINLEY,
|
|
TRUE,
|
|
0,
|
|
NUMBER_OF_PERFMON_REGISTER_PAIRS,
|
|
HalpMcKinleyProfileMapping,
|
|
ProfileMcKinleyMaximum,
|
|
ProfileMcKinleyDerivedEventMinimum,
|
|
HalpMcKinleyPerfMonDataMaximumCount,
|
|
HALP_PMC0_CLEAR_STATUS_MASK,
|
|
HALP_PMC1_CLEAR_STATUS_MASK,
|
|
HALP_PMC2_CLEAR_STATUS_MASK,
|
|
HALP_PMC3_CLEAR_STATUS_MASK
|
|
};
|
|
|
|
#define HalpProfileIA64MicroArchitecture HalpProfileInfo.ProfileMicroArchitecture
|
|
#define HalpProfileMapping HalpProfileInfo.ProfileMapping
|
|
|
|
#define HalpProfileIA64Maximum HalpProfileInfo.ProfileSourceMaximum
|
|
#define HalpProfileIA64DerivedEventMinimum HalpProfileInfo.ProfileSourceDerivedEventMinimum
|
|
|
|
#define HalpPerfMonGenericPairs HalpProfileInfo.ProfilePerfMonGenericPairs
|
|
#define HalpPerfMonDataMaximumCount HalpProfileInfo.ProfilePerfMonDataMaximumCount
|
|
#define HalpPerfMonCnfg0FreezeBitInterrupt HalpProfileInfo.ProfilePerfMonCnfg0FreezeBitInterrupt
|
|
#define HalpPerfMonCnfg0ClearStatusMask HalpProfileInfo.ProfilePerfMonCnfg0ClearStatusMask
|
|
#define HalpPerfMonCnfg1ClearStatusMask HalpProfileInfo.ProfilePerfMonCnfg1ClearStatusMask
|
|
#define HalpPerfMonCnfg2ClearStatusMask HalpProfileInfo.ProfilePerfMonCnfg2ClearStatusMask
|
|
#define HalpPerfMonCnfg3ClearStatusMask HalpProfileInfo.ProfilePerfMonCnfg3ClearStatusMask
|
|
|
|
//
|
|
// End of HALIA64 Profile IA64 MicroArchitecture NameSpace
|
|
//
|
|
////////////////
|
|
|
|
//
|
|
// HALIA64 Profile Source Mapping macros:
|
|
//
|
|
|
|
#define HalpDisactivateProfileSource( _ProfileSource ) ((_ProfileSource) = HalpProfileIA64Maximum)
|
|
#define HalpIsProfileSourceActive( _ProfileSource ) ((_ProfileSource) != HalpProfileIA64Maximum)
|
|
#define HalpIsProfileMappingInvalid( _ProfileMapping ) \
|
|
(!(_ProfileMapping) || ((_ProfileMapping)->Supported == FALSE))
|
|
|
|
// HalpIsProfileSourceDerivedEvent assumes ProfileMapping is valid and supported.
|
|
|
|
#define HalpIsProfileSourceDerivedEvent( _ProfileSource, _ProfileMapping ) \
|
|
(((_ProfileSource) >= (KPROFILE_SOURCE)HalpProfileIA64DerivedEventMinimum) || \
|
|
((_ProfileMapping)->Event >= 0x100))
|
|
|
|
VOID
|
|
HalpSetProfileMicroArchitecture(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the HAL Profile MicroArchitecture namespace.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG cpuFamily;
|
|
PIA64_PERFMON_INFO perfMonInfo;
|
|
USHORT genericPairs;
|
|
|
|
cpuFamily = ((LoaderBlock->u.Ia64.ProcessorConfigInfo.CpuId3) >> 24) & 0xff;
|
|
perfMonInfo = &LoaderBlock->u.Ia64.ProcessorConfigInfo.PerfMonInfo;
|
|
|
|
HalpPerfMonDataMaximumCount =
|
|
((((ULONGLONG)1)<<(perfMonInfo->ImplementedCounterWidth))-1);
|
|
genericPairs = HalpPerfMonGenericPairs = (USHORT) perfMonInfo->PerfMonGenericPairs;
|
|
#if 0
|
|
// 03/2002 FIXFIX ToBeTested.
|
|
HalpPerfMonCnfg3ClearStatusMask = (genericPairs > 192) ? ((ULONGLONG)-1) << (genericPairs - 192)
|
|
: HALP_PMC3_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg2ClearStatusMask = (genericPairs > 128) ? ((ULONGLONG)-1) << (genericPairs - 128)
|
|
: HALP_PMC2_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg1ClearStatusMask = (genericPairs > 64) ? ((ULONGLONG)-1) << (genericPairs - 64)
|
|
: HALP_PMC1_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg0ClearStatusMask = (genericPairs > 4) ? ((((ULONGLONG)-1) << (genericPairs + 4)) | 0x0E)
|
|
: HALP_PMC0_CLEAR_STATUS_MASK;
|
|
#else
|
|
HalpPerfMonCnfg3ClearStatusMask = HALP_PMC3_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg2ClearStatusMask = HALP_PMC2_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg1ClearStatusMask = HALP_PMC1_CLEAR_STATUS_MASK;
|
|
HalpPerfMonCnfg0ClearStatusMask = HALP_PMC0_CLEAR_STATUS_MASK;
|
|
if ( genericPairs > 192 ) {
|
|
HalpPerfMonCnfg3ClearStatusMask = ((ULONGLONG)-1) << (genericPairs - 192);
|
|
}
|
|
else if ( genericPairs > 128 ) {
|
|
HalpPerfMonCnfg2ClearStatusMask = ((ULONGLONG)-1) << (genericPairs - 128);
|
|
}
|
|
else if ( genericPairs > 64 ) {
|
|
HalpPerfMonCnfg1ClearStatusMask = ((ULONGLONG)-1) << (genericPairs - 64);
|
|
}
|
|
else {
|
|
HalpPerfMonCnfg0ClearStatusMask = ((((ULONGLONG)-1) << (genericPairs + 4)) | 0x0E);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// HALIA64 SW default profile microarchitecture is McKinley.
|
|
//
|
|
|
|
if (cpuFamily == 0x7) { // Merced
|
|
HalpProfileIA64MicroArchitecture = HALP_PROFILE_IA64_MERCED;
|
|
HalpProfileIA64Maximum = ProfileMercedMaximum;
|
|
HalpProfileMapping = HalpMercedProfileMapping;
|
|
HalpProfileIA64DerivedEventMinimum = ProfileMercedDerivedEventMinimum;
|
|
|
|
HalpPerfMonCnfg0FreezeBitInterrupt = FALSE;
|
|
}
|
|
|
|
//
|
|
// XXTF FIXFIX - 03/02
|
|
// ASSERTMSG assertions are missing to correlate HALIA64 defaults and OSLOADER PERFMON_INFO data.
|
|
//
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileMicroArchitecture()
|
|
|
|
VOID
|
|
HalpEnableProfileCounting (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the profile counters to increment.
|
|
This function is the counterpart of HalpDisableProfileCounting().
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG Data, ClearStatusMask;
|
|
|
|
//
|
|
// Clear PMC0.fr - bit 0.
|
|
// Clear PMCO,1,2,3 OverFlow Bits.
|
|
//
|
|
|
|
HalpClearPerfMonCnfgOverflows( HalpPerfMonCnfg0ClearStatusMask,
|
|
HalpPerfMonCnfg1ClearStatusMask,
|
|
HalpPerfMonCnfg2ClearStatusMask,
|
|
HalpPerfMonCnfg3ClearStatusMask );
|
|
|
|
if ( HalpPerfMonCnfg0FreezeBitInterrupt ) {
|
|
HalpUnFreezeProfileCounting();
|
|
}
|
|
|
|
return;
|
|
|
|
} // HalpEnableProfileCounting()
|
|
|
|
VOID
|
|
HalpDisableProfileCounting (
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the profile counters to increment.
|
|
This function is the counterpart of HalpEnableProfileCounting().
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
if ( HalpPerfMonCnfg0FreezeBitInterrupt ) {
|
|
HalpFreezeProfileCounting();
|
|
}
|
|
else {
|
|
HalpWritePerfMonCnfgReg0( HalpReadPerfMonCnfgReg0() | 0x1 );
|
|
}
|
|
|
|
return;
|
|
|
|
} // HalpDisableProfileCounting()
|
|
|
|
VOID
|
|
HalpSetupProfilingPhase0(
|
|
IN PLOADER_PARAMETER_BLOCK LoaderBlock
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called at HalInitSystem - phase 0 time to set
|
|
the initial state of processor and profiling os subsystem with
|
|
regards to the profiling functionality.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Implementation Note:
|
|
|
|
Executed at Phase 0 on Monarch processor.
|
|
|
|
--*/
|
|
{
|
|
|
|
// Set the Profile MicroArchitecture namespace based on
|
|
// the monarch processor.
|
|
|
|
HalpSetProfileMicroArchitecture( LoaderBlock );
|
|
|
|
return;
|
|
|
|
} // HalpSetupProfilingPhase0()
|
|
|
|
VOID
|
|
HalpSetProfileCounterInterval (
|
|
IN ULONG Counter,
|
|
IN LONGLONG NextCount
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function preloads the specified counter with a count value
|
|
of 2^IMPL_BITS - NextCount.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
NextCount - Supplies the value to preload in the monitor.
|
|
An external interruption will be generated after NextCount.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
LONGLONG Count;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
Count = (HalpPerfMonDataMaximumCount + 1) - NextCount;
|
|
if ( (ULONGLONG)Count >= HalpPerfMonDataMaximumCount ) {
|
|
Count = 0;
|
|
}
|
|
HalpWritePerfMonDataReg( Counter, (ULONGLONG)Count );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterInterval()
|
|
|
|
VOID
|
|
HalpSetProfileCounterPrivilegeLevelMask(
|
|
IN ULONG Counter,
|
|
IN ULONG Mask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function set the profile counter privilege level mask.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Mask - Supplies the privilege level mask to program the PMC with.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, plmMask;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
plmMask = Mask & 0xF;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~0xF;
|
|
data |= plmMask;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterPrivilegeLevelMask()
|
|
|
|
VOID
|
|
HalpEnableProfileCounterOverflowInterrupt (
|
|
IN ULONG Counter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the delivery of an overflow interrupt for
|
|
the specified profile counter.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, mask;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
mask = 1<<5;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data |= mask;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpEnableProfileCounterOverflowInterrupt()
|
|
|
|
VOID
|
|
HalpDisableProfileCounterOverflowInterrupt (
|
|
IN ULONG Counter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the delivery of an overflow interrupt for
|
|
the specified profile counter.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, mask;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
mask = 1<<5;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~mask;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpDisableProfileCounterOverflowInterrupt()
|
|
|
|
VOID
|
|
HalpEnableProfileCounterPrivilegeMonitor(
|
|
IN ULONG Counter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the profile counter as privileged monitor.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, pm;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
pm = 1<<6;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data |= pm;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpEnableProfileCounterPrivilegeMonitor()
|
|
|
|
VOID
|
|
HalpDisableProfileCounterPrivilegeMonitor(
|
|
IN ULONG Counter
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the profile counter as privileged monitor.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, pm;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
pm = 1<<6;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~pm;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpDisableProfileCounterPrivilegeMonitor()
|
|
|
|
VOID
|
|
HalpSetProfileCounterEvent(
|
|
IN ULONG Counter,
|
|
IN ULONG Event
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The function specifies the monitor event for the profile counter.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Event - Supplies the monitor event code.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, es;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
es = (Event & 0x7F) << 8;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~(0x7F << 8);
|
|
data |= es;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterEvent()
|
|
|
|
VOID
|
|
HalpSetProfileCounterUmask(
|
|
IN ULONG Counter,
|
|
IN ULONG Umask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the event specific umask value for the profile
|
|
counter.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Umask - Supplies the event specific umask value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, um;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
um = (Umask & 0xF) << 16;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~(0xF << 16);
|
|
data |= um;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterUmask()
|
|
|
|
VOID
|
|
HalpSetProfileCounterThreshold(
|
|
IN ULONG Counter,
|
|
IN ULONG Threshold
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the profile counter threshold.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Threshold - Supplies the desired threshold.
|
|
This is related to multi-occurences events.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, reset, th;
|
|
|
|
switch( Counter ) {
|
|
case 4:
|
|
case 5:
|
|
Threshold &= 0x7;
|
|
reset = ~(0x7 << 20);
|
|
break;
|
|
|
|
case 6:
|
|
case 7:
|
|
Threshold &= 0x3;
|
|
reset = ~(0x3 << 20);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
|
|
th = Threshold << 20;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= reset;
|
|
data |= th;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterThreshold()
|
|
|
|
VOID
|
|
HalpSetProfileCounterInstructionSetMask(
|
|
IN ULONG Counter,
|
|
IN ULONG Mask
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function sets the instruction set mask for the profile counter.
|
|
|
|
Arguments:
|
|
|
|
Counter - Supplies the performance counter register number.
|
|
|
|
Mask - Supplies the instruction set mask.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, ismMask;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
ismMask = (Mask & 0x3) << 24;
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
data &= ~(0x3 << 24);
|
|
data |= ismMask;
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
return;
|
|
|
|
} // HalpSetProfileCounterInstructionSetMask()
|
|
|
|
ULONGLONG
|
|
HalpSetProfileCounterConfiguration(
|
|
IN ULONG Counter,
|
|
IN ULONG PrivilegeMask,
|
|
IN ULONG EnableOverflowInterrupt,
|
|
IN ULONG EnablePrivilegeMonitor,
|
|
IN ULONG Event,
|
|
IN ULONG Umask,
|
|
IN ULONG Threshold,
|
|
IN ULONG InstructionSetMask
|
|
)
|
|
/*++
|
|
|
|
Function Description:
|
|
|
|
This function sets the profile counter with the specified parameters.
|
|
|
|
Arguments:
|
|
|
|
IN ULONG Counter -
|
|
|
|
IN ULONG PrivilegeMask -
|
|
|
|
IN ULONG EnableOverflowInterrupt -
|
|
|
|
IN ULONG EnablePrivilegeMonitor -
|
|
|
|
IN ULONG Event -
|
|
|
|
IN ULONG Umask -
|
|
|
|
IN ULONG Threshold -
|
|
|
|
IN ULONG InstructionSetMask -
|
|
|
|
Return Value:
|
|
|
|
VOID
|
|
|
|
Algorithm:
|
|
|
|
ToBeSpecified
|
|
|
|
In/Out Conditions:
|
|
|
|
ToBeSpecified
|
|
|
|
Globals Referenced:
|
|
|
|
ToBeSpecified
|
|
|
|
Exception Conditions:
|
|
|
|
ToBeSpecified
|
|
|
|
MP Conditions:
|
|
|
|
ToBeSpecified
|
|
|
|
Notes:
|
|
|
|
This function is a kind of combo of the different profile counter APIs.
|
|
It was created to provide speed.
|
|
|
|
ToDo List:
|
|
|
|
- Setting the threshold is not yet supported.
|
|
|
|
Modification History:
|
|
|
|
3/16/2000 TF Initial version
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG data, plmMask, ismMask, es, um, th;
|
|
|
|
// if ( (Counter < 4) || (Counter > 7) ) return;
|
|
|
|
plmMask = (PrivilegeMask & 0xF);
|
|
es = (Event & 0x7F) << 8;
|
|
um = (Umask & 0xF) << 16;
|
|
// XXTF - ToBeDone - Threshold not supported yet.
|
|
ismMask = (InstructionSetMask & 0x3) << 24;
|
|
|
|
data = HalpReadPerfMonCnfgReg( Counter );
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileCounterConfiguration: Counter = %ld Read = 0x%I64x\n", Counter, data ));
|
|
|
|
data &= ~( (0x3 << 24) | (0xF << 16) | (0x7F << 8) | 0xF );
|
|
data |= ( plmMask | es | um | ismMask );
|
|
data = EnableOverflowInterrupt ? (data | (1<<5)) : (data & ~(1<<5));
|
|
data = EnablePrivilegeMonitor ? (data | (1<<6)) : (data & ~(1<<6));
|
|
|
|
HalpWritePerfMonCnfgReg( Counter, data );
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileCounterConfiguration: Counter = %ld Written = 0x%I64x\n", Counter, data ));
|
|
|
|
return data;
|
|
|
|
} // HalpSetProfileCounterConfiguration()
|
|
|
|
BOOLEAN
|
|
HalpIsProfileSourceEventEnabled(
|
|
IN ULONG Event
|
|
)
|
|
{
|
|
#define HalpProfileCnfgEvent( _Cnfg ) ((ULONG)((_Cnfg)>>8) & 0x7F)
|
|
|
|
if ( HalpProfileCnfg4 && (HalpProfileCnfgEvent(HalpProfileCnfg4) == Event)) {
|
|
return TRUE;
|
|
}
|
|
if ( HalpProfileCnfg5 && (HalpProfileCnfgEvent(HalpProfileCnfg5) == Event)) {
|
|
return TRUE;
|
|
}
|
|
if ( HalpProfileCnfg6 && (HalpProfileCnfgEvent(HalpProfileCnfg6) == Event)) {
|
|
return TRUE;
|
|
}
|
|
if ( HalpProfileCnfg7 && (HalpProfileCnfgEvent(HalpProfileCnfg7) == Event)) {
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
} // HalpIsProfileSourceEventEnabled()
|
|
|
|
PHALP_PROFILE_MAPPING
|
|
HalpGetProfileMapping(
|
|
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:
|
|
|
|
ProfileMapping entry - Profile source is supported
|
|
|
|
NULL - Profile source is not supported
|
|
|
|
--*/
|
|
{
|
|
if ( (ULONG) Source > HalpProfileIA64Maximum )
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
return(&HalpProfileMapping[Source]);
|
|
|
|
} // HalpGetProfileMapping()
|
|
|
|
ULONG // == ProfileCounter
|
|
HalpApplyProfileSourceEventMaskPolicy(
|
|
ULONG ProfileSourceEventMask
|
|
)
|
|
{
|
|
ULONG pmcd, set;
|
|
ULONG eventMask = ProfileSourceEventMask;
|
|
|
|
set = eventMask >> PMCD_MASK_SET_PMCD_SHIFT;
|
|
if ( set ) {
|
|
KPROFILE_SOURCE profileSource;
|
|
PHALP_PROFILE_MAPPING profileMapping;
|
|
|
|
pmcd = (eventMask >> PMCD_MASK_SET_PMCD_SHIFT) & PMCD_MASK_SET_PMCD;
|
|
profileSource = HalpGetProfileSource( pmcd );
|
|
if ( !HalpIsProfileSourceActive( profileSource ) ) {
|
|
return pmcd;
|
|
}
|
|
profileMapping = HalpGetProfileMapping( profileSource );
|
|
if ( ! HalpIsProfileMappingInvalid( profileMapping ) ) {
|
|
ULONG sameSet = profileMapping->EventMask >> PMCD_MASK_SET_SHIFT;
|
|
|
|
ASSERTMSG( "HAL!HalpApplyProfileSourceEventMaskPolicy: non-derived events are supported!\n", !HalpIsProfileSourceDerivedEvent( profileSource, profileMapping ) );
|
|
|
|
if ( sameSet == set ) {
|
|
|
|
// We are doing one extra but considering the number of counter pairs, this is not a
|
|
// great performance impact.
|
|
|
|
if ( (eventMask & PMCD_MASK_4) && !HalpIsProfileSourceActive( HalpProfileSource4 ) ) {
|
|
return 4;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_6) && !HalpIsProfileSourceActive( HalpProfileSource6 ) ) {
|
|
return 6;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_7) && !HalpIsProfileSourceActive( HalpProfileSource7 ) ) {
|
|
return 7;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_5) && !HalpIsProfileSourceActive( HalpProfileSource5 ) ) {
|
|
return 5;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
if ( (eventMask & PMCD_MASK_4) && !HalpIsProfileSourceActive( HalpProfileSource4 ) ) {
|
|
return 4;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_5) && !HalpIsProfileSourceActive( HalpProfileSource5 ) ) {
|
|
return 5;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_6) && !HalpIsProfileSourceActive( HalpProfileSource6 ) ) {
|
|
return 6;
|
|
}
|
|
if ( (eventMask & PMCD_MASK_7) && !HalpIsProfileSourceActive( HalpProfileSource7 ) ) {
|
|
return 7;
|
|
}
|
|
}
|
|
return 0; // invalid PMC-PMD pair number.
|
|
|
|
} // HalpApplyProfileSourceEventMaskPolicy()
|
|
|
|
NTSTATUS
|
|
HalpApplyProfileSourceEventPolicies(
|
|
IN PHALP_PROFILE_MAPPING ProfileMapping,
|
|
IN KPROFILE_SOURCE ProfileSource,
|
|
OUT PULONG ProfileCounter,
|
|
OUT HALP_PROFILE_MAPPING ProfileDerivedMapping[]
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function executes the different policies defined for the Event of the specified
|
|
Profile Source.
|
|
|
|
Arguments:
|
|
|
|
ProfileMapping - Supplies the Profile Mapping entry.
|
|
|
|
ProfileSource - Supplies the Profile Source corresponding to the Profile Mapping entry.
|
|
|
|
EventMask - Supplies a pointer to an Event Mask variable.
|
|
|
|
ProfileDerivedMapping - Supplies a HALP_PROFILE_MAPPING array of derived counters for the
|
|
passed event if it is derived.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
STATUS_INVALID_PARAMETER -
|
|
|
|
STATUS_UNSUCESSFUL -
|
|
|
|
Implementation Note:
|
|
|
|
The profile counting is disabled when this function is entered.
|
|
|
|
--*/
|
|
{
|
|
ULONG pmcd;
|
|
BOOLEAN eventDerived;
|
|
|
|
if ( ! ProfileMapping ) {
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
ASSERTMSG( "HAL!HalpApplyProfileSourceEventPolicies: ProfileCounter is NULL!\n", ProfileCounter ) ;
|
|
ASSERTMSG( "HAL!HalpApplyProfileSourceEventPolicies: ProfileDerivedMapping is NULL!\n", ProfileDerivedMapping ) ;
|
|
|
|
*ProfileCounter = 0;
|
|
ProfileDerivedMapping[0].Supported = FALSE;
|
|
eventDerived = FALSE;
|
|
|
|
//
|
|
// Is this ProfileSource a derived event?
|
|
//
|
|
// If this is the case:
|
|
// - We must get the policy applied to this source and apply it.
|
|
// As an example, it could be coupled to the CPU_CYCLE event.
|
|
// In that case, we would compute CPU_CYCLES interval for the
|
|
// specified derived event interval, program the counter(s) and
|
|
// the CPU_CYCLES event.
|
|
//
|
|
|
|
eventDerived = HalpIsProfileSourceDerivedEvent( ProfileSource, ProfileMapping );
|
|
if ( eventDerived ) {
|
|
NTSTATUS status;
|
|
#if defined(HALP_PROFILE_DERIVED_EVENTS)
|
|
// DerivedEvent not implemented yet - FIXFIX 04/2002
|
|
status = ProfileMapping->DerivedEventInitialize( ProfileMapping,
|
|
ProfileSource,
|
|
&cpuCycles
|
|
);
|
|
#else
|
|
status = STATUS_NOT_SUPPORTED;
|
|
#endif
|
|
if ( !NT_SUCCESS( status ) ) {
|
|
return status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// A specific event can be enabled only once at a time per PMU.
|
|
// This also has to be imposed because of the ProfileSource aliases that
|
|
// could use identical events.
|
|
//
|
|
|
|
if ( HalpIsProfileSourceEventEnabled( ProfileMapping->Event ) ) {
|
|
return STATUS_ALREADY_COMMITTED;
|
|
}
|
|
|
|
//
|
|
// Apply EventMask policy for the Source and return the considered counter.
|
|
//
|
|
|
|
pmcd = HalpApplyProfileSourceEventMaskPolicy( ProfileMapping->EventMask );
|
|
if ( !pmcd ) {
|
|
return STATUS_UNSUCCESSFUL;
|
|
}
|
|
*ProfileCounter = pmcd;
|
|
return STATUS_SUCCESS;
|
|
|
|
} // HalpApplyProfileSourceEventPolicies()
|
|
|
|
NTSTATUS
|
|
HalpProgramProfileMapping(
|
|
PHALP_PROFILE_MAPPING ProfileMapping,
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function enables the profiling configuration for the event defined by the
|
|
specified Profile Mapping entry.
|
|
|
|
This function is the counterpart of HalpDeProgramProfileMapping().
|
|
|
|
Arguments:
|
|
|
|
ProfileMapping - Supplies the Profile Mapping entry.
|
|
|
|
ProfileSource - Supplies the Profile Source corresponding to the Profile Mapping entry.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
STATUS_INVALID_PARAMETER -
|
|
|
|
STATUS_UNSUCESSFUL -
|
|
|
|
Implementation Note:
|
|
|
|
The profile counting is disabled when this function is entered.
|
|
|
|
--*/
|
|
{
|
|
HALP_PROFILE_MAPPING profileDerivedMapping[PROCESSOR_IA64_PERFCOUNTERS_PAIRS];
|
|
ULONG profileCounter = 0;
|
|
ULONGLONG profileCounterConfig = 0;
|
|
NTSTATUS status;
|
|
|
|
//
|
|
// Apply the Profile Source policies defining the configuration of the
|
|
// the corresponding Event and determine if this event is a Derived Event for this
|
|
// micro-architecture.
|
|
//
|
|
|
|
status = HalpApplyProfileSourceEventPolicies( ProfileMapping, ProfileSource, &profileCounter, profileDerivedMapping );
|
|
if ( !NT_SUCCESS( status ) ) {
|
|
return status;
|
|
}
|
|
ASSERTMSG( "HAL!HalpProgramProfileMapping: profileCounter is 0!\n", profileCounter ) ;
|
|
|
|
//
|
|
// Follow ProfileMapping attributes to configure PMU counter.
|
|
//
|
|
|
|
HalpSetProfileCounterInterval( profileCounter, ProfileMapping->Interval );
|
|
profileCounterConfig = HalpSetProfileCounterConfiguration( profileCounter,
|
|
ProfileMapping->PrivilegeLevel,
|
|
ProfileMapping->OverflowInterrupt,
|
|
ProfileMapping->PrivilegeEnable,
|
|
ProfileMapping->Event,
|
|
ProfileMapping->UnitMask,
|
|
ProfileMapping->Threshold,
|
|
ProfileMapping->InstructionSetMask
|
|
);
|
|
HalpSetProfileSource( profileCounter, ProfileSource, profileCounterConfig );
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // HalpProgramProfileMapping()
|
|
|
|
VOID
|
|
HalpDeProgramProfileMapping(
|
|
PHALP_PROFILE_MAPPING ProfileMapping,
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function disables the profiling configuration for the event defined by the
|
|
specified Profile Mapping entry.
|
|
|
|
This function is the counterpart of HalpProgramProfileMapping().
|
|
|
|
Arguments:
|
|
|
|
ProfileMapping - Supplies the Profile Mapping entry.
|
|
|
|
ProfileSource - Supplies the Profile Source corresponding to the Profile Mapping entry.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS -
|
|
|
|
STATUS_INVALID_PARAMETER -
|
|
|
|
STATUS_UNSUCESSFUL -
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG eventMask;
|
|
ULONG eventFailedSpeculativeCheckLoads;
|
|
ULONG eventALATOverflows;
|
|
|
|
if ( ! ProfileMapping ) {
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Is this ProfileSource a derived event?
|
|
//
|
|
// XXTF - ToBeDone - Derived Event
|
|
|
|
//
|
|
// Validate the Profile Source as active.
|
|
//
|
|
|
|
if ( HalpProfileSource4 == ProfileSource ) {
|
|
|
|
HalpProfileCnfg4 = HalpSetProfileCounterConfiguration( 4,
|
|
PMC_PLM_NONE,
|
|
PMC_DISABLE_OVERFLOW_INTERRUPT,
|
|
PMC_DISABLE_PRIVILEGE_MONITOR,
|
|
0, // Event
|
|
0, // Umask
|
|
0, // Threshold
|
|
PMC_ISM_NONE
|
|
);
|
|
|
|
HalpSetProfileCounterInterval( 4, 0 );
|
|
HalpDisactivateProfileSource( HalpProfileSource4 );
|
|
HalpProfilingRunning--;
|
|
|
|
}
|
|
else if ( HalpProfileSource5 == ProfileSource ) {
|
|
|
|
HalpProfileCnfg5 = HalpSetProfileCounterConfiguration( 5,
|
|
PMC_PLM_NONE,
|
|
PMC_DISABLE_OVERFLOW_INTERRUPT,
|
|
PMC_DISABLE_PRIVILEGE_MONITOR,
|
|
0, // Event
|
|
0, // Umask
|
|
0, // Threshold
|
|
PMC_ISM_NONE
|
|
);
|
|
|
|
HalpSetProfileCounterInterval( 5, 0 );
|
|
HalpDisactivateProfileSource( HalpProfileSource5 );
|
|
HalpProfilingRunning--;
|
|
|
|
}
|
|
else if ( HalpProfileSource6 == ProfileSource ) {
|
|
|
|
HalpProfileCnfg6 = HalpSetProfileCounterConfiguration( 6,
|
|
PMC_PLM_NONE,
|
|
PMC_DISABLE_OVERFLOW_INTERRUPT,
|
|
PMC_DISABLE_PRIVILEGE_MONITOR,
|
|
0, // Event
|
|
0, // Umask
|
|
0, // Threshold
|
|
PMC_ISM_NONE
|
|
);
|
|
|
|
HalpSetProfileCounterInterval( 6, 0 );
|
|
HalpDisactivateProfileSource( HalpProfileSource6);
|
|
HalpProfilingRunning--;
|
|
|
|
}
|
|
else if ( HalpProfileSource7 == ProfileSource ) {
|
|
|
|
HalpProfileCnfg7 = HalpSetProfileCounterConfiguration( 7,
|
|
PMC_PLM_NONE,
|
|
PMC_DISABLE_OVERFLOW_INTERRUPT,
|
|
PMC_DISABLE_PRIVILEGE_MONITOR,
|
|
0, // Event
|
|
0, // Umask
|
|
0, // Threshold
|
|
PMC_ISM_NONE
|
|
);
|
|
|
|
HalpSetProfileCounterInterval( 7, 0 );
|
|
HalpDisactivateProfileSource( HalpProfileSource7 );
|
|
HalpProfilingRunning--;
|
|
}
|
|
|
|
return;
|
|
|
|
} // HalpDeProgramProfileMapping()
|
|
|
|
ULONG_PTR
|
|
HalpSetProfileInterruptHandler(
|
|
IN ULONG_PTR ProfileInterruptHandler
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function registers a per-processor Profiling Interrupt Handler.
|
|
|
|
Arguments:
|
|
|
|
ProfileInterruptHandler - Interrupt Handler.
|
|
|
|
Return Value:
|
|
|
|
(ULONG_PTR)STATUS_SUCCESS - Successful registration.
|
|
|
|
(ULONG_PTR)STATUS_ALREADY_COMMITTED - Cannot register an handler if profiling events are running.
|
|
|
|
(ULONG_PTR)STATUS_PORT_ALREADY_SET - An Profiling Interrupt Handler was already registred - not imposed currently.
|
|
|
|
Note:
|
|
|
|
IT IS THE RESPONSIBILITY OF THE CALLER OF THIS ROUTINE TO ENSURE
|
|
THAT NO PAGE FAULTS WILL OCCUR DURING EXECUTION OF THE PROVIDED
|
|
FUNCTION OR ACCESS TO THE PROVIDED CONTEXT.
|
|
A MINIMUM OF FUNCTION POINTER CHECKING WAS DONE IN HalSetSystemInformation PROCESSING.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// If profiling is already running, we do not allow the handler registration.
|
|
//
|
|
// This imposes that:
|
|
//
|
|
// - if the default HAL profiling is running or a profiling with a registered interrupt
|
|
// handler is running, we cannot register an interrupt handler.
|
|
// In the last case, all the profiling events have to be stopped before a possible
|
|
// registration.
|
|
//
|
|
// It should be also noticed that there is no ownership of profiling monitors implemented.
|
|
// Meaning that if profiling is started, the registred handler will get the interrupts
|
|
// generated by ALL the running monitor events if they are programmed to generate interrupts.
|
|
//
|
|
|
|
if ( HalpProfilingRunning ) {
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalpSetProfileInterruptHandler: Profiling already running\n" ));
|
|
return((ULONG_PTR)(ULONG)(STATUS_ALREADY_COMMITTED));
|
|
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Thierry - 03/2000. ToBeVerified.
|
|
//
|
|
// In case, no profiling was started, there is currently no restriction in registering
|
|
// another handler if one was already registered.
|
|
//
|
|
|
|
if ( HalpProfillingInterruptHandler ) {
|
|
return((ULONG_PTR)(ULONG)(STATUS_PORT_ALREADY_SET));
|
|
}
|
|
|
|
#endif // 0
|
|
|
|
HalpProfilingInterruptHandler = (ULONGLONG)ProfileInterruptHandler;
|
|
return((ULONG_PTR)(ULONG)(STATUS_SUCCESS));
|
|
|
|
} // HalpSetProfileInterruptHandler()
|
|
|
|
VOID
|
|
HalpProfileInterrupt(
|
|
IN PKINTERRUPT_ROUTINE Interrupt,
|
|
IN PKTRAP_FRAME TrapFrame
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Default PROFILE_VECTOR Interrupt Handler.
|
|
This function is executed as the result of an interrupt from the
|
|
internal microprocessor performance counters. The interrupt
|
|
may be used to signal the completion of a profile event.
|
|
If profiling is current active, the function determines if the
|
|
profile interval has expired and if so dispatches to the standard
|
|
system routine to update the system profile time. If profiling
|
|
is not active then returns.
|
|
|
|
Arguments:
|
|
|
|
TrapFrame - Trap frame address.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Call registered per-processor Profiling Interrupt handler if it exists.
|
|
// We will return immediately before doing any default profiling interrupt handling.
|
|
//
|
|
|
|
if ( HalpProfilingInterruptHandler &&
|
|
(*((PHAL_PROFILE_INTERRUPT_HANDLER)HalpProfilingInterruptHandler) != NULL) ) {
|
|
(*((PHAL_PROFILE_INTERRUPT_HANDLER)HalpProfilingInterruptHandler))( TrapFrame );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Handle interrupt if profiling is enabled.
|
|
//
|
|
|
|
if ( HalpProfilingRunning ) {
|
|
|
|
//
|
|
// Process every PMC/PMD pair overflow.
|
|
//
|
|
|
|
// XXTF - FIXFIX - Merced specific.
|
|
UCHAR pmc0, overflow;
|
|
ULONG source;
|
|
|
|
HalpProfilingInterrupts++;
|
|
|
|
pmc0 = (UCHAR)HalpReadPerfMonCnfgReg0();
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt PMC0 freeze bit is not set!\n", pmc0 & 0x1 );
|
|
overflow = pmc0 & 0xF0;
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", overflow );
|
|
if ( overflow & (1<<4) ) {
|
|
source = HalpProfileSource4; // XXTF - IfFaster - Coud used pmc.es
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < HalpProfileIA64Maximum );
|
|
KeProfileInterruptWithSource( TrapFrame, source );
|
|
HalpSetProfileCounterInterval( 4, HalpProfileMapping[source].Interval );
|
|
// XXTF - IfFaster - HalpWritePerfMonDataReg( 4, HalpProfileMapping[source].Interval );
|
|
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 4, *PCRProfileCnfg4Reload );
|
|
}
|
|
if ( overflow & (1<<5) ) {
|
|
source = HalpProfileSource5; // XXTF - IfFaster - Coud used pmc.es
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < HalpProfileIA64Maximum );
|
|
KeProfileInterruptWithSource( TrapFrame, source );
|
|
HalpSetProfileCounterInterval( 5, HalpProfileMapping[source].Interval );
|
|
// XXTF - IfFaster - HalpWritePerfMonDataReg( 5, HalpProfileMapping[source].Interval );
|
|
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 5, *PCRProfileCnfg5Reload );
|
|
}
|
|
if ( overflow & (1<<6) ) {
|
|
source = HalpProfileSource6; // XXTF - IfFaster - Coud used pmc.es
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < HalpProfileIA64Maximum );
|
|
KeProfileInterruptWithSource( TrapFrame, source );
|
|
HalpSetProfileCounterInterval( 6, HalpProfileMapping[source].Interval );
|
|
// XXTF - IfFaster - HalpWritePerfMonDataReg( 6, HalpProfileMapping[source].Interval );
|
|
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 6, *PCRProfileCnfg6Reload );
|
|
}
|
|
if ( overflow & (1<<7) ) {
|
|
source = HalpProfileSource7; // XXTF - IfFaster - Coud used pmc.es
|
|
ASSERTMSG( "HAL!HalpProfileInterrupt no overflow bit set!\n", source < HalpProfileIA64Maximum );
|
|
KeProfileInterruptWithSource( TrapFrame, source );
|
|
HalpSetProfileCounterInterval( 7, HalpProfileMapping[source].Interval );
|
|
// XXTF - IfFaster - HalpWritePerfMonDataReg( 6, HalpProfileMapping[source].Interval );
|
|
// XXTF - CodeWithReload - HalpWritePerfMonCnfgReg( 7, *PCRProfileCnfg7Reload );
|
|
}
|
|
|
|
//
|
|
// Clear pmc0.fr and overflow bits.
|
|
//
|
|
|
|
HalpEnableProfileCounting();
|
|
|
|
}
|
|
else {
|
|
|
|
HalpProfilingInterruptsWithoutProfiling++;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
} // HalpProfileInterrupt()
|
|
|
|
NTSTATUS
|
|
HalSetProfileSourceInterval(
|
|
IN KPROFILE_SOURCE ProfileSource,
|
|
IN OUT ULONG_PTR *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
|
|
|
|
- if ProfileSource is ProfileTime, Interval is in 100ns units.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS
|
|
|
|
--*/
|
|
{
|
|
ULONGLONG countEvents;
|
|
PHALP_PROFILE_MAPPING profileMapping;
|
|
|
|
profileMapping = HalpGetProfileMapping(ProfileSource);
|
|
if ( profileMapping == NULL ) {
|
|
return( STATUS_NOT_IMPLEMENTED );
|
|
}
|
|
if ( profileMapping->Supported == FALSE ) {
|
|
return( STATUS_NOT_SUPPORTED );
|
|
}
|
|
|
|
//
|
|
// Fill in the profile source value.
|
|
//
|
|
|
|
profileMapping->ProfileSource = ProfileSource;
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: ProfileSource = %ld IN Desired Interval = 0x%Ix\n", ProfileSource, *Interval ));
|
|
|
|
countEvents = (ULONGLONG)*Interval;
|
|
if ( (ProfileSource == ProfileTime) && countEvents ) {
|
|
//
|
|
// Convert the clock tick period (in 100ns units) into a cycle count period
|
|
//
|
|
countEvents = (ULONGLONG)(countEvents * HalpITCTicksPer100ns);
|
|
}
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: countEvent = 0x%I64x\n", countEvents ));
|
|
|
|
//
|
|
// Check to see if the desired Interval is reasonable, if not adjust it.
|
|
//
|
|
// A specific case for desired Interval == 0, this resets the ProfileMapping entry Interval
|
|
// field and will make the event increment the PMD up to overflow bit if the Events generating
|
|
// caller is killed or does not stop the interrupts for any reason.
|
|
// Again, this is to avoid hanging the system with PMU interrupts.
|
|
//
|
|
|
|
if ( countEvents ) {
|
|
if ( countEvents > profileMapping->IntervalMax ) {
|
|
countEvents = profileMapping->IntervalMax;
|
|
}
|
|
else if ( countEvents < profileMapping->IntervalMin ) {
|
|
countEvents = profileMapping->IntervalMin;
|
|
}
|
|
}
|
|
profileMapping->Interval = countEvents;
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: CurrentInterval = 0x%I64x\n", profileMapping->Interval ));
|
|
|
|
if ( (ProfileSource == ProfileTime) && countEvents ) {
|
|
//
|
|
// Convert cycle count back into 100ns clock ticks
|
|
//
|
|
|
|
countEvents = (ULONGLONG)(countEvents / HalpITCTicksPer100ns);
|
|
}
|
|
*Interval = (ULONG_PTR)countEvents;
|
|
|
|
HalDebugPrint(( HAL_PROFILE, "HalSetProfileSourceInterval: ProfileSource = %ld OUT *Interval = 0x%Ix\n", ProfileSource, *Interval ));
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
} // HalSetProfileSourceInterval()
|
|
|
|
ULONG_PTR
|
|
HalSetProfileInterval (
|
|
IN ULONG_PTR Interval
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine sets the ProfileTime source interrupt interval.
|
|
|
|
Arguments:
|
|
|
|
Interval - Supplies the desired profile interval in 100ns units.
|
|
|
|
Return Value:
|
|
|
|
The actual profile interval.
|
|
|
|
--*/
|
|
|
|
{
|
|
ULONG_PTR NewInterval;
|
|
|
|
NewInterval = Interval;
|
|
HalSetProfileSourceInterval(ProfileTime, &NewInterval);
|
|
return(NewInterval);
|
|
|
|
} // HalSetProfileInterval()
|
|
|
|
VOID
|
|
HalStartProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine turns on the profile interrupt.
|
|
|
|
N.B. This routine must be called at PROFILE_LEVEL on each processor.
|
|
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN disabledProfileCounting;
|
|
NTSTATUS status;
|
|
PHALP_PROFILE_MAPPING profileMapping;
|
|
|
|
//
|
|
// Get the Hal profile mapping entry associated with the specified source.
|
|
//
|
|
|
|
profileMapping = HalpGetProfileMapping( ProfileSource );
|
|
if ( HalpIsProfileMappingInvalid( profileMapping ) ) {
|
|
HalDebugPrint(( HAL_PROFILE, "HalStartProfileInterrupt: invalid source = %ld\n", ProfileSource ));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Disable the profile counting if enabled.
|
|
//
|
|
|
|
disabledProfileCounting = FALSE;
|
|
if ( HalpProfilingRunning && !(HalpReadPerfMonCnfgReg0() & 0x1) ) {
|
|
HalpDisableProfileCounting();
|
|
disabledProfileCounting = TRUE;
|
|
}
|
|
|
|
//
|
|
// Obtain and initialize an available PMC register that supports this event.
|
|
// We may enable more than one event.
|
|
// If the initialization failed, we return immediately.
|
|
//
|
|
// XXTF - FIXFIX - is there a way to
|
|
// * notify the caller for the failure and the reason of the failure. or
|
|
// * modify the API. or
|
|
// * define a new API.
|
|
//
|
|
|
|
status = HalpProgramProfileMapping( profileMapping, ProfileSource );
|
|
if ( !NT_SUCCESS(status) ) {
|
|
HalDebugPrint(( HAL_PROFILE, "HalStartProfileInterrupt: HalpProgramProfileMapping failed.\n" ));
|
|
if ( disabledProfileCounting ) {
|
|
HalpEnableProfileCounting();
|
|
}
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Notify the profiling as active.
|
|
// before enabling the selected pmc overflow interrupt and unfreezing the counters.
|
|
//
|
|
|
|
HalpProfilingRunning++;
|
|
HalpEnableProfileCounting();
|
|
|
|
return;
|
|
|
|
} // HalStartProfileInterrupt()
|
|
|
|
VOID
|
|
HalStopProfileInterrupt (
|
|
KPROFILE_SOURCE ProfileSource
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine turns off the profile interrupt.
|
|
|
|
N.B. This routine must be called at PROFILE_LEVEL on each processor.
|
|
|
|
|
|
Arguments:
|
|
|
|
ProfileSource - Supplies the Profile Source to stop.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PHALP_PROFILE_MAPPING profileMapping;
|
|
|
|
//
|
|
// Get the Hal profile mapping entry associated with the specified profile source.
|
|
//
|
|
|
|
profileMapping = HalpGetProfileMapping( ProfileSource );
|
|
if ( HalpIsProfileMappingInvalid( profileMapping ) ) {
|
|
HalDebugPrint(( HAL_PROFILE, "HalStopProfileInterrupt: invalid source = %ld\n", ProfileSource ));
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Get and disable an available PMC register that supports this event.
|
|
// We might disable more than one event.
|
|
// If the initialization failed, we return immediately.
|
|
//
|
|
// XXTF - FIXFIX - is there a way to
|
|
// * notify the caller for the failure and the reason of the failure. or
|
|
// * modify the API. or
|
|
// * define a new API.
|
|
//
|
|
|
|
HalpDeProgramProfileMapping( profileMapping, ProfileSource );
|
|
|
|
return;
|
|
|
|
} // HalStopProfileInterrupt()
|
|
|
|
VOID
|
|
HalpResetProcessorDependentPerfMonCnfgRegs(
|
|
ULONGLONG DefaultValue
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the processor dependent performance configuration
|
|
registers.
|
|
|
|
Arguments:
|
|
|
|
DefaultValue - default value used to initialize IA64 generic PMCs.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
// XXTF - 02/08/2000
|
|
// For now, there is no initialization for processor dependent performance
|
|
// configuration registers.
|
|
return;
|
|
|
|
} // HalpResetProcessorDependentPerfMonCnfgRegs()
|
|
|
|
VOID
|
|
HalpResetPerfMonCnfgRegs(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine initializes the IA64 architected performance configuration
|
|
registers and calls the micro-architecture specific initialization.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
ULONG pmc;
|
|
ULONGLONG value;
|
|
|
|
value = HALP_PMC4_RESET;
|
|
pmc = 4;
|
|
HalpWritePerfMonCnfgReg( pmc, value );
|
|
|
|
value = HALP_PMC_RESET;
|
|
for ( pmc = 5; pmc < 8; pmc++ ) {
|
|
HalpWritePerfMonCnfgReg( pmc, value );
|
|
}
|
|
|
|
HalpResetProcessorDependentPerfMonCnfgRegs( value );
|
|
|
|
return;
|
|
|
|
} // HalpResetPerfMonCnfgRegs()
|
|
|
|
VOID
|
|
HalpEnablePMU(
|
|
VOID
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine enables the processor Performance Monitoring Unit.
|
|
|
|
Called from HalInitializeProfiling at phase 1 on every processor.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the processor number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
Implementation Notes:
|
|
|
|
Starting with McKinley, in order to use any of the PMU features,
|
|
a 1 should be written to the PMC4.23 bit. This controls the clocks
|
|
to all PMDs and all PMCs (with the exception of PMC4) and other
|
|
non-critical circuitry. This bit powers up as 1 and must be written
|
|
as 1, otherwise the PMU will not function correctly.
|
|
|
|
--*/
|
|
{
|
|
HalpWritePerfMonCnfgReg( 4, HALP_PMC4_RESET );
|
|
} // HalpEnablePMU()
|
|
|
|
VOID
|
|
HalpInitializeProfiling (
|
|
ULONG Number
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called during initialization to initialize profiling
|
|
for each processor in the system.
|
|
|
|
Called from HalInitSystem at phase 1 on every processor.
|
|
|
|
Arguments:
|
|
|
|
Number - Supplies the processor number.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
|
|
//
|
|
// Enable IA64 Processor PMU
|
|
//
|
|
|
|
HalpEnablePMU();
|
|
|
|
//
|
|
// Disable processor profile counting.
|
|
//
|
|
|
|
HalpDisableProfileCounting();
|
|
|
|
//
|
|
// If BSP processor, initialize the ProfileTime Interval entries.
|
|
//
|
|
// Assumes HalpITCTicksPer100ns has been initialized.
|
|
|
|
if ( Number == 0 ) {
|
|
ULONGLONG interval;
|
|
ULONGLONG count;
|
|
PHALP_PROFILE_MAPPING profile;
|
|
|
|
profile = &HalpProfileMapping[ProfileTime];
|
|
|
|
interval = DEFAULT_PROFILE_INTERVAL;
|
|
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
|
|
profile->IntervalDef = count;
|
|
|
|
interval = MAXIMUM_PROFILE_INTERVAL;
|
|
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
|
|
profile->IntervalMax = count;
|
|
|
|
interval = MINIMUM_PROFILE_INTERVAL;
|
|
count = (ULONGLONG)(interval * HalpITCTicksPer100ns);
|
|
profile->IntervalMin = count;
|
|
}
|
|
|
|
//
|
|
// ToBeDone - checkpoint for default processor.PSR fields for
|
|
// performance monitoring.
|
|
//
|
|
|
|
//
|
|
// Resets the processor performance configuration registers.
|
|
//
|
|
|
|
HalpResetPerfMonCnfgRegs();
|
|
|
|
//
|
|
// Initialization of the Per processor profiling data.
|
|
//
|
|
|
|
HalpProfilingRunning = 0;
|
|
HalpDisactivateProfileSource( HalpProfileSource4 );
|
|
HalpDisactivateProfileSource( HalpProfileSource5 );
|
|
HalpDisactivateProfileSource( HalpProfileSource6 );
|
|
HalpDisactivateProfileSource( HalpProfileSource7 );
|
|
|
|
//
|
|
// XXTF 02/08/2000:
|
|
// Different performance vectors are considered:
|
|
// - Profiling (default) -> PROFILE_VECTOR
|
|
// - Tracing -> PERF_VECTOR [PMUTRACE_VECTOR]
|
|
//
|
|
// Set default Performance vector to Profiling.
|
|
//
|
|
|
|
ASSERTMSG( "HAL!HalpInitializeProfiler PROFILE_VECTOR handler != HalpProfileInterrupt\n",
|
|
PCR->InterruptRoutine[PROFILE_VECTOR] == (PKINTERRUPT_ROUTINE)HalpProfileInterrupt );
|
|
|
|
HalpWritePerfMonVectorReg( PROFILE_VECTOR );
|
|
|
|
return;
|
|
|
|
} // HalpInitializeProfiling()
|
|
|
|
NTSTATUS
|
|
HalpProfileSourceInformation (
|
|
OUT PVOID Buffer,
|
|
IN ULONG BufferLength,
|
|
OUT PULONG ReturnedLength
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Returns the HAL_PROFILE_SOURCE_INFORMATION or
|
|
HAL_PROFILE_SOURCE_INFORMATION_EX for this processor.
|
|
|
|
Arguments:
|
|
|
|
Buffer - output buffer
|
|
BufferLength - length of buffer on input
|
|
ReturnedLength - The length of data returned
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS - successful return.
|
|
STATUS_BUFFER_TOO_SMALL - passed buffer size is invalid
|
|
The ReturnedLength contains the buffersize mininum
|
|
STATUS_NOT_IMPLEMENTED - specified source is not implemented
|
|
STATUS_NOT_SUPPORTED - specified source is not supported
|
|
|
|
--*/
|
|
{
|
|
PHALP_PROFILE_MAPPING profileMapping;
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
KPROFILE_SOURCE source;
|
|
|
|
if ( (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) &&
|
|
(BufferLength < sizeof(HAL_PROFILE_SOURCE_INFORMATION_EX)) )
|
|
{
|
|
status = STATUS_INFO_LENGTH_MISMATCH;
|
|
return status;
|
|
}
|
|
|
|
source = ((PHAL_PROFILE_SOURCE_INFORMATION)Buffer)->Source;
|
|
profileMapping = HalpGetProfileMapping( source );
|
|
|
|
//
|
|
// return a different status error if the source is not supported or invalid.
|
|
//
|
|
|
|
if ( profileMapping == NULL ) {
|
|
status = STATUS_NOT_IMPLEMENTED;
|
|
return status;
|
|
}
|
|
if ( profileMapping->Supported == FALSE ) {
|
|
status = STATUS_NOT_SUPPORTED;
|
|
}
|
|
|
|
//
|
|
// Fill in the profile source value.
|
|
//
|
|
|
|
profileMapping->ProfileSource = source;
|
|
|
|
//
|
|
// and Fill in the information.
|
|
//
|
|
|
|
if ( BufferLength == sizeof(HAL_PROFILE_SOURCE_INFORMATION) ) {
|
|
|
|
PHAL_PROFILE_SOURCE_INFORMATION sourceInfo;
|
|
|
|
//
|
|
// HAL_PROFILE_SOURCE_INFORMATION buffer.
|
|
//
|
|
|
|
sourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
|
|
sourceInfo->Supported = profileMapping->Supported;
|
|
if ( sourceInfo->Supported ) {
|
|
|
|
//
|
|
// For ProfileTime, we convert cycle count back into 100ns clock ticks.
|
|
//
|
|
|
|
if ( profileMapping->ProfileSource == ProfileTime ) {
|
|
sourceInfo->Interval = (ULONG) (profileMapping->Interval / HalpITCTicksPer100ns);
|
|
}
|
|
else {
|
|
sourceInfo->Interval = (ULONG) profileMapping->Interval;
|
|
}
|
|
|
|
}
|
|
|
|
if ( ReturnedLength ) {
|
|
*ReturnedLength = sizeof(HAL_PROFILE_SOURCE_INFORMATION);
|
|
}
|
|
|
|
}
|
|
else {
|
|
|
|
PHAL_PROFILE_SOURCE_INFORMATION_EX sourceInfoEx;
|
|
|
|
//
|
|
// HAL_PROFILE_SOURCE_INFORMATION_EX buffer.
|
|
//
|
|
|
|
sourceInfoEx = (PHAL_PROFILE_SOURCE_INFORMATION_EX)Buffer;
|
|
sourceInfoEx->Supported = profileMapping->Supported;
|
|
if ( sourceInfoEx->Supported ) {
|
|
|
|
//
|
|
// For ProfileTime, we convert cycle count back into 100ns clock ticks.
|
|
//
|
|
|
|
if ( profileMapping->ProfileSource == ProfileTime ) {
|
|
sourceInfoEx->Interval =
|
|
(ULONG_PTR) (profileMapping->Interval / HalpITCTicksPer100ns);
|
|
}
|
|
else {
|
|
sourceInfoEx->Interval = (ULONG_PTR) profileMapping->Interval;
|
|
}
|
|
|
|
sourceInfoEx->DefInterval = (ULONG_PTR) profileMapping->IntervalDef;
|
|
sourceInfoEx->MaxInterval = (ULONG_PTR) profileMapping->IntervalMax;
|
|
sourceInfoEx->MinInterval = (ULONG_PTR) profileMapping->IntervalMin;
|
|
}
|
|
|
|
if ( ReturnedLength ) {
|
|
*ReturnedLength = sizeof(HAL_PROFILE_SOURCE_INFORMATION_EX);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
|
|
} // HalpProfileSourceInformation()
|
|
|