mirror of https://github.com/acidanthera/audk.git
427 lines
11 KiB
C
427 lines
11 KiB
C
|
/*++
|
||
|
|
||
|
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 ;
|
||
|
}
|