/* ================ Sys_DoubleTime ================ */ double Sys_DoubleTime( void ) { static longtime_t g_PerformanceFrequency; static longtime_t g_ClockStart; longtime_t CurrentTime; #ifdef XASH_SDL if( !g_PerformanceFrequency ) { g_PerformanceFrequency = SDL_GetPerformanceFrequency(); g_ClockStart = SDL_GetPerformanceCounter(); } CurrentTime = SDL_GetPerformanceCounter(); return (double)( CurrentTime - g_ClockStart ) / (double)( g_PerformanceFrequency ); #elif _WIN32 if( !g_PerformanceFrequency ) { g_PerformanceFrequency = GetPerformanceFrequency(); g_ClockStart = GetPerformanceCounter(); } CurrentTime = GetPerformanceCounter(); return (double)( CurrentTime - g_ClockStart ) / (double)( g_PerformanceFrequency ); #else struct timespec ts; if( !g_PerformanceFrequency ) { struct timespec res; if( !clock_getres(CLOCK_MONOTONIC, &res) ) g_PerformanceFrequency = 1000000000LL/res.tv_nsec; } clock_gettime(CLOCK_MONOTONIC, &ts); return (double) ts.tv_sec + (double) ts.tv_nsec/1000000000.0; #endif }
EFIAPI AcquireSpinLock ( IN OUT SPIN_LOCK *SpinLock ) { UINT64 Tick; UINT64 Start, End; UINT64 Timeout; Tick = 0; Start = 0; End = 0; if (PcdGet32 (PcdSpinLockTimeout) > 0) { Tick = GetPerformanceCounter (); Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), PcdGet32 (PcdSpinLockTimeout) ), 1000000 ); if (Start < End) { Tick += Timeout; } else { Tick -= Timeout; } } while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ())); } return SpinLock; }
/** Fills in the end time of a performance measurement. Looks up the record that matches Handle, Token, Module and Identifier. If the record can not be found then return RETURN_NOT_FOUND. If the record is found and TimeStamp is not zero, then TimeStamp is added to the record as the end time. If the record is found and TimeStamp is zero, then this function reads the current time stamp and adds that time stamp value to the record as the end time. @param Handle Pointer to environment specific context used to identify the component being measured. @param Token Pointer to a Null-terminated ASCII string that identifies the component being measured. @param Module Pointer to a Null-terminated ASCII string that identifies the module being measured. @param TimeStamp 64-bit time stamp. @param Identifier 32-bit identifier. If the value is 0, the found record is same as the one found by EndPerformanceMeasurement. @retval RETURN_SUCCESS The end of the measurement was recorded. @retval RETURN_NOT_FOUND The specified measurement record could not be found. **/ RETURN_STATUS EFIAPI EndPerformanceMeasurementEx ( IN CONST VOID *Handle, OPTIONAL IN CONST CHAR8 *Token, OPTIONAL IN CONST CHAR8 *Module, OPTIONAL IN UINT64 TimeStamp, IN UINT32 Identifier ) { PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; UINT32 *PeiPerformanceIdArray; PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; UINT32 Index; if (TimeStamp == 0) { TimeStamp = GetPerformanceCounter (); } InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray); Index = InternalSearchForLogEntry (PeiPerformanceLog, PeiPerformanceIdArray, Handle, Token, Module, Identifier); if (Index >= PeiPerformanceLog->NumberOfEntries) { return RETURN_NOT_FOUND; } LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); LogEntryArray[Index].EndTimeStamp = TimeStamp; return RETURN_SUCCESS; }
void RandAddSeed() { // Seed with CPU performance counter int64_t nCounter = GetPerformanceCounter(); RAND_add(&nCounter, sizeof(nCounter), 1.5); memory_cleanse((void*)&nCounter, sizeof(nCounter)); }
HRESULT MyClock::GetAudioClockTime(REFERENCE_TIME* pAudioTime, REFERENCE_TIME* pCounterTime) { CheckPointer(pAudioTime, E_POINTER); CAutoLock lock(this); if (m_audioClock) { uint64_t audioFrequency, audioPosition, audioTime; if (SUCCEEDED(m_audioClock->GetFrequency(&audioFrequency)) && SUCCEEDED(m_audioClock->GetPosition(&audioPosition, &audioTime))) { int64_t counterTime = llMulDiv(GetPerformanceCounter(), OneSecond, m_performanceFrequency, 0); int64_t clockTime = llMulDiv(audioPosition, OneSecond, audioFrequency, 0) + m_audioStart + (audioPosition > 0 ? m_audioOffset + counterTime - audioTime : 0); *pAudioTime = clockTime; if (pCounterTime) *pCounterTime = counterTime; return S_OK; } } return E_FAIL; }
/** Searches the performance measurement log from the beginning of the log for the first matching record that contains a zero end time and fills in a valid end time. Searches the performance measurement log from the beginning of the log for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero. If the record can not be found then return EFI_NOT_FOUND. If the record is found and TimeStamp is not zero, then the end time in the record is filled in with the value specified by TimeStamp. If the record is found and TimeStamp is zero, then the end time in the matching record is filled in with the current time stamp value. @param Handle Pointer to environment specific context used to identify the component being measured. @param Token Pointer to a Null-terminated ASCII string that identifies the component being measured. @param Module Pointer to a Null-terminated ASCII string that identifies the module being measured. @param TimeStamp 64-bit time stamp. @param Identifier 32-bit identifier. If the value is 0, the found record is same as the one found by EndGauge of PERFORMANCE_PROTOCOL. @retval EFI_SUCCESS The end of the measurement was recorded. @retval EFI_NOT_FOUND The specified measurement record could not be found. **/ EFI_STATUS EFIAPI EndGaugeEx ( IN CONST VOID *Handle, OPTIONAL IN CONST CHAR8 *Token, OPTIONAL IN CONST CHAR8 *Module, OPTIONAL IN UINT64 TimeStamp, IN UINT32 Identifier ) { GAUGE_DATA_ENTRY_EX *GaugeEntryExArray; UINT32 Index; if (TimeStamp == 0) { TimeStamp = GetPerformanceCounter (); } Index = InternalSearchForGaugeEntry (Handle, Token, Module, Identifier); if (Index >= mGaugeData->NumberOfEntries) { return EFI_NOT_FOUND; } GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1); GaugeEntryExArray[Index].EndTimeStamp = TimeStamp; return EFI_SUCCESS; }
VOID CEntryPoint ( IN UINTN MpId, IN UINTN UefiMemoryBase, IN UINTN StacksBase ) { UINT64 StartTimeStamp; // Initialize the platform specific controllers ArmPlatformInitialize (MpId); if (PerformanceMeasurementEnabled ()) { // Initialize the Timer Library to setup the Timer HW controller TimerConstructor (); // We cannot call yet the PerformanceLib because the HOB List has not been initialized StartTimeStamp = GetPerformanceCounter (); } else { StartTimeStamp = 0; } // Data Cache enabled on Primary core when MMU is enabled. ArmDisableDataCache (); // Invalidate instruction cache ArmInvalidateInstructionCache (); // Enable Instruction Caches on all cores. ArmEnableInstructionCache (); PrePiMain (UefiMemoryBase, StacksBase, StartTimeStamp); // DXE Core should always load and never return ASSERT (FALSE); }
void RandAddSeed() { // Seed with CPU performance counter int64 nCounter = GetPerformanceCounter(); RAND_add(&nCounter, sizeof(nCounter), 1.5); memset(&nCounter, 0, sizeof(nCounter)); }
/** Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record performance data for ExitBootServicesEntry in FPDT. @param[in] Event The Event that is being processed. @param[in] Context The Event Context. **/ VOID EFIAPI FpdtExitBootServicesEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { if (mAcpiBootPerformanceTable == NULL) { // // Firmware Performance Data Table not installed, do nothing. // return ; } // // Update Firmware Basic Boot Performance Record for UEFI boot. // mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ()); // // Dump FPDT Boot Performance record. // DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry)); // // ExitBootServicesExit will be updated later, so don't dump it here. // }
UINT64 InternalGetPerformanceCounterFrequency ( VOID ) { BOOLEAN InterruptState; UINT64 Count; if (mPerformanceCounterFrequency == 0) { InterruptState = SaveAndDisableInterrupts (); Count = GetPerformanceCounter (); MicroSecondDelay (100); mPerformanceCounterFrequency = MultU64x32 (GetPerformanceCounter () - Count, 10000); SetInterruptState (InterruptState); } return mPerformanceCounterFrequency; }
/** Start Timer for SMM AP Sync. **/ UINT64 EFIAPI StartSyncTimer ( VOID ) { return GetPerformanceCounter (); }
VOID CEntryPoint ( IN UINTN MpId, IN UINTN UefiMemoryBase, IN UINTN StacksBase, IN UINTN GlobalVariableBase ) { UINT64 StartTimeStamp; ASSERT(!ArmIsMpCore() || (PcdGet32 (PcdCoreCount) > 1)); // Initialize the platform specific controllers ArmPlatformInitialize (MpId); if (ArmPlatformIsPrimaryCore (MpId) && PerformanceMeasurementEnabled ()) { // Initialize the Timer Library to setup the Timer HW controller TimerConstructor (); // We cannot call yet the PerformanceLib because the HOB List has not been initialized StartTimeStamp = GetPerformanceCounter (); } else { StartTimeStamp = 0; } // Data Cache enabled on Primary core when MMU is enabled. ArmDisableDataCache (); // Invalidate Data cache ArmInvalidateDataCache (); // Invalidate instruction cache ArmInvalidateInstructionCache (); // Enable Instruction Caches on all cores. ArmEnableInstructionCache (); // Define the Global Variable region when we are not running in XIP if (!IS_XIP()) { if (ArmPlatformIsPrimaryCore (MpId)) { mGlobalVariableBase = GlobalVariableBase; if (ArmIsMpCore()) { // Signal the Global Variable Region is defined (event: ARM_CPU_EVENT_DEFAULT) ArmCallSEV (); } } else { // Wait the Primay core has defined the address of the Global Variable region (event: ARM_CPU_EVENT_DEFAULT) ArmCallWFE (); } } // If not primary Jump to Secondary Main if (ArmPlatformIsPrimaryCore (MpId)) { // Goto primary Main. PrimaryMain (UefiMemoryBase, StacksBase, GlobalVariableBase, StartTimeStamp); } else { SecondaryMain (MpId); } // DXE Core should always load and never return ASSERT (FALSE); }
bool PerfCounterItem::SetCounterValue(int newValue) { bool ret = false; if (mPerfCounterId!=-1 ) { ret = GetPerformanceCounter()->SetPerformanceCounter(mPerfCounterId,newValue); } return ret; }
bool PerfCounterItem::SetName(const char* name) { bool ret = false; mPerfCounterId = GetPerformanceCounter()->AddPerformanceCounter(name); if (mPerfCounterId!=-1) { ret = true; } return ret; }
bool PerfCounterItem::Increment(int incrementvalue) { bool ret = false; if (mPerfCounterId!=-1 ) { ret = GetPerformanceCounter()->IncrementPerformanceCounter(mPerfCounterId,incrementvalue); } return ret; }
/******************************************************************** * * TimerHandler * * Handles both coalesced and non-coalesced timers, and keeps * the record of the effective elapsed time. * Switches the coalesced modes periodically for comparison. * *********************************************************************/ void CALLBACK TimerHandler(_In_ HWND hwnd, _In_ UINT_PTR idEvent) { if (idEvent >= ARRAYSIZE(gTimerRec)) { return; } TimerRec& t = gTimerRec[idEvent]; LONGLONG lTime = GetPerformanceCounter(); LONGLONG lElapsed = lTime - t.lLast; t.lElapsedMin = min(t.lElapsedMin, lElapsed); t.lElapsedMax = max(t.lElapsedMax, lElapsed); t.lLast = lTime; ++t.lCount; t.lSum += lElapsed; if (t.lCount % TIMER_CONTIGUOUS_RUN == 0) { // Now, let's switch the timer types. // First, kill the current timer. KillTimer(hwnd, idEvent); // Reverse the timer id. idEvent = !idEvent; /* * Setting new timer - switching the coalescing mode. * * Note that the coalesced timers may be fired * together with other timers that are readied during the * coalescing tolerance. As such, in an environment * that has a lot of short timers may only see a small or no * increase in the average time. * If that's the case, try running this sample with * the minimum number of processes. */ gTimerRec[idEvent].lLast = GetPerformanceCounter(); SetCoalescableTimer(hwnd, idEvent, TIMER_ELAPSE, NULL, idEvent == TIMERID_NOCOALSCING ? TIMERV_NO_COALESCING : TIMER_TOLERANCE); } }
REFERENCE_TIME MyClock::GetPrivateTime() { CAutoLock lock(this); REFERENCE_TIME audioClockTime, audioClockCounterTime; if (SUCCEEDED(GetAudioClockTime(&audioClockTime, &audioClockCounterTime))) { m_counterOffset = audioClockTime - audioClockCounterTime; return audioClockTime; } return m_counterOffset + llMulDiv(GetPerformanceCounter(), OneSecond, m_performanceFrequency, 0); }
/****************************************************************** * * WndProc * ******************************************************************/ LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_CREATE: // Start with non-coalescable timer. // Later we switch to the coalescable timer. gTimerRec[TIMERID_NOCOALSCING].lLast = GetPerformanceCounter(); if (!SetCoalescableTimer(hwnd, TIMERID_NOCOALSCING, TIMER_ELAPSE, NULL, TIMERV_NO_COALESCING)) { return -1; } // Let's update the screen periodically. SetTimer(hwnd, TIMERID_UPDATE_SCREEN, TIMER_AUTO_REFRESH_ELAPSE, NULL); return 0; case WM_TIMER: if (wParam < ARRAYSIZE(gTimerRec)) { TimerHandler(hwnd, (UINT_PTR)wParam); } else if (wParam == TIMERID_UPDATE_SCREEN) { // Periodically update the results. case WM_MOUSEMOVE: // Tricky: also update the screen at every mouse move. InvalidateRect(hwnd, NULL, FALSE); } break; case WM_PAINT: case WM_DISPLAYCHANGE: { PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps); OnPaint(hdc, &ps.rcPaint); EndPaint(hwnd, &ps); } return 0; case WM_KEYDOWN: if (wParam == VK_SPACE) { // Space key to power down the monitor. DefWindowProc(GetDesktopWindow(), WM_SYSCOMMAND, SC_MONITORPOWER, 2); } break; case WM_DESTROY: PostQuitMessage(0); return 1; } return DefWindowProc(hwnd, message, wParam, lParam); }
/** Retrieves the current value of a 64-bit free running timestamp counter. The counter shall count up in proportion to the amount of time that has passed. The counter value will always roll over to zero. The properties of the counter can be retrieved from GetProperties(). The caller should be prepared for the function to return the same value twice across successive calls. The counter value will not go backwards other than when wrapping, as defined by EndValue in GetProperties(). The frequency of the returned timestamp counter value must remain constant. Power management operations that affect clocking must not change the returned counter frequency. The quantization of counter value updates may vary as long as the value reflecting time passed remains consistent. @retval The current value of the free running timestamp counter. **/ UINT64 EFIAPI TimestampDriverGetTimestamp ( VOID ) { // // The timestamp of Timestamp Protocol // UINT64 TimestampValue; TimestampValue = 0; // // Get the timestamp // if (mTimerLibStartValue > mTimerLibEndValue) { TimestampValue = mTimerLibStartValue - GetPerformanceCounter(); } else { TimestampValue = GetPerformanceCounter() - mTimerLibStartValue; } return TimestampValue; }
/** Creates a record for the beginning of a performance measurement. Creates a record that contains the Handle, Token, Module and Identifier. If TimeStamp is not zero, then TimeStamp is added to the record as the start time. If TimeStamp is zero, then this function reads the current time stamp and adds that time stamp value to the record as the start time. @param Handle Pointer to environment specific context used to identify the component being measured. @param Token Pointer to a Null-terminated ASCII string that identifies the component being measured. @param Module Pointer to a Null-terminated ASCII string that identifies the module being measured. @param TimeStamp 64-bit time stamp. @param Identifier 32-bit identifier. If the value is 0, the created record is same as the one created by StartPerformanceMeasurement. @retval RETURN_SUCCESS The start of the measurement was recorded. @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement. **/ RETURN_STATUS EFIAPI StartPerformanceMeasurementEx ( IN CONST VOID *Handle, OPTIONAL IN CONST CHAR8 *Token, OPTIONAL IN CONST CHAR8 *Module, OPTIONAL IN UINT64 TimeStamp, IN UINT32 Identifier ) { PEI_PERFORMANCE_LOG_HEADER *PeiPerformanceLog; UINT32 *PeiPerformanceIdArray; PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray; UINT32 Index; UINT16 PeiPerformanceLogEntries; PeiPerformanceLogEntries = (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ? PcdGet16 (PcdMaxPeiPerformanceLogEntries16) : PcdGet8 (PcdMaxPeiPerformanceLogEntries)); InternalGetPerformanceHobLog (&PeiPerformanceLog, &PeiPerformanceIdArray); if (PeiPerformanceLog->NumberOfEntries >= PeiPerformanceLogEntries) { DEBUG ((DEBUG_ERROR, "PEI performance log array out of resources\n")); return RETURN_OUT_OF_RESOURCES; } Index = PeiPerformanceLog->NumberOfEntries++; LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (PeiPerformanceLog + 1); LogEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle; if (Token != NULL) { AsciiStrnCpyS (LogEntryArray[Index].Token, PEI_PERFORMANCE_STRING_SIZE, Token, PEI_PERFORMANCE_STRING_LENGTH); } if (Module != NULL) { AsciiStrnCpyS (LogEntryArray[Index].Module, PEI_PERFORMANCE_STRING_SIZE, Module, PEI_PERFORMANCE_STRING_LENGTH); } LogEntryArray[Index].EndTimeStamp = 0; PeiPerformanceIdArray[Index] = Identifier; if (TimeStamp == 0) { TimeStamp = GetPerformanceCounter (); } LogEntryArray[Index].StartTimeStamp = TimeStamp; return RETURN_SUCCESS; }
/** Check if the SMM AP Sync timer is timeout. @param Timer The start timer from the begin. **/ BOOLEAN EFIAPI IsSyncTimerTimeout ( IN UINT64 Timer ) { UINT64 CurrentTimer; UINT64 Delta; CurrentTimer = GetPerformanceCounter (); // // We need to consider the case that CurrentTimer is equal to Timer // when some timer runs too slow and CPU runs fast. We think roll over // condition does not happen on this case. // if (mCountDown) { // // The performance counter counts down. Check for roll over condition. // if (CurrentTimer <= Timer) { Delta = Timer - CurrentTimer; } else { // // Handle one roll-over. // Delta = mCycle - (CurrentTimer - Timer) + 1; } } else { // // The performance counter counts up. Check for roll over condition. // if (CurrentTimer >= Timer) { Delta = CurrentTimer - Timer; } else { // // Handle one roll-over. // Delta = mCycle - (Timer - CurrentTimer) + 1; } } return (BOOLEAN) (Delta >= mTimeoutTicker); }
/** Check if the timer is timeout. @param[in] UsbDebugPortHandle Pointer to USB Debug port handle @param[in] Timer The start timer from the begin. @param[in] TimeoutTicker Ticker number need time out. @return TRUE Timer time out occurs. @retval FALSE Timer does not time out. **/ BOOLEAN IsTimerTimeout ( IN USB_DEBUG_PORT_HANDLE *UsbDebugPortHandle, IN UINT64 Timer, IN UINT64 TimeoutTicker ) { UINT64 CurrentTimer; UINT64 Delta; CurrentTimer = GetPerformanceCounter (); if (UsbDebugPortHandle->TimerCountDown) { // // The timer counter counts down. Check for roll over condition. // if (CurrentTimer < Timer) { Delta = Timer - CurrentTimer; } else { // // Handle one roll-over. // Delta = UsbDebugPortHandle->TimerCycle - (CurrentTimer - Timer); } } else { // // The timer counter counts up. Check for roll over condition. // if (CurrentTimer > Timer) { Delta = CurrentTimer - Timer; } else { // // Handle one roll-over. // Delta = UsbDebugPortHandle->TimerCycle - (Timer - CurrentTimer); } } return (BOOLEAN) (Delta >= TimeoutTicker); }
/** Notify function for event EVT_SIGNAL_EXIT_BOOT_SERVICES. This is used to record performance data for ExitBootServicesEntry in FPDT. @param[in] Event The Event that is being processed. @param[in] Context The Event Context. **/ VOID EFIAPI FpdtExitBootServicesEventNotify ( IN EFI_EVENT Event, IN VOID *Context ) { if (!mDxeCoreReportStatusCodeEnable) { // // When DxeCore Report Status Code is disabled, // Unregister boot time report status code listener at ExitBootService Event. // mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe); } if (mAcpiBootPerformanceTable == NULL) { // // Firmware Performance Data Table not installed, do nothing. // return ; } // // Update Firmware Basic Boot Performance Record for UEFI boot. // mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry = GetTimeInNanoSecond (GetPerformanceCounter ()); // // Dump FPDT Boot Performance record. // DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ResetEnd = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ResetEnd)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderLoadImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - OsLoaderStartImageStart = %ld\n", mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart)); DEBUG ((EFI_D_INFO, "FPDT: Boot Performance - ExitBootServicesEntry = %ld\n", mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesEntry)); // // ExitBootServicesExit will be updated later, so don't dump it here. // }
/** Allocates a block of memory and writes performance data of booting into it. OS can processing these record. **/ VOID WriteBootToOsPerformanceData ( VOID ) { EFI_STATUS Status; UINT32 AcpiLowMemoryLength; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_LENGTH]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } AcpiLowMemoryLength = 0x4000; if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { // // Allocate a block of memory that contain performance data to OS // Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (AcpiLowMemoryLength), &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { FreePool (Handles); return ; } } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpy (mPerfData.Token, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); gRT->SetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (EFI_PHYSICAL_ADDRESS), &mAcpiLowMemoryBase ); return ; }
/** Report status code listener for SMM. This is used to record the performance data for S3 Suspend Start and S3 Suspend End in FPDT. @param[in] CodeType Indicates the type of status code being reported. @param[in] Value Describes the current status of a hardware or software entity. This included information about the class and subclass that is used to classify the entity as well as an operation. @param[in] Instance The enumeration of a hardware or software entity within the system. Valid instance numbers start with 1. @param[in] CallerId This optional parameter may be used to identify the caller. This parameter allows the status code driver to apply different rules to different callers. @param[in] Data This optional parameter may be used to pass additional data. @retval EFI_SUCCESS Status code is what we expected. @retval EFI_UNSUPPORTED Status code not supported. **/ EFI_STATUS EFIAPI FpdtStatusCodeListenerSmm ( IN EFI_STATUS_CODE_TYPE CodeType, IN EFI_STATUS_CODE_VALUE Value, IN UINT32 Instance, IN EFI_GUID *CallerId, IN EFI_STATUS_CODE_DATA *Data ) { EFI_STATUS Status; UINT64 CurrentTime; EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD S3SuspendRecord; UINT8 *NewRecordBuffer; // // Check whether status code is what we are interested in. // if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) { return EFI_UNSUPPORTED; } // // Collect one or more Boot records in boot time // if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) { AcquireSpinLock (&mSmmFpdtLock); if (mBootRecordSize + Data->Size > mBootRecordMaxSize) { // // Try to allocate big SMRAM data to store Boot record. // if (mSmramIsOutOfResource) { ReleaseSpinLock (&mSmmFpdtLock); return EFI_OUT_OF_RESOURCES; } NewRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer); if (NewRecordBuffer == NULL) { ReleaseSpinLock (&mSmmFpdtLock); mSmramIsOutOfResource = TRUE; return EFI_OUT_OF_RESOURCES; } mBootRecordBuffer = NewRecordBuffer; mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE; } // // Save boot record into the temp memory space. // CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size); mBootRecordSize += Data->Size; ReleaseSpinLock (&mSmmFpdtLock); return EFI_SUCCESS; } if ((Value != PcdGet32 (PcdProgressCodeS3SuspendStart)) && (Value != PcdGet32 (PcdProgressCodeS3SuspendEnd))) { return EFI_UNSUPPORTED; } // // Retrieve current time. // CurrentTime = GetTimeInNanoSecond (GetPerformanceCounter ()); if (Value == PcdGet32 (PcdProgressCodeS3SuspendStart)) { // // S3 Suspend started, record the performance data and return. // mSuspendStartTime = CurrentTime; return EFI_SUCCESS; } // // We are going to S3 sleep, record S3 Suspend End performance data. // S3SuspendRecord.SuspendStart = mSuspendStartTime; S3SuspendRecord.SuspendEnd = CurrentTime; // // Save S3 suspend performance data to lock box, it will be used by Firmware Performance PEIM. // if (!mS3SuspendLockBoxSaved) { Status = SaveLockBox ( &gEfiFirmwarePerformanceGuid, &S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD) ); ASSERT_EFI_ERROR (Status); mS3SuspendLockBoxSaved = TRUE; } else { Status = UpdateLockBox ( &gEfiFirmwarePerformanceGuid, 0, &S3SuspendRecord, sizeof (EFI_ACPI_5_0_FPDT_S3_SUSPEND_RECORD) ); ASSERT_EFI_ERROR (Status); } return EFI_SUCCESS; }
REFERENCE_TIME MyTestClock::GetPrivateTime() { return llMulDiv(GetPerformanceCounter(), OneSecond, m_performanceFrequency, 0); }
/** Writes performance data of booting into the allocated memory. OS can process these records. @param Event The triggered event. @param Context Context for this event. **/ VOID EFIAPI WriteBootToOsPerformanceData ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_SIZE]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; UINTN VarSize; // // Record the performance data for End of BDS // PERF_END(NULL, "BDS", NULL, 0); // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, NULL, &VarSize, &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { // // Fail to get the variable, return. // return; } } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); return ; }
EFIAPI AcquireSpinLock ( IN OUT SPIN_LOCK *SpinLock ) { UINT64 Current; UINT64 Previous; UINT64 Total; UINT64 Start; UINT64 End; UINT64 Timeout; INT64 Cycle; INT64 Delta; if (PcdGet32 (PcdSpinLockTimeout) > 0) { // // Get the current timer value // Current = GetPerformanceCounter(); // // Initialize local variables // Start = 0; End = 0; Total = 0; // // Retrieve the performance counter properties and compute the number of performance // counter ticks required to reach the timeout // Timeout = DivU64x32 ( MultU64x32 ( GetPerformanceCounterProperties (&Start, &End), PcdGet32 (PcdSpinLockTimeout) ), 1000000 ); Cycle = End - Start; if (Cycle < 0) { Cycle = -Cycle; } Cycle++; while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); Previous = Current; Current = GetPerformanceCounter(); Delta = (INT64) (Current - Previous); if (Start > End) { Delta = -Delta; } if (Delta < 0) { Delta += Cycle; } Total += Delta; ASSERT (Total < Timeout); } } else { while (!AcquireSpinLockOrFail (SpinLock)) { CpuPause (); } } return SpinLock; }
/** Adds a record at the end of the performance measurement log that records the start time of a performance measurement. Adds a record to the end of the performance measurement log that contains the Handle, Token, Module and Identifier. The end time of the new record must be set to zero. If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record. If TimeStamp is zero, the start time in the record is filled in with the value read from the current time stamp. @param Handle Pointer to environment specific context used to identify the component being measured. @param Token Pointer to a Null-terminated ASCII string that identifies the component being measured. @param Module Pointer to a Null-terminated ASCII string that identifies the module being measured. @param TimeStamp 64-bit time stamp. @param Identifier 32-bit identifier. If the value is 0, the created record is same as the one created by StartGauge of PERFORMANCE_PROTOCOL. @retval EFI_SUCCESS The data was read correctly from the device. @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement. **/ EFI_STATUS EFIAPI StartGaugeEx ( IN CONST VOID *Handle, OPTIONAL IN CONST CHAR8 *Token, OPTIONAL IN CONST CHAR8 *Module, OPTIONAL IN UINT64 TimeStamp, IN UINT32 Identifier ) { GAUGE_DATA_ENTRY_EX *GaugeEntryExArray; UINTN GaugeDataSize; GAUGE_DATA_HEADER *NewGaugeData; UINTN OldGaugeDataSize; GAUGE_DATA_HEADER *OldGaugeData; UINT32 Index; Index = mGaugeData->NumberOfEntries; if (Index >= mMaxGaugeRecords) { // // Try to enlarge the scale of gauge array. // OldGaugeData = mGaugeData; OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords; GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2; NewGaugeData = AllocateZeroPool (GaugeDataSize); if (NewGaugeData == NULL) { return EFI_OUT_OF_RESOURCES; } mGaugeData = NewGaugeData; mMaxGaugeRecords *= 2; // // Initialize new data array and migrate old data one. // mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize); FreePool (OldGaugeData); } GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1); GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle; if (Token != NULL) { AsciiStrCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, Token); } if (Module != NULL) { AsciiStrCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, Module); } GaugeEntryExArray[Index].EndTimeStamp = 0; GaugeEntryExArray[Index].Identifier = Identifier; if (TimeStamp == 0) { TimeStamp = GetPerformanceCounter (); } GaugeEntryExArray[Index].StartTimeStamp = TimeStamp; mGaugeData->NumberOfEntries++; return EFI_SUCCESS; }
/** Report status code listener of FPDT. This is used to collect performance data for OsLoaderLoadImageStart and OsLoaderStartImageStart in FPDT. @param[in] CodeType Indicates the type of status code being reported. @param[in] Value Describes the current status of a hardware or software entity. This included information about the class and subclass that is used to classify the entity as well as an operation. @param[in] Instance The enumeration of a hardware or software entity within the system. Valid instance numbers start with 1. @param[in] CallerId This optional parameter may be used to identify the caller. This parameter allows the status code driver to apply different rules to different callers. @param[in] Data This optional parameter may be used to pass additional data. @retval EFI_SUCCESS Status code is what we expected. @retval EFI_UNSUPPORTED Status code not supported. **/ EFI_STATUS EFIAPI FpdtStatusCodeListenerDxe ( IN EFI_STATUS_CODE_TYPE CodeType, IN EFI_STATUS_CODE_VALUE Value, IN UINT32 Instance, IN EFI_GUID *CallerId, IN EFI_STATUS_CODE_DATA *Data ) { EFI_STATUS Status; // // Check whether status code is what we are interested in. // if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) != EFI_PROGRESS_CODE) { return EFI_UNSUPPORTED; } Status = EFI_SUCCESS; if (Value == PcdGet32 (PcdProgressCodeOsLoaderLoad)) { // // Progress code for OS Loader LoadImage. // if (mAcpiBootPerformanceTable == NULL) { return Status; } // // Update OS Loader LoadImage Start for UEFI boot. // mAcpiBootPerformanceTable->BasicBoot.OsLoaderLoadImageStart = GetTimeInNanoSecond (GetPerformanceCounter ()); } else if (Value == PcdGet32 (PcdProgressCodeOsLoaderStart)) { // // Progress code for OS Loader StartImage. // if (mAcpiBootPerformanceTable == NULL) { return Status; } // // Update OS Loader StartImage Start for UEFI boot. // mAcpiBootPerformanceTable->BasicBoot.OsLoaderStartImageStart = GetTimeInNanoSecond (GetPerformanceCounter ()); } else if (Value == (EFI_SOFTWARE_EFI_BOOT_SERVICE | EFI_SW_BS_PC_EXIT_BOOT_SERVICES)) { // // Progress code for ExitBootServices. // if (mAcpiBootPerformanceTable == NULL) { return Status; } // // Update ExitBootServicesExit for UEFI boot. // mAcpiBootPerformanceTable->BasicBoot.ExitBootServicesExit = GetTimeInNanoSecond (GetPerformanceCounter ()); // // Unregister boot time report status code listener. // mRscHandlerProtocol->Unregister (FpdtStatusCodeListenerDxe); } else if (Data != NULL && CompareGuid (&Data->Type, &gEfiFirmwarePerformanceGuid)) { // // Append one or more Boot records // if (mAcpiBootPerformanceTable == NULL) { // // Append Boot records before FPDT ACPI table is installed. // if (mBootRecordSize + Data->Size > mBootRecordMaxSize) { mBootRecordBuffer = ReallocatePool (mBootRecordSize, mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE, mBootRecordBuffer); ASSERT (mBootRecordBuffer != NULL); mBootRecordMaxSize = mBootRecordSize + Data->Size + EXTENSION_RECORD_SIZE; } // // Save boot record into the temp memory space. // CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size); mBootRecordSize += Data->Size; } else { // // Append Boot records after FPDT ACPI table is installed. // if (mBootRecordSize + Data->Size > mBootRecordMaxSize) { // // No enough space to save boot record. // Status = EFI_OUT_OF_RESOURCES; } else { // // Save boot record into BootPerformance table // CopyMem (mBootRecordBuffer + mBootRecordSize, Data + 1, Data->Size); mBootRecordSize += Data->Size; mAcpiBootPerformanceTable->Header.Length = mBootRecordSize; } } } else { // // Ignore else progress code. // Status = EFI_UNSUPPORTED; } return Status; }