| /** @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; | |
| } |