summaryrefslogtreecommitdiff
path: root/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c
diff options
context:
space:
mode:
Diffstat (limited to 'EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c')
-rw-r--r--EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c426
1 files changed, 426 insertions, 0 deletions
diff --git a/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c
new file mode 100644
index 0000000000..320d6b7c44
--- /dev/null
+++ b/EdkNt32Pkg/Library/EdkGenericBdsLib/Performance.c
@@ -0,0 +1,426 @@
+/*++
+
+Copyright (c) 2006, 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.
+
+Module Name:
+
+ Performance.c
+
+Abstract:
+
+ 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.
+
+--*/
+
+#include "Performance.h"
+
+VOID
+ClearDebugRegisters (
+ VOID
+ )
+{
+ AsmWriteDr0 (0);
+ AsmWriteDr1 (0);
+}
+
+STATIC
+VOID
+GetShortPdbFileName (
+ CHAR8 *PdbFileName,
+ CHAR8 *GaugeString
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Returns:
+
+--*/
+{
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ if (PdbFileName == NULL) {
+ AsciiStrCpy (GaugeString, " ");
+ } 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 == PERF_TOKEN_LENGTH - 1) {
+ break;
+ }
+ }
+
+ GaugeString[Index1] = 0;
+ }
+
+ return ;
+}
+
+STATIC
+CHAR8 *
+GetPdbPath (
+ VOID *ImageBase
+ )
+/*++
+
+Routine Description:
+
+ Located PDB path name in PE image
+
+Arguments:
+
+ ImageBase - base of PE to search
+
+Returns:
+
+ Pointer into image at offset of PDB file name if PDB file name is found,
+ Otherwise a pointer to an empty string.
+
+--*/
+{
+ CHAR8 *PdbPath;
+ UINT32 DirCount;
+ EFI_IMAGE_DOS_HEADER *DosHdr;
+ EFI_IMAGE_NT_HEADERS *NtHdr;
+ EFI_IMAGE_OPTIONAL_HEADER *OptionalHdr;
+ EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
+ EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
+ VOID *CodeViewEntryPointer;
+
+ CodeViewEntryPointer = NULL;
+ PdbPath = NULL;
+ DosHdr = ImageBase;
+
+ if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
+ NtHdr = (EFI_IMAGE_NT_HEADERS *) ((UINT8 *) DosHdr + DosHdr->e_lfanew);
+ OptionalHdr = (VOID *) &NtHdr->OptionalHeader;
+ DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionalHdr->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
+ if (DirectoryEntry->VirtualAddress != 0) {
+ for (DirCount = 0;
+ (DirCount < DirectoryEntry->Size / sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) && CodeViewEntryPointer == NULL;
+ DirCount++
+ ) {
+ DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (DirectoryEntry->VirtualAddress + (UINTN) ImageBase + DirCount * sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY));
+ if (DebugEntry->Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
+ CodeViewEntryPointer = (VOID *) ((UINTN) DebugEntry->RVA + (UINTN) ImageBase);
+ switch (*(UINT32 *) CodeViewEntryPointer) {
+ case CODEVIEW_SIGNATURE_NB10:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
+ break;
+
+ case CODEVIEW_SIGNATURE_RSDS:
+ PdbPath = (CHAR8 *) CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ return PdbPath;
+}
+
+STATIC
+VOID
+GetNameFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *GaugeString
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *Image;
+ CHAR8 *PdbFileName;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ AsciiStrCpy (GaugeString, " ");
+
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ &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,
+ &Image
+ );
+ }
+
+ PdbFileName = GetPdbPath (Image->ImageBase);
+
+ if (PdbFileName != NULL) {
+ GetShortPdbFileName (PdbFileName, GaugeString);
+ }
+
+ return ;
+}
+
+
+
+VOID
+WriteBootToOsPerformanceData (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Allocates a block of memory and writes performance data of booting to OS into it.
+
+Arguments:
+
+ None
+
+Returns:
+
+ None
+
+--*/
+{
+ EFI_STATUS Status;
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+ EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase;
+ UINT32 mAcpiLowMemoryLength;
+ UINT32 LimitCount;
+ PERF_HEADER mPerfHeader;
+ PERF_DATA mPerfData;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ CHAR8 GaugeString[PERF_TOKEN_LENGTH];
+ UINT8 *Ptr;
+ UINT32 mIndex;
+ UINT64 Ticker;
+ UINT64 Freq;
+ UINT32 Duration;
+ UINT64 CurrentTicker;
+ UINT64 TimerPeriod;
+ UINTN LogEntryKey;
+ CONST VOID *Handle;
+ CONST CHAR8 *Token;
+ CONST CHAR8 *Module;
+ UINT64 StartTicker;
+ UINT64 EndTicker;
+
+ //
+ // Retrive time stamp count as early as possilbe
+ //
+ Ticker = AsmReadTsc ();
+
+ //
+ // Allocate a block of memory that contain performance data to OS
+ //
+ Status = gBS->AllocatePages (
+ AllocateAnyPages,
+ EfiACPIReclaimMemory,
+ 4,
+ &mAcpiLowMemoryBase
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ mAcpiLowMemoryLength = 0x1000;
+
+ Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
+ LimitCount = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
+
+ //
+ // Initialize performance data structure
+ //
+ ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));
+
+ //
+ // Get CPU frequency
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiCpuArchProtocolGuid,
+ NULL,
+ &Cpu
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (mAcpiLowMemoryBase, 1);
+ return ;
+ }
+ //
+ // Get Cpu Frequency
+ //
+ Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (mAcpiLowMemoryBase, 1);
+ return ;
+ }
+
+ Freq = DivU64x32 (1000000000000, (UINTN) TimerPeriod);
+
+ mPerfHeader.CpuFreq = Freq;
+
+ //
+ // Record BDS raw performance data
+ //
+ mPerfHeader.BDSRaw = Ticker;
+
+ //
+ // Put Detailed performance data into memory
+ //
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (mAcpiLowMemoryBase, 1);
+ return ;
+ }
+ //
+ // Get DXE drivers performance
+ //
+ for (mIndex = 0; mIndex < NoHandles; mIndex++) {
+ Ticker = 0;
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {
+ Ticker += (EndTicker - StartTicker);
+ }
+ }
+
+ Duration = (UINT32) DivU64x32 (
+ Ticker,
+ (UINT32) Freq
+ );
+
+ if (Duration > 0) {
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));
+
+ GetNameFromHandle (Handles[mIndex], 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;
+ }
+ }
+ }
+
+ gBS->FreePool (Handles);
+
+ //
+ // Get inserted performance data
+ //
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if ((Handle == NULL) && (StartTicker <= EndTicker)) {
+
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));
+
+ AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);
+ mPerfData.Duration = (UINT32) DivU64x32 (
+ EndTicker - StartTicker,
+ (UINT32) Freq
+ );
+
+ CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+ Ptr += sizeof (PERF_DATA);
+
+ mPerfHeader.Count++;
+ if (mPerfHeader.Count == LimitCount) {
+ goto Done;
+ }
+ }
+ }
+
+Done:
+
+ ClearDebugRegisters ();
+
+ mPerfHeader.Signiture = 0x66726550;
+
+ //
+ // Put performance data to memory
+ //
+ CopyMem (
+ (UINT32 *) (UINT32) mAcpiLowMemoryBase,
+ &mPerfHeader,
+ sizeof (PERF_HEADER)
+ );
+
+ gRT->SetVariable (
+ L"PerfDataMemAddr",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT32),
+ (VOID *) &mAcpiLowMemoryBase
+ );
+
+ return ;
+}