--- /dev/null
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation \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
+Module Name:\r
+\r
+ Performance.c\r
+\r
+Abstract:\r
+\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
+--*/\r
+\r
+#include "Performance.h"\r
+\r
+VOID\r
+ClearDebugRegisters (\r
+ VOID\r
+ )\r
+{\r
+ //\r
+ // BugBug: We should not need to do this. We need to root cause this bug!!!!\r
+ //\r
+ AsmWriteDr0 (0);\r
+ AsmWriteDr1 (0);\r
+}\r
+\r
+STATIC\r
+VOID\r
+GetShortPdbFileName (\r
+ CHAR8 *PdbFileName,\r
+ CHAR8 *GaugeString\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+Arguments:\r
+\r
+Returns:\r
+\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
+\r
+STATIC\r
+CHAR8 *\r
+GetPdbPath (\r
+ VOID *ImageBase\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Located PDB path name in PE image\r
+\r
+Arguments:\r
+\r
+ ImageBase - base of PE to search\r
+\r
+Returns:\r
+\r
+ Pointer into image at offset of PDB file name if PDB file name is found,\r
+ Otherwise a pointer to an empty string.\r
+\r
+--*/\r
+{\r
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r
+\r
+ ZeroMem (&ImageContext, sizeof (ImageContext));\r
+ ImageContext.Handle = ImageBase;\r
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+ PeCoffLoaderGetImageInfo (&ImageContext);\r
+\r
+ return ImageContext.PdbPointer;\r
+}\r
+\r
+\r
+STATIC\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 = GetPdbPath (Image->ImageBase);\r
+\r
+ if (PdbFileName != NULL) {\r
+ GetShortPdbFileName (PdbFileName, GaugeString);\r
+ }\r
+\r
+ return ;\r
+}\r
+\r
+\r
+\r
+VOID\r
+WriteBootToOsPerformanceData (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ \r
+ Allocates a block of memory and writes performance data of booting to OS into it.\r
+\r
+Arguments:\r
+ \r
+ None\r
+ \r
+Returns:\r
+\r
+ None\r
+\r
+--*/\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_CPU_ARCH_PROTOCOL *Cpu;\r
+ EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;\r
+ UINT32 mAcpiLowMemoryLength;\r
+ UINT32 LimitCount;\r
+ PERF_HEADER mPerfHeader;\r
+ PERF_DATA mPerfData;\r
+ EFI_HANDLE *Handles;\r
+ UINTN NoHandles;\r
+ CHAR8 GaugeString[PERF_TOKEN_LENGTH];\r
+ UINT8 *Ptr;\r
+ UINT32 mIndex;\r
+ UINT64 Ticker;\r
+ UINT64 Freq;\r
+ UINT32 Duration;\r
+ UINT64 CurrentTicker;\r
+ UINT64 TimerPeriod;\r
+ UINTN LogEntryKey;\r
+ CONST VOID *Handle;\r
+ CONST CHAR8 *Token;\r
+ CONST CHAR8 *Module;\r
+ UINT64 StartTicker;\r
+ UINT64 EndTicker;\r
+\r
+ //\r
+ // Retrive time stamp count as early as possilbe\r
+ //\r
+ Ticker = AsmReadTsc ();\r
+\r
+ //\r
+ // Allocate a block of memory that contain performance data to OS\r
+ //\r
+ mAcpiLowMemoryBase = 0xFFFFFFFF;\r
+ Status = gBS->AllocatePages (\r
+ AllocateMaxAddress,\r
+ EfiReservedMemoryType,\r
+ 4,\r
+ &mAcpiLowMemoryBase\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ return ;\r
+ }\r
+\r
+ mAcpiLowMemoryLength = EFI_PAGES_TO_SIZE(4);\r
+\r
+ Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
+ LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
+\r
+ //\r
+ // Initialize performance data structure\r
+ //\r
+ ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));\r
+\r
+ //\r
+ // Get CPU frequency\r
+ //\r
+ Status = gBS->LocateProtocol (\r
+ &gEfiCpuArchProtocolGuid,\r
+ NULL,\r
+ (VOID **)&Cpu\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePages (mAcpiLowMemoryBase, 4);\r
+ return ;\r
+ }\r
+ //\r
+ // Get Cpu Frequency\r
+ //\r
+ Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);\r
+ if (EFI_ERROR (Status)) {\r
+ gBS->FreePages (mAcpiLowMemoryBase, 4);\r
+ return ;\r
+ }\r
+\r
+ Freq = DivU64x32 (1000000000000UL, (UINTN) TimerPeriod);\r
+\r
+ mPerfHeader.CpuFreq = Freq;\r
+\r
+ //\r
+ // Record BDS raw performance data\r
+ //\r
+ mPerfHeader.BDSRaw = Ticker;\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 (mAcpiLowMemoryBase, 4);\r
+ return ;\r
+ }\r
+ //\r
+ // Get DXE drivers performance\r
+ //\r
+ for (mIndex = 0; mIndex < NoHandles; mIndex++) {\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[mIndex]) && (StartTicker < EndTicker)) {\r
+ Ticker += (EndTicker - StartTicker);\r
+ }\r
+ }\r
+\r
+ Duration = (UINT32) DivU64x32 (\r
+ Ticker,\r
+ (UINT32) Freq\r
+ );\r
+\r
+ if (Duration > 0) {\r
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
+\r
+ GetNameFromHandle (Handles[mIndex], 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
+ gBS->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) && (StartTicker <= EndTicker)) {\r
+\r
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
+\r
+ AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);\r
+ mPerfData.Duration = (UINT32) DivU64x32 (\r
+ EndTicker - StartTicker,\r
+ (UINT32) Freq\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
+ ClearDebugRegisters ();\r
+\r
+ mPerfHeader.Signiture = 0x66726550;\r
+\r
+ //\r
+ // Put performance data to memory\r
+ //\r
+ CopyMem (\r
+ (UINT32 *) (UINT32) mAcpiLowMemoryBase,\r
+ &mPerfHeader,\r
+ sizeof (PERF_HEADER)\r
+ );\r
+\r
+ gRT->SetVariable (\r
+ L"PerfDataMemAddr",\r
+ &gEfiGlobalVariableGuid,\r
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+ sizeof (UINT32),\r
+ (VOID *) &mAcpiLowMemoryBase\r
+ );\r
+\r
+ return ;\r
+}\r