/** @file | |
Shell command for Displaying Performance Metrics. | |
The Dp command reads performance data and presents it in several | |
different formats depending upon the needs of the user. Both | |
Trace and Measured Profiling information is processed and presented. | |
Dp uses the "PerformanceLib" to read the measurement records. | |
The "TimerLib" provides information about the timer, such as frequency, | |
beginning, and ending counter values. | |
Measurement records contain identifying information (Handle, Token, Module) | |
and start and end time values. | |
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 - 2018, Intel Corporation. All rights reserved. | |
(C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#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_HII_HANDLE mDpHiiHandle; | |
typedef struct { | |
EFI_HANDLE Handle; | |
EFI_GUID ModuleGuid; | |
} HANDLE_GUID_MAP; | |
HANDLE_GUID_MAP *mCacheHandleGuidTable; | |
UINTN mCachePairCount = 0; | |
// | |
/// Module-Global Variables | |
///@{ | |
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; | |
UINT64 mResetEnd = 0; | |
PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO. | |
MEASUREMENT_RECORD *mMeasurementList = NULL; | |
UINTN mMeasurementNum = 0; | |
/// Items for which to gather cumulative statistics. | |
PERF_CUM_DATA CumData[] = { | |
PERF_INIT_CUM_DATA (LOAD_IMAGE_TOK), | |
PERF_INIT_CUM_DATA (START_IMAGE_TOK), | |
PERF_INIT_CUM_DATA (DRIVERBINDING_START_TOK), | |
PERF_INIT_CUM_DATA (DRIVERBINDING_SUPPORT_TOK), | |
PERF_INIT_CUM_DATA (DRIVERBINDING_STOP_TOK) | |
}; | |
/// Number of items for which we are gathering cumulative statistics. | |
UINT32 const NumCum = sizeof (CumData) / sizeof (PERF_CUM_DATA); | |
STATIC CONST SHELL_PARAM_ITEM ParamList[] = { | |
{ L"-v", TypeFlag }, // -v Verbose Mode | |
{ L"-A", TypeFlag }, // -A All, Cooked | |
{ L"-R", TypeFlag }, // -R RAW All | |
{ L"-s", TypeFlag }, // -s Summary | |
{ L"-x", TypeFlag }, // -x eXclude Cumulative Items | |
{ L"-i", TypeFlag }, // -i Display Identifier | |
{ L"-c", TypeValue }, // -c Display cumulative data. | |
{ L"-n", TypeValue }, // -n # Number of records to display for A and R | |
{ L"-t", TypeValue }, // -t # Threshold of interest | |
{ NULL, TypeMax } | |
}; | |
///@} | |
/** | |
Display the trailing Verbose information. | |
**/ | |
VOID | |
DumpStatistics ( | |
void | |
) | |
{ | |
EFI_STRING StringPtr; | |
EFI_STRING StringPtrUnknown; | |
StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_STATISTICS), NULL); | |
StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); | |
ShellPrintHiiEx ( | |
-1, | |
-1, | |
NULL, | |
STRING_TOKEN (STR_DP_SECTION_HEADER), | |
mDpHiiHandle, | |
(StringPtr == NULL) ? StringPtrUnknown : StringPtr | |
); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMTRACE), mDpHiiHandle, SummaryData.NumTrace); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMINCOMPLETE), mDpHiiHandle, SummaryData.NumIncomplete); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPHASES), mDpHiiHandle, SummaryData.NumSummary); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMHANDLES), mDpHiiHandle, SummaryData.NumHandles, SummaryData.NumTrace - SummaryData.NumHandles); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPEIMS), mDpHiiHandle, SummaryData.NumPEIMs); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMGLOBALS), mDpHiiHandle, SummaryData.NumGlobal); | |
SHELL_FREE_NON_NULL (StringPtr); | |
SHELL_FREE_NON_NULL (StringPtrUnknown); | |
} | |
/** | |
Get Boot performance table form Acpi table. | |
**/ | |
EFI_STATUS | |
GetBootPerformanceTable ( | |
) | |
{ | |
FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable; | |
FirmwarePerformanceTable = (FIRMWARE_PERFORMANCE_TABLE *)EfiLocateFirstAcpiTable ( | |
EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE | |
); | |
if (FirmwarePerformanceTable == NULL) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_FPDT_FAIL), mDpHiiHandle); | |
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 from the cached 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 EFI_SUCCESS; | |
} | |
/** | |
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 ((Measurement->Token != NULL) && (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0)) { | |
Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); | |
} else { | |
GetHandleFormModuleGuid (ModuleGuid, &StartHandle); | |
Measurement->Handle = StartHandle; | |
// | |
// When no perf entry to record the PEI and DXE phase, | |
// For start image, we need detect the PEIM and non PEIM here. | |
// | |
if (Measurement->Token == NULL) { | |
if ((StartHandle == NULL) && !IsZeroGuid (ModuleGuid)) { | |
Measurement->Token = ALit_PEIM; | |
Measurement->Module = ALit_PEIM; | |
Measurement->Handle = ModuleGuid; | |
} else { | |
Measurement->Token = ALit_START_IMAGE; | |
Measurement->Module = ALit_START_IMAGE; | |
} | |
} | |
} | |
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 ((Measurement->Token != NULL) && (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0)) { | |
Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid); | |
} else { | |
GetHandleFormModuleGuid (ModuleGuid, &StartHandle); | |
Measurement->Handle = StartHandle; | |
// | |
// When no perf entry to record the PEI and DXE phase, | |
// For start image, we need detect the PEIM and non PEIM here. | |
// | |
if ((Measurement->Token == NULL) && ((Measurement->Identifier == MODULE_START_ID) || (Measurement->Identifier == MODULE_END_ID))) { | |
if ((StartHandle == NULL) && !IsZeroGuid (ModuleGuid)) { | |
Measurement->Token = ALit_PEIM; | |
Measurement->Handle = ModuleGuid; | |
} else { | |
Measurement->Token = ALit_START_IMAGE; | |
} | |
} | |
} | |
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; | |
case FPDT_DUAL_GUID_STRING_EVENT_TYPE: | |
ModuleGuid = &(((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Guid1); | |
Measurement->Identifier = ((UINT32)((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->ProgressID); | |
if (IsStart) { | |
Measurement->StartTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; | |
} else { | |
Measurement->EndTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp; | |
} | |
Measurement->Token = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String; | |
Measurement->Module = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String; | |
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 (EndMeasureMent->Identifier == PERF_CROSSMODULE_END_ID) { | |
if ((mMeasurementList[Index].EndTimeStamp == 0) && | |
(AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) && | |
(AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0) && | |
(mMeasurementList[Index].Identifier == PERF_CROSSMODULE_START_ID)) | |
{ | |
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; | |
UINT8 *BasicBootTablePtr; | |
UINT64 ResetEnd; | |
UINT16 StartProgressId; | |
UINTN TableLength; | |
UINT8 *StartRecordEvent; | |
MEASUREMENT_RECORD MeasureMent; | |
mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize); | |
if (mMeasurementList == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Update the ResetEnd which was logged at the beginning of firmware image execution | |
// | |
TableLength = sizeof (EFI_ACPI_5_0_FPDT_PERFORMANCE_TABLE_HEADER); | |
BasicBootTablePtr = (mBootPerformanceTable + TableLength); | |
ResetEnd = ((EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD *)BasicBootTablePtr)->ResetEnd; | |
if (ResetEnd > 0) { | |
mResetEnd = ResetEnd; | |
} | |
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 with ProgressId 0, the record doesn't appear in pairs. The timestamp in the record is the EndTimeStamp, its StartTimeStamp is 0. | |
// 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 == 0) { | |
GetMeasurementInfo (RecordHeader, FALSE, &(mMeasurementList[mMeasurementNum])); | |
mMeasurementNum++; | |
} else 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 (StartProgressId == PERF_CROSSMODULE_START_ID ) { | |
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 { | |
ZeroMem (&MeasureMent, sizeof (MEASUREMENT_RECORD)); | |
GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent); | |
SearchMeasurement (&MeasureMent); | |
} | |
TableLength += RecordHeader->Length; | |
PerformanceTablePtr += RecordHeader->Length; | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
Initialize the cumulative data. | |
**/ | |
VOID | |
InitCumulativeData ( | |
VOID | |
) | |
{ | |
UINTN Index; | |
for (Index = 0; Index < NumCum; ++Index) { | |
CumData[Index].Count = 0; | |
CumData[Index].MinDur = PERF_MAXDUR; | |
CumData[Index].MaxDur = 0; | |
CumData[Index].Duration = 0; | |
} | |
} | |
/** | |
Initialize the Summary data. | |
**/ | |
VOID | |
InitSummaryData ( | |
VOID | |
) | |
{ | |
SummaryData.NumTrace = 0; | |
SummaryData.NumIncomplete = 0; | |
SummaryData.NumSummary = 0; | |
SummaryData.NumHandles = 0; | |
SummaryData.NumPEIMs = 0; | |
SummaryData.NumGlobal = 0; | |
} | |
/** | |
Dump performance data. | |
@param[in] ImageHandle The image handle. | |
@param[in] SystemTable The system table. | |
@retval SHELL_SUCCESS Command completed successfully. | |
@retval SHELL_INVALID_PARAMETER Command usage error. | |
@retval SHELL_ABORTED The user aborts the operation. | |
@retval value Unknown error. | |
**/ | |
SHELL_STATUS | |
RunDp ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
LIST_ENTRY *ParamPackage; | |
CONST CHAR16 *CmdLineArg; | |
EFI_STATUS Status; | |
PERFORMANCE_PROPERTY *PerformanceProperty; | |
UINTN Number2Display; | |
EFI_STRING StringPtr; | |
BOOLEAN SummaryMode; | |
BOOLEAN VerboseMode; | |
BOOLEAN AllMode; | |
BOOLEAN RawMode; | |
BOOLEAN ExcludeMode; | |
BOOLEAN CumulativeMode; | |
CONST CHAR16 *CustomCumulativeToken; | |
PERF_CUM_DATA *CustomCumulativeData; | |
UINTN NameSize; | |
SHELL_STATUS ShellStatus; | |
TIMER_INFO TimerInfo; | |
UINT64 Intermediate; | |
StringPtr = NULL; | |
SummaryMode = FALSE; | |
VerboseMode = FALSE; | |
AllMode = FALSE; | |
RawMode = FALSE; | |
ExcludeMode = FALSE; | |
CumulativeMode = FALSE; | |
CustomCumulativeData = NULL; | |
ShellStatus = SHELL_SUCCESS; | |
// | |
// initialize the shell lib (we must be in non-auto-init...) | |
// | |
Status = ShellInitialize (); | |
ASSERT_EFI_ERROR (Status); | |
// | |
// Process Command Line arguments | |
// | |
Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_ARG), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} else if (ShellCommandLineGetCount (ParamPackage) > 1) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_MANY), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} | |
// | |
// Boolean options | |
// | |
VerboseMode = ShellCommandLineGetFlag (ParamPackage, L"-v"); | |
SummaryMode = (BOOLEAN)(ShellCommandLineGetFlag (ParamPackage, L"-S") || ShellCommandLineGetFlag (ParamPackage, L"-s")); | |
AllMode = ShellCommandLineGetFlag (ParamPackage, L"-A"); | |
RawMode = ShellCommandLineGetFlag (ParamPackage, L"-R"); | |
ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x"); | |
mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i"); | |
CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c"); | |
if (AllMode && RawMode) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CONFLICT_ARG), mDpHiiHandle, L"-A", L"-R"); | |
return SHELL_INVALID_PARAMETER; | |
} | |
// Options with Values | |
if (ShellCommandLineGetFlag (ParamPackage, L"-n")) { | |
CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n"); | |
if (CmdLineArg == NULL) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} else { | |
if (!(RawMode || AllMode)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_NO_RAW_ALL), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} | |
Status = ShellConvertStringToUint64 (CmdLineArg, &Intermediate, FALSE, TRUE); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-n"); | |
return SHELL_INVALID_PARAMETER; | |
} else { | |
Number2Display = (UINTN)Intermediate; | |
if ((Number2Display == 0) || (Number2Display > MAXIMUM_DISPLAYCOUNT)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_RANGE), mDpHiiHandle, L"-n", 0, MAXIMUM_DISPLAYCOUNT); | |
return SHELL_INVALID_PARAMETER; | |
} | |
} | |
} | |
} else { | |
Number2Display = DEFAULT_DISPLAYCOUNT; | |
} | |
if (ShellCommandLineGetFlag (ParamPackage, L"-t")) { | |
CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-t"); | |
if (CmdLineArg == NULL) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} else { | |
Status = ShellConvertStringToUint64 (CmdLineArg, &Intermediate, FALSE, TRUE); | |
if (EFI_ERROR (Status)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-t"); | |
return SHELL_INVALID_PARAMETER; | |
} else { | |
mInterestThreshold = Intermediate; | |
} | |
} | |
} else { | |
mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us | |
} | |
if (ShellCommandLineGetFlag (ParamPackage, L"-c")) { | |
CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c"); | |
if (CustomCumulativeToken == NULL) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle); | |
return SHELL_INVALID_PARAMETER; | |
} else { | |
CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA)); | |
if (CustomCumulativeData == NULL) { | |
ShellStatus = SHELL_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
CustomCumulativeData->MinDur = PERF_MAXDUR; | |
CustomCumulativeData->MaxDur = 0; | |
CustomCumulativeData->Count = 0; | |
CustomCumulativeData->Duration = 0; | |
NameSize = StrLen (CustomCumulativeToken) + 1; | |
CustomCumulativeData->Name = AllocateZeroPool (NameSize); | |
if (CustomCumulativeData->Name == NULL) { | |
ShellStatus = SHELL_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
UnicodeStrToAsciiStrS (CustomCumulativeToken, CustomCumulativeData->Name, NameSize); | |
} | |
} | |
// | |
// 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)) { | |
ShellStatus = Status; | |
goto Done; | |
} | |
// | |
// 2. Cache the ModuleGuid and hanlde mapping table. | |
// | |
Status = BuildCachedGuidHandleTable (); | |
if (EFI_ERROR (Status)) { | |
ShellStatus = Status; | |
goto Done; | |
} | |
// | |
// 3. Build the measurement array form the FPDT records. | |
// | |
Status = BuildMeasurementList (); | |
if (EFI_ERROR (Status)) { | |
ShellStatus = SHELL_OUT_OF_RESOURCES; | |
goto Done; | |
} | |
// | |
// Initialize the pre-defined cumulative data. | |
// | |
InitCumulativeData (); | |
// | |
// Initialize the Summary data. | |
// | |
InitSummaryData (); | |
// | |
// Timer specific processing | |
// | |
// Get the Performance counter characteristics: | |
// Freq = Frequency in Hz | |
// StartCount = Value loaded into the counter when it starts counting | |
// EndCount = Value counter counts to before it needs to be reset | |
// | |
Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **)&PerformanceProperty); | |
if (EFI_ERROR (Status) || (PerformanceProperty == NULL)) { | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PERF_PROPERTY_NOT_FOUND), mDpHiiHandle); | |
goto Done; | |
} | |
TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000); | |
TimerInfo.StartCount = 0; | |
TimerInfo.EndCount = 0xFFFF; | |
TimerInfo.CountUp = TRUE; | |
// | |
// Print header | |
// | |
// print DP's build version | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_BUILD_REVISION), mDpHiiHandle, DP_MAJOR_VERSION, DP_MINOR_VERSION); | |
// print performance timer characteristics | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_KHZ), mDpHiiHandle, TimerInfo.Frequency); | |
if (VerboseMode && !RawMode) { | |
StringPtr = HiiGetString ( | |
mDpHiiHandle, | |
(EFI_STRING_ID)(TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)), | |
NULL | |
); | |
ASSERT (StringPtr != NULL); | |
// Print Timer count range and direction | |
ShellPrintHiiEx ( | |
-1, | |
-1, | |
NULL, | |
STRING_TOKEN (STR_DP_TIMER_PROPERTIES), | |
mDpHiiHandle, | |
StringPtr, | |
TimerInfo.StartCount, | |
TimerInfo.EndCount | |
); | |
ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mDpHiiHandle, mInterestThreshold); | |
} | |
/**************************************************************************** | |
**** Print Sections based on command line options | |
**** | |
**** Option modes have the following priority: | |
**** v Verbose -- Valid in combination with any other options | |
**** t Threshold -- Modifies All, Raw, and Cooked output | |
**** Default is 0 for All and Raw mode | |
**** Default is DEFAULT_THRESHOLD for "Cooked" mode | |
**** n Number2Display Used by All and Raw mode. Otherwise ignored. | |
**** A All -- R and S options are ignored | |
**** R Raw -- S option is ignored | |
**** s Summary -- Modifies "Cooked" output only | |
**** Cooked (Default) | |
****************************************************************************/ | |
GatherStatistics (CustomCumulativeData); | |
if (CumulativeMode) { | |
ProcessCumulative (CustomCumulativeData); | |
} else if (AllMode) { | |
Status = DumpAllTrace (Number2Display, ExcludeMode); | |
if (Status == EFI_ABORTED) { | |
ShellStatus = SHELL_ABORTED; | |
goto Done; | |
} | |
} else if (RawMode) { | |
Status = DumpRawTrace (Number2Display, ExcludeMode); | |
if (Status == EFI_ABORTED) { | |
ShellStatus = SHELL_ABORTED; | |
goto Done; | |
} | |
} else { | |
// ------------- Begin Cooked Mode Processing | |
ProcessPhases (); | |
if ( !SummaryMode) { | |
Status = ProcessHandles (ExcludeMode); | |
if (Status == EFI_ABORTED) { | |
ShellStatus = SHELL_ABORTED; | |
goto Done; | |
} | |
Status = ProcessPeims (); | |
if (Status == EFI_ABORTED) { | |
ShellStatus = SHELL_ABORTED; | |
goto Done; | |
} | |
Status = ProcessGlobal (); | |
if (Status == EFI_ABORTED) { | |
ShellStatus = SHELL_ABORTED; | |
goto Done; | |
} | |
ProcessCumulative (NULL); | |
} | |
} // ------------- End of Cooked Mode Processing | |
if ( VerboseMode || SummaryMode) { | |
DumpStatistics (); | |
} | |
Done: | |
if (ParamPackage != NULL) { | |
ShellCommandLineFreeVarList (ParamPackage); | |
} | |
SHELL_FREE_NON_NULL (StringPtr); | |
if (CustomCumulativeData != NULL) { | |
SHELL_FREE_NON_NULL (CustomCumulativeData->Name); | |
} | |
SHELL_FREE_NON_NULL (CustomCumulativeData); | |
SHELL_FREE_NON_NULL (mMeasurementList); | |
SHELL_FREE_NON_NULL (mCacheHandleGuidTable); | |
mMeasurementNum = 0; | |
mCachePairCount = 0; | |
return ShellStatus; | |
} | |
/** | |
Retrieve HII package list from ImageHandle and publish to HII database. | |
@param ImageHandle The image handle of the process. | |
@return HII handle. | |
**/ | |
EFI_HII_HANDLE | |
InitializeHiiPackage ( | |
EFI_HANDLE ImageHandle | |
) | |
{ | |
EFI_STATUS Status; | |
EFI_HII_PACKAGE_LIST_HEADER *PackageList; | |
EFI_HII_HANDLE HiiHandle; | |
// | |
// Retrieve HII package list from ImageHandle | |
// | |
Status = gBS->OpenProtocol ( | |
ImageHandle, | |
&gEfiHiiPackageListProtocolGuid, | |
(VOID **)&PackageList, | |
ImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_GET_PROTOCOL | |
); | |
ASSERT_EFI_ERROR (Status); | |
if (EFI_ERROR (Status)) { | |
return NULL; | |
} | |
// | |
// Publish HII package list to HII Database. | |
// | |
Status = gHiiDatabase->NewPackageList ( | |
gHiiDatabase, | |
PackageList, | |
NULL, | |
&HiiHandle | |
); | |
ASSERT_EFI_ERROR (Status); | |
if (EFI_ERROR (Status)) { | |
return NULL; | |
} | |
return HiiHandle; | |
} |