/** @file This file include the file which can help to get the system performance, all the function will only include if the performance switch is set. Copyright (c) 2004 - 2015, 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 "InternalBm.h" PERF_HEADER mBmPerfHeader; PERF_DATA mBmPerfData; EFI_PHYSICAL_ADDRESS mBmAcpiLowMemoryBase = 0x0FFFFFFFFULL; /** Get the short verion of PDB file name to be used in performance data logging. @param PdbFileName The long PDB file name. @param GaugeString The output string to be logged by performance logger. @param StringSize The buffer size of GaugeString in bytes. **/ VOID BmGetShortPdbFileName ( IN CONST CHAR8 *PdbFileName, OUT CHAR8 *GaugeString, IN UINTN StringSize ) { UINTN Index; UINTN Index1; UINTN StartIndex; UINTN EndIndex; if (PdbFileName == NULL) { AsciiStrCpyS (GaugeString, StringSize, " "); } else { StartIndex = 0; for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++) ; for (Index = 0; PdbFileName[Index] != 0; Index++) { if (PdbFileName[Index] == '\\') { StartIndex = Index + 1; } if (PdbFileName[Index] == '.') { EndIndex = Index; } } Index1 = 0; for (Index = StartIndex; Index < EndIndex; Index++) { GaugeString[Index1] = PdbFileName[Index]; Index1++; if (Index1 == StringSize - 1) { break; } } GaugeString[Index1] = 0; } return ; } /** Get the name from the Driver handle, which can be a handle with EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed. This name can be used in performance data logging. @param Handle Driver handle. @param GaugeString The output string to be logged by performance logger. @param StringSize The buffer size of GaugeString in bytes. **/ VOID BmGetNameFromHandle ( IN EFI_HANDLE Handle, OUT CHAR8 *GaugeString, IN UINTN StringSize ) { EFI_STATUS Status; EFI_LOADED_IMAGE_PROTOCOL *Image; CHAR8 *PdbFileName; EFI_DRIVER_BINDING_PROTOCOL *DriverBinding; AsciiStrCpyS (GaugeString, StringSize, " "); // // Get handle name from image protocol // Status = gBS->HandleProtocol ( Handle, &gEfiLoadedImageProtocolGuid, (VOID **) &Image ); if (EFI_ERROR (Status)) { Status = gBS->OpenProtocol ( Handle, &gEfiDriverBindingProtocolGuid, (VOID **) &DriverBinding, NULL, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return ; } // // Get handle name from image protocol // Status = gBS->HandleProtocol ( DriverBinding->ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &Image ); } PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase); if (PdbFileName != NULL) { BmGetShortPdbFileName (PdbFileName, GaugeString, StringSize); } return ; } /** 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 BmWriteBootToOsPerformanceData ( 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 VarSize; BOOLEAN Found; // // 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); mBmPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mBmPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mBmPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } // // Reset the entry count // mBmPerfHeader.Count = 0; if (mBmAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, NULL, &VarSize, &mBmAcpiLowMemoryBase ); 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) mBmAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); // // Get performance data // LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (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) { continue; } ZeroMem (&mBmPerfData, sizeof (PERF_DATA)); mBmPerfData.Duration = Duration; // // See if the Handle is in the handle buffer // Found = FALSE; for (Index = 0; Index < NoHandles; Index++) { if (Handle == Handles[Index]) { BmGetNameFromHandle (Handles[Index], GaugeString, PERF_TOKEN_SIZE); AsciiStrCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, GaugeString); Found = TRUE; break; } } if (!Found) { AsciiStrnCpyS (mBmPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); } CopyMem (Ptr, &mBmPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mBmPerfHeader.Count++; if (mBmPerfHeader.Count == LimitCount) { goto Done; } } } Done: FreePool (Handles); mBmPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mBmAcpiLowMemoryBase, &mBmPerfHeader, sizeof (PERF_HEADER) ); return ; }