--- /dev/null
+/** @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 - 2008, Intel Corporation. <BR>\r
+All rights reserved. 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
+\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
+ AsciiStrCpy (GaugeString, " ");\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 - 1) {\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
+ AsciiStrCpy (GaugeString, " ");\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
+ Allocates a block of memory and writes performance data of booting into it.\r
+ OS can processing these record.\r
+ \r
+**/\r
+VOID\r
+WriteBootToOsPerformanceData (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;\r
+ UINT32 AcpiLowMemoryLength;\r
+ UINT32 LimitCount;\r
+ EFI_HANDLE *Handles;\r
+ UINTN NoHandles;\r
+ CHAR8 GaugeString[PERF_TOKEN_LENGTH];\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
+\r
+ //\r
+ // Retrive time stamp count as early as possilbe\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
+ AcpiLowMemoryLength = 0x2000;\r
+\r
+ //\r
+ // Allocate a block of memory that contain performance data to OS\r
+ //\r
+ Status = gBS->AllocatePages (\r
+ AllocateAnyPages,\r
+ EfiACPIReclaimMemory,\r
+ EFI_SIZE_TO_PAGES (AcpiLowMemoryLength),\r
+ &AcpiLowMemoryBase\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+\r
+ Ptr = (UINT8 *) ((UINT32) AcpiLowMemoryBase + sizeof (PERF_HEADER));\r
+ LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\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
+ gBS->FreePages (AcpiLowMemoryBase, 1);\r
+ return ;\r
+ }\r
+ \r
+ //\r
+ // Get DXE drivers performance\r
+ //\r
+ for (Index = 0; Index < NoHandles; Index++) {\r
+ Ticker = 0;\r
+ LogEntryKey = 0;\r
+ while ((LogEntryKey = GetPerformanceMeasurement (\r
+ LogEntryKey,\r
+ &Handle,\r
+ &Token,\r
+ &Module,\r
+ &StartTicker,\r
+ &EndTicker)) != 0) {\r
+ if ((Handle == Handles[Index]) && (EndTicker != 0)) {\r
+ Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);\r
+ }\r
+ }\r
+\r
+ Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);\r
+\r
+ if (Duration > 0) {\r
+\r
+ GetNameFromHandle (Handles[Index], GaugeString);\r
+\r
+ AsciiStrCpy (mPerfData.Token, GaugeString);\r
+ mPerfData.Duration = Duration;\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
+ FreePool (Handles);\r
+\r
+ //\r
+ // Get inserted 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 (Handle == NULL && EndTicker != 0) {\r
+\r
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
+\r
+ AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH);\r
+ Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);\r
+\r
+ mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);\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
+ mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;\r
+\r
+ //\r
+ // Put performance data to ACPI memory\r
+ //\r
+ CopyMem (\r
+ (UINTN *) (UINTN) AcpiLowMemoryBase,\r
+ &mPerfHeader,\r
+ sizeof (PERF_HEADER)\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ L"PerfDataMemAddr",\r
+ &gEfiGenericPlatformVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (EFI_PHYSICAL_ADDRESS),\r
+ &AcpiLowMemoryBase\r
+ );\r
+\r
+ return ;\r
+}\r