ShellPkg/Dp: Updated to dump perf log based on FPDT table

Cc: Liming Gao <liming.gao@intel.com>
Cc: Star Zeng <star.zeng@intel.com>
Cc: Ruiyu Ni <ruiyu.ni@intel.com>
Cc: Jaben Carsey <jaben.carsey@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Dandan Bi <dandan.bi@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
This commit is contained in:
Dandan Bi
2018-01-22 16:39:03 +08:00
committed by Liming Gao
parent 718a937ed9
commit 115eae650b
11 changed files with 724 additions and 127 deletions

View File

@ -13,7 +13,7 @@
Dp uses this information to group records in different ways. It also uses
timer information to calculate elapsed time for each measurement.
Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.
Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
This program and the accompanying materials
are licensed and made available under the terms and conditions of the BSD License
@ -24,13 +24,34 @@
WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
**/
#include "PerformanceTokens.h"
#include "Dp.h"
#include "Literals.h"
#include "DpInternal.h"
#pragma pack(1)
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT32 Entry;
} RSDT_TABLE;
typedef struct {
EFI_ACPI_DESCRIPTION_HEADER Header;
UINT64 Entry;
} XSDT_TABLE;
#pragma pack()
EFI_HANDLE mDpHiiHandle;
typedef struct {
EFI_HANDLE Handle;
EFI_GUID ModuleGuid;
} HANDLE_GUID_MAP;
HANDLE_GUID_MAP *mCacheHandleGuidTable;
UINTN mCachePairCount = 0;
//
/// Module-Global Variables
///@{
@ -38,11 +59,14 @@ CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1];
CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE];
UINT64 mInterestThreshold;
BOOLEAN mShowId = FALSE;
UINT8 *mBootPerformanceTable;
UINTN mBootPerformanceTableSize;
BOOLEAN mPeiPhase = FALSE;
BOOLEAN mDxePhase = FALSE;
PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO.
/// Timer Specific Information.
TIMER_INFO TimerInfo;
MEASUREMENT_RECORD *mMeasurementList = NULL;
UINTN mMeasurementNum = 0;
/// Items for which to gather cumulative statistics.
PERF_CUM_DATA CumData[] = {
@ -99,6 +123,536 @@ DumpStatistics( void )
SHELL_FREE_NON_NULL (StringPtrUnknown);
}
/**
This function scan ACPI table in RSDT.
@param Rsdt ACPI RSDT
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
ScanTableInRSDT (
IN RSDT_TABLE *Rsdt,
IN UINT32 Signature
)
{
UINTN Index;
UINT32 EntryCount;
UINT32 *EntryPtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
EntryCount = (Rsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
EntryPtr = &Rsdt->Entry;
for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(*EntryPtr));
if (Table->Signature == Signature) {
return Table;
}
}
return NULL;
}
/**
This function scan ACPI table in XSDT.
@param Xsdt ACPI XSDT
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
ScanTableInXSDT (
IN XSDT_TABLE *Xsdt,
IN UINT32 Signature
)
{
UINTN Index;
UINT32 EntryCount;
UINT64 EntryPtr;
UINTN BasePtr;
EFI_ACPI_DESCRIPTION_HEADER *Table;
EntryCount = (Xsdt->Header.Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
BasePtr = (UINTN)(&(Xsdt->Entry));
for (Index = 0; Index < EntryCount; Index ++) {
CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
Table = (EFI_ACPI_DESCRIPTION_HEADER*)((UINTN)(EntryPtr));
if (Table->Signature == Signature) {
return Table;
}
}
return NULL;
}
/**
This function scan ACPI table in RSDP.
@param Rsdp ACPI RSDP
@param Signature ACPI table signature
@return ACPI table
**/
VOID *
FindAcpiPtr (
IN EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp,
IN UINT32 Signature
)
{
EFI_ACPI_DESCRIPTION_HEADER *AcpiTable;
RSDT_TABLE *Rsdt;
XSDT_TABLE *Xsdt;
AcpiTable = NULL;
//
// Check ACPI2.0 table
//
Rsdt = (RSDT_TABLE *)(UINTN)Rsdp->RsdtAddress;
Xsdt = NULL;
if ((Rsdp->Revision >= 2) && (Rsdp->XsdtAddress < (UINT64)(UINTN)-1)) {
Xsdt = (XSDT_TABLE *)(UINTN)Rsdp->XsdtAddress;
}
//
// Check Xsdt
//
if (Xsdt != NULL) {
AcpiTable = ScanTableInXSDT (Xsdt, Signature);
}
//
// Check Rsdt
//
if ((AcpiTable == NULL) && (Rsdt != NULL)) {
AcpiTable = ScanTableInRSDT (Rsdt, Signature);
}
return AcpiTable;
}
/**
Get Boot performance table form Acpi table.
**/
EFI_STATUS
GetBootPerformanceTable (
)
{
EFI_STATUS Status;
VOID *AcpiTable;
FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable;
AcpiTable = NULL;
Status = EfiGetSystemConfigurationTable (
&gEfiAcpi20TableGuid,
&AcpiTable
);
if (EFI_ERROR (Status)) {
Status = EfiGetSystemConfigurationTable (
&gEfiAcpi10TableGuid,
&AcpiTable
);
}
if (EFI_ERROR(Status)) {
return Status;
}
FirmwarePerformanceTable = FindAcpiPtr (
(EFI_ACPI_5_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)AcpiTable,
EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
);
if (FirmwarePerformanceTable == NULL) {
return EFI_NOT_FOUND;
}
mBootPerformanceTable = (UINT8*) (UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer;
mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *) mBootPerformanceTable)->Header.Length;
return EFI_SUCCESS;
}
/**
Get Handle form Module Guid.
@param ModuleGuid Module Guid.
@param Handle The handle to be returned.
**/
VOID
GetHandleFormModuleGuid (
IN EFI_GUID *ModuleGuid,
IN OUT EFI_HANDLE *Handle
)
{
UINTN Index;
if (IsZeroGuid (ModuleGuid)) {
*Handle = NULL;
}
//
// Try to get the Handle form the caached array.
//
for (Index = 0; Index < mCachePairCount; Index++) {
if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) {
*Handle = mCacheHandleGuidTable[Index].Handle;
break;
}
}
if (Index >= mCachePairCount) {
*Handle = NULL;
}
}
/**
Cache the GUID and handle mapping pairs. In order to save time for searching.
**/
EFI_STATUS
BuildCachedGuidHandleTable (
VOID
)
{
EFI_STATUS Status;
EFI_HANDLE *HandleBuffer;
UINTN HandleCount;
UINTN Index;
EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
EFI_GUID *TempGuid;
MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
if (EFI_ERROR (Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);
return Status;
}
mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP));
if (mCacheHandleGuidTable == NULL) {
return EFI_OUT_OF_RESOURCES;
}
for (Index = 0; Index < HandleCount; Index++) {
//
// Try Handle as ImageHandle.
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiLoadedImageProtocolGuid,
(VOID**) &LoadedImage
);
if (EFI_ERROR (Status)) {
//
// Try Handle as Controller Handle
//
Status = gBS->OpenProtocol (
HandleBuffer[Index],
&gEfiDriverBindingProtocolGuid,
(VOID **) &DriverBinding,
NULL,
NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
if (!EFI_ERROR (Status)) {
//
// Get Image protocol from ImageHandle
//
Status = gBS->HandleProtocol (
DriverBinding->ImageHandle,
&gEfiLoadedImageProtocolGuid,
(VOID**) &LoadedImage
);
}
}
if (!EFI_ERROR (Status) && LoadedImage != NULL) {
//
// Get Module Guid from DevicePath.
//
if (LoadedImage->FilePath != NULL &&
LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH &&
LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP
) {
FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
TempGuid = &FvFilePath->FvFileName;
mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index];
CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid);
mCachePairCount ++;
}
}
}
if (HandleBuffer != NULL) {
FreePool (HandleBuffer);
HandleBuffer = NULL;
}
return Status;
}
/**
Get Measurement form Fpdt records.
@param RecordHeader Pointer to the start record.
@param IsStart Is start record or End record.
@param Measurement Pointer to the measurement which need to be filled.
**/
VOID
GetMeasurementInfo (
IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader,
IN BOOLEAN IsStart,
IN OUT MEASUREMENT_RECORD *Measurement
)
{
VOID *ModuleGuid;
EFI_HANDLE StartHandle;
switch (RecordHeader->Type) {
case FPDT_GUID_EVENT_TYPE:
ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);
Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID);
if (IsStart) {
Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
} else {
Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
}
switch (Measurement->Identifier) {
case MODULE_START_ID:
case MODULE_END_ID:
if (mPeiPhase) {
Measurement->Token = ALit_PEIM;
Measurement->Module = ALit_PEIM;
} else if (mDxePhase) {
Measurement->Token = ALit_START_IMAGE;
Measurement->Module = ALit_START_IMAGE;
}
break;
default:
ASSERT(FALSE);
}
if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
Measurement->Handle = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);
} else {
GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
Measurement->Handle = StartHandle;
}
break;
case FPDT_DYNAMIC_STRING_EVENT_TYPE:
ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
if (IsStart) {
Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
} else {
Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
}
switch (Measurement->Identifier) {
case MODULE_START_ID:
case MODULE_END_ID:
if (mPeiPhase) {
Measurement->Token = ALit_PEIM;
} else if (mDxePhase) {
Measurement->Token = ALit_START_IMAGE;
}
break;
case MODULE_LOADIMAGE_START_ID:
case MODULE_LOADIMAGE_END_ID:
Measurement->Token = ALit_LOAD_IMAGE;
break;
case MODULE_DB_START_ID:
case MODULE_DB_END_ID:
Measurement->Token = ALit_DB_START;
break;
case MODULE_DB_SUPPORT_START_ID:
case MODULE_DB_SUPPORT_END_ID:
Measurement->Token = ALit_DB_SUPPORT;
break;
case MODULE_DB_STOP_START_ID:
case MODULE_DB_STOP_END_ID:
Measurement->Token = ALit_DB_STOP;
break;
default:
Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
break;
}
Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
if (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0) {
Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
} else {
GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
Measurement->Handle = StartHandle;
}
break;
case FPDT_GUID_QWORD_EVENT_TYPE:
ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid);
Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID);
if (IsStart) {
Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
} else {
Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
}
switch (Measurement->Identifier) {
case MODULE_DB_START_ID:
Measurement->Token = ALit_DB_START;
Measurement->Module = ALit_DB_START;
break;
case MODULE_DB_SUPPORT_START_ID:
case MODULE_DB_SUPPORT_END_ID:
Measurement->Token = ALit_DB_SUPPORT;
Measurement->Module = ALit_DB_SUPPORT;
break;
case MODULE_DB_STOP_START_ID:
case MODULE_DB_STOP_END_ID:
Measurement->Token = ALit_DB_STOP;
Measurement->Module = ALit_DB_STOP;
break;
case MODULE_LOADIMAGE_START_ID:
case MODULE_LOADIMAGE_END_ID:
Measurement->Token = ALit_LOAD_IMAGE;
Measurement->Module = ALit_LOAD_IMAGE;
break;
default:
ASSERT(FALSE);
}
GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
Measurement->Handle = StartHandle;
break;
case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid);
Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
if (IsStart) {
Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD*)RecordHeader)->Timestamp;
} else {
Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
}
//
// Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE.
//
switch (Measurement->Identifier) {
case MODULE_DB_END_ID:
Measurement->Token = ALit_DB_START;
Measurement->Module = ALit_DB_START;
break;
default:
ASSERT(FALSE);
}
GetHandleFormModuleGuid(ModuleGuid, &StartHandle);
Measurement->Handle = StartHandle;
break;
default:
break;
}
}
/**
Search the start measurement in the mMeasurementList for the end measurement.
@param EndMeasureMent Measurement for end record.
**/
VOID
SearchMeasurement (
IN MEASUREMENT_RECORD *EndMeasureMent
)
{
INTN Index;
for (Index = mMeasurementNum - 1; Index >= 0; Index--) {
if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) {
if (mMeasurementList[Index].EndTimeStamp == 0 && EndMeasureMent->Handle!= NULL && mMeasurementList[Index].Handle != NULL&&
CompareGuid(mMeasurementList[Index].Handle, EndMeasureMent->Handle) &&
(AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
(AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {
mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
break;
}
} else {
if (mMeasurementList[Index].EndTimeStamp == 0 && mMeasurementList[Index].Handle == EndMeasureMent->Handle &&
(AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
(AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0)) {
mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
break;
}
}
}
}
/**
Generate the measure record array.
**/
EFI_STATUS
BuildMeasurementList (
)
{
EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;
UINT8 *PerformanceTablePtr;
UINT16 StartProgressId;
UINTN TableLength;
UINT8 *StartRecordEvent;
MEASUREMENT_RECORD MeasureMent;
mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize);
if (mMeasurementList == NULL) {
return EFI_OUT_OF_RESOURCES;
}
TableLength = sizeof (BOOT_PERFORMANCE_TABLE);
PerformanceTablePtr = (mBootPerformanceTable + TableLength);
while (TableLength < mBootPerformanceTableSize) {
RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER*) PerformanceTablePtr;
StartRecordEvent = (UINT8 *)RecordHeader;
StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID;
//
// If the record is the start record, fill the info to the measurement in the mMeasurementList.
// If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp.
//
if (((StartProgressId >= PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x000F) == 0)) ||
(StartProgressId < PERF_EVENTSIGNAL_START_ID && ((StartProgressId & 0x0001) != 0)))) {
//
// Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE
// So we need to identify these two kinds of record through different phase.
//
if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) {
mPeiPhase = TRUE;
} else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) {
mDxePhase = TRUE;
mPeiPhase = FALSE;
}
// Get measurement info form the start record to the mMeasurementList.
GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum]));
mMeasurementNum ++;
} else {
GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent);
SearchMeasurement (&MeasureMent);
}
TableLength += RecordHeader->Length;
PerformanceTablePtr += RecordHeader->Length;
}
return EFI_SUCCESS;
}
/**
Initialize the cumulative data.
@ -155,6 +709,7 @@ RunDp (
PERF_CUM_DATA *CustomCumulativeData;
UINTN NameSize;
SHELL_STATUS ShellStatus;
TIMER_INFO TimerInfo;
StringPtr = NULL;
SummaryMode = FALSE;
@ -174,6 +729,36 @@ RunDp (
Status = ShellInitialize();
ASSERT_EFI_ERROR(Status);
//
// DP dump performance data by parsing FPDT table in ACPI table.
// Folloing 3 steps are to get the measurement form the FPDT table.
//
//
//1. Get FPDT from ACPI table.
//
Status = GetBootPerformanceTable ();
if (EFI_ERROR(Status)) {
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_BOOT_PERFORMANCE_TABLE_FAIL), mDpHiiHandle);
return Status;
}
//
//2. Cache the ModuleGuid and hanlde mapping table.
//
Status = BuildCachedGuidHandleTable();
if (EFI_ERROR (Status)) {
return Status;
}
//
//3. Build the measurement array form the FPDT records.
//
Status = BuildMeasurementList ();
if (EFI_ERROR(Status)) {
return Status;
}
//
// Process Command Line arguments
//
@ -267,11 +852,9 @@ RunDp (
}
TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000);
TimerInfo.StartCount = PerformanceProperty->TimerStartValue;
TimerInfo.EndCount = PerformanceProperty->TimerEndValue;
// Determine in which direction the performance counter counts.
TimerInfo.CountUp = (BOOLEAN) (TimerInfo.EndCount >= TimerInfo.StartCount);
TimerInfo.StartCount = 0;
TimerInfo.EndCount = 0xFFFF;
TimerInfo.CountUp = TRUE;
//
// Print header
@ -385,6 +968,12 @@ Done:
}
SHELL_FREE_NON_NULL (CustomCumulativeData);
SHELL_FREE_NON_NULL (mMeasurementList);
SHELL_FREE_NON_NULL (mCacheHandleGuidTable);
mMeasurementNum = 0;
mCachePairCount = 0;
return ShellStatus;
}