-/** @file\r
- This file include the file which can help to get the system\r
- performance, all the function will only include if the performance\r
- switch is set.\r
-\r
-Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "InternalBdsLib.h"\r
-\r
-PERF_HEADER mPerfHeader;\r
-PERF_DATA mPerfData;\r
-EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase = 0x0FFFFFFFFULL;\r
-\r
-/**\r
- Get the short verion of PDB file name to be\r
- used in performance data logging.\r
-\r
- @param PdbFileName The long PDB file name.\r
- @param GaugeString The output string to be logged by performance logger.\r
-\r
-**/\r
-VOID\r
-GetShortPdbFileName (\r
- IN CONST CHAR8 *PdbFileName,\r
- OUT CHAR8 *GaugeString\r
- )\r
-{\r
- UINTN Index;\r
- UINTN Index1;\r
- UINTN StartIndex;\r
- UINTN EndIndex;\r
-\r
- if (PdbFileName == NULL) {\r
- AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");\r
- } else {\r
- StartIndex = 0;\r
- for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
- ;\r
-\r
- for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
- if (PdbFileName[Index] == '\\') {\r
- StartIndex = Index + 1;\r
- }\r
-\r
- if (PdbFileName[Index] == '.') {\r
- EndIndex = Index;\r
- }\r
- }\r
-\r
- Index1 = 0;\r
- for (Index = StartIndex; Index < EndIndex; Index++) {\r
- GaugeString[Index1] = PdbFileName[Index];\r
- Index1++;\r
- if (Index1 == PERF_TOKEN_LENGTH) {\r
- break;\r
- }\r
- }\r
-\r
- GaugeString[Index1] = 0;\r
- }\r
-\r
- return ;\r
-}\r
-\r
-/**\r
- Get the name from the Driver handle, which can be a handle with\r
- EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.\r
- This name can be used in performance data logging.\r
-\r
- @param Handle Driver handle.\r
- @param GaugeString The output string to be logged by performance logger.\r
-\r
-**/\r
-VOID\r
-GetNameFromHandle (\r
- IN EFI_HANDLE Handle,\r
- OUT CHAR8 *GaugeString\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_LOADED_IMAGE_PROTOCOL *Image;\r
- CHAR8 *PdbFileName;\r
- EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
-\r
- AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");\r
-\r
- //\r
- // Get handle name from image protocol\r
- //\r
- Status = gBS->HandleProtocol (\r
- Handle,\r
- &gEfiLoadedImageProtocolGuid,\r
- (VOID **) &Image\r
- );\r
-\r
- if (EFI_ERROR (Status)) {\r
- Status = gBS->OpenProtocol (\r
- Handle,\r
- &gEfiDriverBindingProtocolGuid,\r
- (VOID **) &DriverBinding,\r
- NULL,\r
- NULL,\r
- EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return ;\r
- }\r
- //\r
- // Get handle name from image protocol\r
- //\r
- Status = gBS->HandleProtocol (\r
- DriverBinding->ImageHandle,\r
- &gEfiLoadedImageProtocolGuid,\r
- (VOID **) &Image\r
- );\r
- }\r
-\r
- PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);\r
-\r
- if (PdbFileName != NULL) {\r
- GetShortPdbFileName (PdbFileName, GaugeString);\r
- }\r
-\r
- return ;\r
-}\r
-\r
-/**\r
-\r
- Writes performance data of booting into the allocated memory.\r
- OS can process these records.\r
-\r
- @param Event The triggered event.\r
- @param Context Context for this event.\r
-\r
-**/\r
-VOID\r
-EFIAPI\r
-WriteBootToOsPerformanceData (\r
- IN EFI_EVENT Event,\r
- IN VOID *Context\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 LimitCount;\r
- EFI_HANDLE *Handles;\r
- UINTN NoHandles;\r
- CHAR8 GaugeString[PERF_TOKEN_SIZE];\r
- UINT8 *Ptr;\r
- UINT32 Index;\r
- UINT64 Ticker;\r
- UINT64 Freq;\r
- UINT32 Duration;\r
- UINTN LogEntryKey;\r
- CONST VOID *Handle;\r
- CONST CHAR8 *Token;\r
- CONST CHAR8 *Module;\r
- UINT64 StartTicker;\r
- UINT64 EndTicker;\r
- UINT64 StartValue;\r
- UINT64 EndValue;\r
- BOOLEAN CountUp;\r
- UINTN VarSize;\r
- BOOLEAN Found;\r
-\r
- //\r
- // Record the performance data for End of BDS\r
- //\r
- PERF_END(NULL, "BDS", NULL, 0);\r
-\r
- //\r
- // Retrieve time stamp count as early as possible\r
- //\r
- Ticker = GetPerformanceCounter ();\r
-\r
- Freq = GetPerformanceCounterProperties (&StartValue, &EndValue);\r
- \r
- Freq = DivU64x32 (Freq, 1000);\r
-\r
- mPerfHeader.CpuFreq = Freq;\r
-\r
- //\r
- // Record BDS raw performance data\r
- //\r
- if (EndValue >= StartValue) {\r
- mPerfHeader.BDSRaw = Ticker - StartValue;\r
- CountUp = TRUE;\r
- } else {\r
- mPerfHeader.BDSRaw = StartValue - Ticker;\r
- CountUp = FALSE;\r
- }\r
-\r
- //\r
- // Reset the entry count\r
- //\r
- mPerfHeader.Count = 0;\r
-\r
- if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {\r
- VarSize = sizeof (EFI_PHYSICAL_ADDRESS);\r
- Status = gRT->GetVariable (\r
- L"PerfDataMemAddr",\r
- &gPerformanceProtocolGuid,\r
- NULL,\r
- &VarSize,\r
- &mAcpiLowMemoryBase\r
- );\r
- if (EFI_ERROR (Status)) {\r
- //\r
- // Fail to get the variable, return.\r
- //\r
- return;\r
- }\r
- }\r
-\r
- //\r
- // Put Detailed performance data into memory\r
- //\r
- Handles = NULL;\r
- Status = gBS->LocateHandleBuffer (\r
- AllHandles,\r
- NULL,\r
- NULL,\r
- &NoHandles,\r
- &Handles\r
- );\r
- if (EFI_ERROR (Status)) {\r
- return ;\r
- }\r
-\r
- Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
- LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
-\r
- //\r
- // Get performance data\r
- //\r
- LogEntryKey = 0;\r
- while ((LogEntryKey = GetPerformanceMeasurement (\r
- LogEntryKey,\r
- &Handle,\r
- &Token,\r
- &Module,\r
- &StartTicker,\r
- &EndTicker)) != 0) {\r
- if (EndTicker != 0) {\r
- if (StartTicker == 1) {\r
- StartTicker = StartValue;\r
- }\r
- if (EndTicker == 1) {\r
- EndTicker = StartValue;\r
- }\r
- Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);\r
-\r
- Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);\r
- if (Duration == 0) {\r
- continue;\r
- }\r
-\r
- ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
-\r
- mPerfData.Duration = Duration;\r
-\r
- //\r
- // See if the Handle is in the handle buffer\r
- //\r
- Found = FALSE;\r
- for (Index = 0; Index < NoHandles; Index++) {\r
- if (Handle == Handles[Index]) {\r
- GetNameFromHandle (Handles[Index], GaugeString);\r
- AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString);\r
- Found = TRUE;\r
- break;\r
- }\r
- }\r
-\r
- if (!Found) {\r
- AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);\r
- }\r
-\r
- CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
- Ptr += sizeof (PERF_DATA);\r
-\r
- mPerfHeader.Count++;\r
- if (mPerfHeader.Count == LimitCount) {\r
- goto Done;\r
- }\r
- }\r
- }\r
-\r
-Done:\r
-\r
- FreePool (Handles);\r
-\r
- mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;\r
-\r
- //\r
- // Put performance data to Reserved memory\r
- //\r
- CopyMem (\r
- (UINTN *) (UINTN) mAcpiLowMemoryBase,\r
- &mPerfHeader,\r
- sizeof (PERF_HEADER)\r
- );\r
-\r
- return ;\r
-}\r