From c06ad33ed2fbbacdba42baf07f5d3fd41b36781d Mon Sep 17 00:00:00 2001 From: darylm503 Date: Fri, 23 Apr 2010 17:00:32 +0000 Subject: Libraries and utilities for instrumenting regions of code and measuring their performance. git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@10417 6f19259b-4bc3-4df7-8a09-765794883524 --- PerformancePkg/Library/TscTimerLib/TscTimerLib.c | 243 +++++++++++++++++++++ PerformancePkg/Library/TscTimerLib/TscTimerLib.inf | 52 +++++ 2 files changed, 295 insertions(+) create mode 100644 PerformancePkg/Library/TscTimerLib/TscTimerLib.c create mode 100644 PerformancePkg/Library/TscTimerLib/TscTimerLib.inf (limited to 'PerformancePkg/Library/TscTimerLib') diff --git a/PerformancePkg/Library/TscTimerLib/TscTimerLib.c b/PerformancePkg/Library/TscTimerLib/TscTimerLib.c new file mode 100644 index 0000000000..19151a4e9b --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/TscTimerLib.c @@ -0,0 +1,243 @@ +/** @file + A Timer Library implementation which uses the Time Stamp Counter in the processor. + + For Pentium 4 processors, Intel Xeon processors (family [0FH], models [03H and higher]); + for Intel Core Solo and Intel Core Duo processors (family [06H], model [0EH]); + for the Intel Xeon processor 5100 series and Intel Core 2 Duo processors (family [06H], model [0FH]); + for Intel Core 2 and Intel Xeon processors (family [06H], display_model [17H]); + for Intel Atom processors (family [06H], display_model [1CH]): + the time-stamp counter increments at a constant rate. + That rate may be set by the maximum core-clock to bus-clock ratio of the processor or may be set by + the maximum resolved frequency at which the processor is booted. The maximum resolved frequency may + differ from the maximum qualified frequency of the processor. + + The specific processor configuration determines the behavior. Constant TSC behavior ensures that the + duration of each clock tick is uniform and supports the use of the TSC as a wall clock timer even if + the processor core changes frequency. This is the architectural behavior moving forward. + + A Processor’s support for invariant TSC is indicated by CPUID.0x80000007.EDX[8]. + + Copyright (c) 2009-2010, Intel Corporation. All rights reserved.
+ This program and the accompanying materials + are licensed and made available under the terms and conditions of the BSD License + which accompanies this distribution. The full text of the license may be found at + http://opensource.org/licenses/bsd-license.php + + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, + WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. + +**/ + +#include +#include + +#include +#include +#include +#include +#include + +STATIC UINT64 mTscFrequency; + +#ifndef R_ICH_ACPI_PM1_TMR +#define R_ICH_ACPI_PM1_TMR R_ACPI_PM1_TMR +#endif + +/** The constructor function determines the actual TSC frequency. + + The TSC counting frequency is determined by comparing how far it counts + during a 1ms period as determined by the ACPI timer. The ACPI timer is + used because it counts at a known frequency. + If ACPI I/O space not enabled, this function will enable it. Then the + TSC is sampled, followed by waiting for 3579 clocks of the ACPI timer, or 1ms. + The TSC is then sampled again. The difference multiplied by 1000 is the TSC + frequency. There will be a small error because of the overhead of reading + the ACPI timer. An attempt is made to determine and compensate for this error. + This function will always return RETURN_SUCCESS. + + @retval RETURN_SUCCESS The constructor always returns RETURN_SUCCESS. + +**/ +RETURN_STATUS +EFIAPI +TscTimerLibConstructor ( + VOID + ) +{ + UINT64 StartTSC; + UINT64 EndTSC; + UINT32 TimerAddr; + UINT32 Ticks; + + // + // If ACPI I/O space is not enabled yet, program ACPI I/O base address and enable it. + // + if ((PciRead8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT)) & B_ICH_LPC_ACPI_CNT_ACPI_EN) == 0) { + PciWrite16 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_BASE), PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress)); + PciOr8 (PCI_ICH_LPC_ADDRESS (R_ICH_LPC_ACPI_CNT), B_ICH_LPC_ACPI_CNT_ACPI_EN); + } + + TimerAddr = PcdGet16 (PcdPerfPkgAcpiIoPortBaseAddress) + R_ACPI_PM1_TMR; // Locate the ACPI Timer + Ticks = IoRead32( TimerAddr) + (3579); // Set Ticks to 1ms in the future + StartTSC = AsmReadTsc(); // Get base value for the TSC + // + // Wait until the ACPI timer has counted 1ms. + // Timer wrap-arounds are handled correctly by this function. + // When the current ACPI timer value is greater than 'Ticks', the while loop will exit. + // + while (((Ticks - IoRead32( TimerAddr)) & BIT23) == 0) { + CpuPause(); + } + EndTSC = AsmReadTsc(); // TSC value 1ms later + + mTscFrequency = MultU64x32 ( + (EndTSC - StartTSC), // Number of TSC counts in 1ms + 1000 // Number of ms in a second + ); + // + // mTscFrequency is now equal to the number of TSC counts per second + // + return RETURN_SUCCESS; +} + +/** Stalls the CPU for at least the given number of ticks. + + Stalls the CPU for at least the given number of ticks. It's invoked by + MicroSecondDelay() and NanoSecondDelay(). + + @param[in] Delay A period of time to delay in ticks. + +**/ +STATIC +VOID +InternalX86Delay ( + IN UINT64 Delay + ) +{ + UINT64 Ticks; + + // + // The target timer count is calculated here + // + Ticks = AsmReadTsc() + Delay; + + // + // Wait until time out + // Timer wrap-arounds are NOT handled correctly by this function. + // Thus, this function must be called within 10 years of reset since + // Intel guarantees a minimum of 10 years before the TSC wraps. + // + while (AsmReadTsc() <= Ticks) CpuPause(); +} + +/** Stalls the CPU for at least the specified number of MicroSeconds. + + @param[in] MicroSeconds The minimum number of microseconds to delay. + + @return The value of MicroSeconds input. + +**/ +UINTN +EFIAPI +MicroSecondDelay ( + IN UINTN MicroSeconds + ) +{ + InternalX86Delay ( + DivU64x32 ( + MultU64x64 ( + mTscFrequency, + MicroSeconds + ), + 1000000u + ) + ); + return MicroSeconds; +} + +/** Stalls the CPU for at least the specified number of NanoSeconds. + + @param[in] NanoSeconds The minimum number of nanoseconds to delay. + + @return The value of NanoSeconds input. + +**/ +UINTN +EFIAPI +NanoSecondDelay ( + IN UINTN NanoSeconds + ) +{ + InternalX86Delay ( + DivU64x32 ( + MultU64x32 ( + mTscFrequency, + (UINT32)NanoSeconds + ), + 1000000000u + ) + ); + return NanoSeconds; +} + +/** Retrieves the current value of the 64-bit free running Time-Stamp counter. + + The time-stamp counter (as implemented in the P6 family, Pentium, Pentium M, + Pentium 4, Intel Xeon, Intel Core Solo and Intel Core Duo processors and + later processors) is a 64-bit counter that is set to 0 following a RESET of + the processor. Following a RESET, the counter increments even when the + processor is halted by the HLT instruction or the external STPCLK# pin. Note + that the assertion of the external DPSLP# pin may cause the time-stamp + counter to stop. + + The properties of the counter can be retrieved by the + GetPerformanceCounterProperties() function. + + @return The current value of the free running performance counter. + +**/ +UINT64 +EFIAPI +GetPerformanceCounter ( + VOID + ) +{ + return AsmReadTsc(); +} + +/** Retrieves the 64-bit frequency in Hz and the range of performance counter + values. + + If StartValue is not NULL, then the value that the performance counter starts + with, 0x0, is returned in StartValue. If EndValue is not NULL, then the value + that the performance counter end with, 0xFFFFFFFFFFFFFFFF, is returned in + EndValue. + + The 64-bit frequency of the performance counter, in Hz, is always returned. + To determine average processor clock frequency, Intel recommends the use of + EMON logic to count processor core clocks over the period of time for which + the average is required. + + + @param[out] StartValue Pointer to where the performance counter's starting value is saved, or NULL. + @param[out] EndValue Pointer to where the performance counter's ending value is saved, or NULL. + + @return The frequency in Hz. + +**/ +UINT64 +EFIAPI +GetPerformanceCounterProperties ( + OUT UINT64 *StartValue, OPTIONAL + OUT UINT64 *EndValue OPTIONAL + ) +{ + if (StartValue != NULL) { + *StartValue = 0; + } + if (EndValue != NULL) { + *EndValue = 0xFFFFFFFFFFFFFFFFull; + } + + return mTscFrequency; +} diff --git a/PerformancePkg/Library/TscTimerLib/TscTimerLib.inf b/PerformancePkg/Library/TscTimerLib/TscTimerLib.inf new file mode 100644 index 0000000000..3f9aebfdcb --- /dev/null +++ b/PerformancePkg/Library/TscTimerLib/TscTimerLib.inf @@ -0,0 +1,52 @@ +#/** @file +# Timer Library which uses the Time Stamp Counter in the processor. +# +# A version of the Timer Library using the processor's TSC. +# The time stamp counter in newer processors may support an enhancement, referred to as invariant TSC. +# The invariant TSC runs at a constant rate in all ACPI P-, C-. and T-states. +# This is the architectural behavior moving forward. +# TSC reads are much more efficient and do not incur the overhead associated with a ring transition or +# access to a platform resource. +# +# Copyright (c) 2009-2010, Intel Corporation. All rights reserved. +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +#**/ + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = TscTimerLib + FILE_GUID = 95ab030f-b4fd-4ee4-92a5-9e04e87634d9 + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = TimerLib + + CONSTRUCTOR = TscTimerLibConstructor + + +# +# VALID_ARCHITECTURES = IA32 X64 +# + +[Sources.common] + TscTimerLib.c + + +[Packages] + MdePkg/MdePkg.dec + PerformancePkg/PerformancePkg.dec + + +[LibraryClasses] + PcdLib + PciLib + IoLib + BaseLib + +[Pcd.common] + gPerformancePkgTokenSpaceGuid.PcdPerfPkgAcpiIoPortBaseAddress -- cgit v1.2.3