public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Ard Biesheuvel <ard.biesheuvel@linaro.org>
To: Dandan Bi <dandan.bi@intel.com>,
	Leif Lindholm <leif.lindholm@linaro.org>
Cc: "edk2-devel@lists.01.org" <edk2-devel@lists.01.org>,
	Star Zeng <star.zeng@intel.com>,
	 Liming Gao <liming.gao@intel.com>,
	Matt Sealey <neko@bakuhatsu.net>
Subject: Re: [PATCH v2 3/8] MdeModulePkg/DxeCorePerformanceLib:Track FPDT record in DXE phase
Date: Tue, 1 May 2018 18:26:55 +0200	[thread overview]
Message-ID: <CAKv+Gu8eUd7S4or41HAiUfb49ROVzJ+xaZG3nq8C_EKktNc=gA@mail.gmail.com> (raw)
In-Reply-To: <1517320437-11688-4-git-send-email-dandan.bi@intel.com>

On 30 January 2018 at 14:53, Dandan Bi <dandan.bi@intel.com> wrote:
> V2:
> Update DxecorePerformanceLib to report the boot performance table
> address instead of records contents.
>
> Updated to convert Pref entry to FPDT record in DXE phase and then
> allocate boot performance table to save the record and report
> the address of boot performance table to FirmwarePerformanceDxe.
>
> Cc: Liming Gao <liming.gao@intel.com>
> Cc: Star Zeng <star.zeng@intel.com>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Dandan Bi <dandan.bi@intel.com>
> ---
>  .../DxeCorePerformanceLib/DxeCorePerformanceLib.c  | 1389 +++++++++++++++-----
>  .../DxeCorePerformanceLib.inf                      |   20 +-
>  .../DxeCorePerformanceLibInternal.h                |   17 +-
>  3 files changed, 1108 insertions(+), 318 deletions(-)
>
> diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
> index 7c0e207..c6f8a16 100644
> --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
> +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
> @@ -8,11 +8,11 @@
>    which are consumed by DxePerformanceLib to logging performance data in DXE phase.
>
>    This library is mainly used by DxeCore to start performance logging to ensure that
>    Performance Protocol is installed at the very beginning of DXE phase.
>
> -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>  (C) Copyright 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
>  which accompanies this distribution.  The full text of the license may be found at
>  http://opensource.org/licenses/bsd-license.php
> @@ -23,27 +23,65 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>  **/
>
>
>  #include "DxeCorePerformanceLibInternal.h"
>
> -
>  //
> -// The data structure to hold global performance data.
> +// Data for FPDT performance records.
>  //
> -GAUGE_DATA_HEADER    *mGaugeData;
> +#define SMM_BOOT_RECORD_COMM_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data) + sizeof(SMM_BOOT_RECORD_COMMUNICATE))
> +#define STRING_SIZE             (EDKII_STRING_EVENT_RECORD_NAME_LENGTH * sizeof (CHAR8))
> +#define MAX_RECORD_SIZE         (sizeof (DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE)
> +#define FIRMWARE_RECORD_BUFFER  0x10000
> +#define CACHE_HANDLE_GUID_COUNT 0x1000
> +
> +BOOT_PERFORMANCE_TABLE          *mAcpiBootPerformanceTable = NULL;
> +BOOT_PERFORMANCE_TABLE          mBootPerformanceTableTemplate = {
> +  {
> +    EFI_ACPI_5_0_FPDT_BOOT_PERFORMANCE_TABLE_SIGNATURE,
> +    sizeof (BOOT_PERFORMANCE_TABLE)
> +  },
> +  {
> +    {
> +      EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_TYPE_FIRMWARE_BASIC_BOOT,    // Type
> +      sizeof (EFI_ACPI_5_0_FPDT_FIRMWARE_BASIC_BOOT_RECORD),        // Length
> +      EFI_ACPI_5_0_FPDT_RUNTIME_RECORD_REVISION_FIRMWARE_BASIC_BOOT // Revision
> +    },
> +    0,  // Reserved
> +    //
> +    // These values will be updated at runtime.
> +    //
> +    0,  // ResetEnd
> +    0,  // OsLoaderLoadImageStart
> +    0,  // OsLoaderStartImageStart
> +    0,  // ExitBootServicesEntry
> +    0   // ExitBootServicesExit
> +  }
> +};
>
> -//
> -// The current maximum number of logging entries. If current number of
> -// entries exceeds this value, it will re-allocate a larger array and
> -// migration the old data to the larger array.
> -//
> -UINT32               mMaxGaugeRecords;
> +typedef struct {
> +  EFI_HANDLE    Handle;
> +  CHAR8         NameString[EDKII_STRING_EVENT_RECORD_NAME_LENGTH];
> +  EFI_GUID      ModuleGuid;
> +} HANDLE_GUID_MAP;
>
> -//
> -// The handle to install Performance Protocol instance.
> -//
> -EFI_HANDLE           mHandle = NULL;
> +HANDLE_GUID_MAP mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
> +UINTN           mCachePairCount = 0;
> +
> +UINT32  mLoadImageCount       = 0;
> +UINT32  mPerformanceLength    = 0;
> +UINT32  mMaxPerformanceLength = 0;
> +UINT32  mBootRecordSize       = 0;
> +UINT32  mBootRecordMaxSize    = 0;
> +
> +BOOLEAN mFpdtBufferIsReported = FALSE;
> +BOOLEAN mLackSpaceIsReported  = FALSE;
> +CHAR8   *mPlatformLanguage    = NULL;
> +UINT8   *mPerformancePointer  = NULL;
> +UINT8   *mBootRecordBuffer    = NULL;
> +
> +EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *mDevicePathToText = NULL;
>
>  //
>  // Interfaces for Performance Protocol.
>  //
>  PERFORMANCE_PROTOCOL mPerformanceInterface = {
> @@ -61,179 +99,1069 @@ PERFORMANCE_EX_PROTOCOL mPerformanceExInterface = {
>    GetGaugeEx
>    };
>
>  PERFORMANCE_PROPERTY  mPerformanceProperty;
>
> -//
> -//  Gauge record lock to avoid data corruption or even memory overflow
> -//
> -STATIC EFI_LOCK mPerfRecordLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_NOTIFY);
> +/**
> +Check whether the Token is a known one which is uesed by core.
> +
> +@param  Token      Pointer to a Null-terminated ASCII string
> +
> +@retval TRUE       Is a known one used by core.
> +@retval FALSE      Not a known one.
> +
> +**/
> +BOOLEAN
> +IsKnownTokens (
> +  IN CONST CHAR8  *Token
> +  )
> +{
> +  if (AsciiStrCmp (Token, SEC_TOK) == 0 ||
> +      AsciiStrCmp (Token, PEI_TOK) == 0 ||
> +      AsciiStrCmp (Token, DXE_TOK) == 0 ||
> +      AsciiStrCmp (Token, BDS_TOK) == 0 ||
> +      AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0 ||
> +      AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0 ||
> +      AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0 ||
> +      AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0 ||
> +      AsciiStrCmp (Token, START_IMAGE_TOK) == 0 ||
> +      AsciiStrCmp (Token, PEIM_TOK) == 0) {
> +    return TRUE;
> +  } else {
> +    return FALSE;
> +  }
> +}
> +
> +/**
> +Check whether the ID is a known one which map to the known Token.
> +
> +@param  Identifier  32-bit identifier.
> +
> +@retval TRUE        Is a known one used by core.
> +@retval FALSE       Not a known one.
> +
> +**/
> +BOOLEAN
> +IsKnownID (
> +  IN UINT32       Identifier
> +  )
> +{
> +  if (Identifier == MODULE_START_ID ||
> +      Identifier == MODULE_END_ID ||
> +      Identifier == MODULE_LOADIMAGE_START_ID ||
> +      Identifier == MODULE_LOADIMAGE_END_ID ||
> +      Identifier == MODULE_DB_START_ID ||
> +      Identifier == MODULE_DB_END_ID ||
> +      Identifier == MODULE_DB_SUPPORT_START_ID ||
> +      Identifier == MODULE_DB_SUPPORT_END_ID ||
> +      Identifier == MODULE_DB_STOP_START_ID ||
> +      Identifier == MODULE_DB_STOP_END_ID) {
> +    return TRUE;
> +  } else {
> +    return FALSE;
> +  }
> +}
>
>  /**
> -  Searches in the gauge array with keyword Handle, Token, Module and Identifier.
> +  Allocate EfiReservedMemoryType below 4G memory address.
> +
> +  This function allocates EfiReservedMemoryType below 4G memory address.
> +
> +  @param[in]  Size   Size of memory to allocate.
> +
> +  @return Allocated address for output.
> +
> +**/
> +VOID *
> +FpdtAllocateReservedMemoryBelow4G (
> +  IN UINTN       Size
> +  )
> +{
> +  UINTN                 Pages;
> +  EFI_PHYSICAL_ADDRESS  Address;
> +  EFI_STATUS            Status;
> +  VOID                  *Buffer;
> +
> +  Buffer  = NULL;
> +  Pages   = EFI_SIZE_TO_PAGES (Size);
> +  Address = 0xffffffff;
> +
> +  Status = gBS->AllocatePages (
> +                  AllocateMaxAddress,
> +                  EfiReservedMemoryType,
> +                  Pages,
> +                  &Address
> +                  );
> +  ASSERT_EFI_ERROR (Status);

This code is breaking DEBUG builds on ARM systems that have no memory
below 4 GB.

> +
> +  if (!EFI_ERROR (Status)) {
> +    Buffer = (VOID *) (UINTN) Address;
> +    ZeroMem (Buffer, Size);
> +  }
> +
> +  return Buffer;
> +}
> +
> +/**
> +  Allocate buffer for Boot Performance table.
> +
> +  @return Status code.
> +
> +**/
> +EFI_STATUS
> +AllocateBootPerformanceTable (
> +  )
> +{
> +  EFI_STATUS                    Status;
> +  UINTN                         Size;
> +  UINT8                         *SmmBootRecordCommBuffer;
> +  EFI_SMM_COMMUNICATE_HEADER    *SmmCommBufferHeader;
> +  SMM_BOOT_RECORD_COMMUNICATE   *SmmCommData;
> +  UINTN                         CommSize;
> +  UINTN                         BootPerformanceDataSize;
> +  UINT8                         *BootPerformanceData;
> +  EFI_SMM_COMMUNICATION_PROTOCOL  *Communication;
> +  FIRMWARE_PERFORMANCE_VARIABLE PerformanceVariable;
> +  EDKII_PI_SMM_COMMUNICATION_REGION_TABLE *SmmCommRegionTable;
> +  EFI_MEMORY_DESCRIPTOR         *SmmCommMemRegion;
> +  UINTN                         Index;
> +  VOID                          *SmmBootRecordData;
> +  UINTN                         SmmBootRecordDataSize;
> +  UINTN                         ReservedMemSize;
> +
> +  //
> +  // Collect boot records from SMM drivers.
> +  //
> +  SmmBootRecordCommBuffer = NULL;
> +  SmmCommData             = NULL;
> +  SmmBootRecordData       = NULL;
> +  SmmBootRecordDataSize   = 0;
> +  ReservedMemSize         = 0;
> +  Status = gBS->LocateProtocol (&gEfiSmmCommunicationProtocolGuid, NULL, (VOID **) &Communication);
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Initialize communicate buffer
> +    // Get the prepared Reserved Memory Range
> +    //
> +    Status = EfiGetSystemConfigurationTable (
> +              &gEdkiiPiSmmCommunicationRegionTableGuid,
> +              (VOID **) &SmmCommRegionTable
> +              );
> +    if (!EFI_ERROR (Status)) {
> +      ASSERT (SmmCommRegionTable != NULL);
> +      SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) (SmmCommRegionTable + 1);
> +      for (Index = 0; Index < SmmCommRegionTable->NumberOfEntries; Index ++) {
> +        if (SmmCommMemRegion->Type == EfiConventionalMemory) {
> +          break;
> +        }
> +        SmmCommMemRegion = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) SmmCommMemRegion + SmmCommRegionTable->DescriptorSize);
> +      }
> +      ASSERT (Index < SmmCommRegionTable->NumberOfEntries);
> +      ASSERT (SmmCommMemRegion->PhysicalStart > 0);
> +      ASSERT (SmmCommMemRegion->NumberOfPages > 0);
> +      ReservedMemSize = (UINTN) SmmCommMemRegion->NumberOfPages * EFI_PAGE_SIZE;
> +
> +      //
> +      // Check enough reserved memory space
> +      //
> +      if (ReservedMemSize > SMM_BOOT_RECORD_COMM_SIZE) {
> +        SmmBootRecordCommBuffer = (VOID *) (UINTN) SmmCommMemRegion->PhysicalStart;
> +        SmmCommBufferHeader = (EFI_SMM_COMMUNICATE_HEADER*)SmmBootRecordCommBuffer;
> +        SmmCommData = (SMM_BOOT_RECORD_COMMUNICATE*)SmmCommBufferHeader->Data;
> +        ZeroMem((UINT8*)SmmCommData, sizeof(SMM_BOOT_RECORD_COMMUNICATE));
> +
> +        CopyGuid (&SmmCommBufferHeader->HeaderGuid, &gEfiFirmwarePerformanceGuid);
> +        SmmCommBufferHeader->MessageLength = sizeof(SMM_BOOT_RECORD_COMMUNICATE);
> +        CommSize = SMM_BOOT_RECORD_COMM_SIZE;
> +
> +        //
> +        // Get the size of boot records.
> +        //
> +        SmmCommData->Function       = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_SIZE;
> +        SmmCommData->BootRecordData = NULL;
> +        Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
> +        ASSERT_EFI_ERROR (Status);
> +
> +        if (!EFI_ERROR (SmmCommData->ReturnStatus) && SmmCommData->BootRecordSize != 0) {
> +          //
> +          // Get all boot records
> +          //
> +          SmmCommData->Function       = SMM_FPDT_FUNCTION_GET_BOOT_RECORD_DATA_BY_OFFSET;
> +          SmmBootRecordDataSize       = SmmCommData->BootRecordSize;
> +          SmmBootRecordData           = AllocateZeroPool(SmmBootRecordDataSize);
> +          ASSERT (SmmBootRecordData  != NULL);
> +          SmmCommData->BootRecordOffset = 0;
> +          SmmCommData->BootRecordData   = (VOID *) ((UINTN) SmmCommMemRegion->PhysicalStart + SMM_BOOT_RECORD_COMM_SIZE);
> +          SmmCommData->BootRecordSize   = ReservedMemSize - SMM_BOOT_RECORD_COMM_SIZE;
> +          while (SmmCommData->BootRecordOffset < SmmBootRecordDataSize) {
> +            Status = Communication->Communicate (Communication, SmmBootRecordCommBuffer, &CommSize);
> +            ASSERT_EFI_ERROR (Status);
> +            ASSERT_EFI_ERROR(SmmCommData->ReturnStatus);
> +            if (SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize > SmmBootRecordDataSize) {
> +              CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmBootRecordDataSize - SmmCommData->BootRecordOffset);
> +            } else {
> +              CopyMem ((UINT8 *) SmmBootRecordData + SmmCommData->BootRecordOffset, SmmCommData->BootRecordData, SmmCommData->BootRecordSize);
> +            }
> +            SmmCommData->BootRecordOffset = SmmCommData->BootRecordOffset + SmmCommData->BootRecordSize;
> +          }
> +        }
> +      }
> +    }
> +  }
> +
> +  //
> +  // Prepare memory for Boot Performance table.
> +  // Boot Performance table includes BasicBoot record, and one or more appended Boot Records.
> +  //
> +  BootPerformanceDataSize = sizeof (BOOT_PERFORMANCE_TABLE) + mPerformanceLength + PcdGet32 (PcdExtFpdtBootRecordPadSize);
> +  if (SmmCommData != NULL) {
> +    BootPerformanceDataSize += SmmBootRecordDataSize;
> +  }
> +
> +  //
> +  // Try to allocate the same runtime buffer as last time boot.
> +  //
> +  ZeroMem (&PerformanceVariable, sizeof (PerformanceVariable));
> +  Size = sizeof (PerformanceVariable);
> +  Status = gRT->GetVariable (
> +                  EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
> +                  &gEfiFirmwarePerformanceGuid,
> +                  NULL,
> +                  &Size,
> +                  &PerformanceVariable
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    Status = gBS->AllocatePages (
> +                    AllocateAddress,
> +                    EfiReservedMemoryType,
> +                    EFI_SIZE_TO_PAGES (BootPerformanceDataSize),
> +                    &PerformanceVariable.BootPerformanceTablePointer
> +                    );
> +    if (!EFI_ERROR (Status)) {
> +      mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) (UINTN) PerformanceVariable.BootPerformanceTablePointer;
> +    }
> +  }
> +
> +  if (mAcpiBootPerformanceTable == NULL) {
> +    //
> +    // Fail to allocate at specified address, continue to allocate at any address.
> +    //
> +    mAcpiBootPerformanceTable = (BOOT_PERFORMANCE_TABLE *) FpdtAllocateReservedMemoryBelow4G (BootPerformanceDataSize);

Why does this allocation need to live below 4 GB?

If there is no good reason, can we please get rid of this?
If there is a good reason, can we please document it in the code?

> +  }
> +  DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: ACPI Boot Performance Table address = 0x%x\n", mAcpiBootPerformanceTable));
> +
> +  if (mAcpiBootPerformanceTable == NULL) {
> +    if (SmmCommData != NULL && SmmBootRecordData != NULL) {
> +      FreePool (SmmBootRecordData);
> +    }
> +    return EFI_OUT_OF_RESOURCES;
> +  }
> +
> +  //
> +  // Prepare Boot Performance Table.
> +  //
> +  BootPerformanceData = (UINT8 *) mAcpiBootPerformanceTable;
> +  //
> +  // Fill Basic Boot record to Boot Performance Table.
> +  //
> +  CopyMem (mAcpiBootPerformanceTable, &mBootPerformanceTableTemplate, sizeof (mBootPerformanceTableTemplate));
> +  BootPerformanceData = BootPerformanceData + mAcpiBootPerformanceTable->Header.Length;
> +  //
> +  // Fill Boot records from boot drivers.
> +  //
> +  if (mPerformancePointer != NULL) {
> +    CopyMem (BootPerformanceData, mPerformancePointer, mPerformanceLength);
> +    mAcpiBootPerformanceTable->Header.Length += mPerformanceLength;
> +    BootPerformanceData = BootPerformanceData + mPerformanceLength;
> +  }
> +  if (SmmCommData != NULL && SmmBootRecordData != NULL) {
> +    //
> +    // Fill Boot records from SMM drivers.
> +    //
> +    CopyMem (BootPerformanceData, SmmBootRecordData, SmmBootRecordDataSize);
> +    FreePool (SmmBootRecordData);
> +    mAcpiBootPerformanceTable->Header.Length = (UINT32) (mAcpiBootPerformanceTable->Header.Length + SmmBootRecordDataSize);
> +    BootPerformanceData = BootPerformanceData + SmmBootRecordDataSize;
> +  }
> +
> +  //
> +  // Save Boot Performance Table address to Variable for use in S4 resume.
> +  //
> +  PerformanceVariable.BootPerformanceTablePointer = (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiBootPerformanceTable;
> +
> +  //
> +  // Save Runtime Performance Table pointers to Variable.
> +  // Don't check SetVariable return status. It doesn't impact FPDT table generation.
> +  //
> +  gRT->SetVariable (
> +        EFI_FIRMWARE_PERFORMANCE_VARIABLE_NAME,
> +        &gEfiFirmwarePerformanceGuid,
> +        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
> +        sizeof (PerformanceVariable),
> +        &PerformanceVariable
> +        );
> +
> +  mBootRecordBuffer  = (UINT8 *) mAcpiBootPerformanceTable;
> +  mBootRecordSize    = mAcpiBootPerformanceTable->Header.Length;
> +  mBootRecordMaxSize = mBootRecordSize + PcdGet32 (PcdExtFpdtBootRecordPadSize);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Get a human readable module name and module guid for the given image handle.
> +  If module name can't be found, "" string will return.
> +  If module guid can't be found, Zero Guid will return.
> +
> +  @param    Handle        Image handle or Controller handle.
> +  @param    NameString    The ascii string will be filled into it. If not found, null string will return.
> +  @param    BufferSize    Size of the input NameString buffer.
> +  @param    ModuleGuid    Point to the guid buffer to store the got module guid value.
> +
> +  @retval EFI_SUCCESS     Successfully get module name and guid.
> +  @retval EFI_INVALID_PARAMETER  The input parameter NameString is NULL.
> +  @retval other value  Module Name can't be got.
> +**/
> +EFI_STATUS
> +GetModuleInfoFromHandle (
> +  IN EFI_HANDLE  Handle,
> +  OUT CHAR8            *NameString,
> +  IN UINTN             BufferSize,
> +  OUT EFI_GUID         *ModuleGuid OPTIONAL
> +  )
> +{
> +  EFI_STATUS                  Status;
> +  EFI_LOADED_IMAGE_PROTOCOL   *LoadedImage;
> +  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
> +  CHAR8                       *PdbFileName;
> +  EFI_GUID                    *TempGuid;
> +  UINTN                       StartIndex;
> +  UINTN                       Index;
> +  INTN                        Count;
> +  BOOLEAN                     ModuleGuidIsGet;
> +  UINTN                       StringSize;
> +  CHAR16                      *StringPtr;
> +  EFI_COMPONENT_NAME2_PROTOCOL      *ComponentName2;
> +  MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
> +
> +  if (NameString == NULL || BufferSize == 0) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +  //
> +  // Try to get the ModuleGuid and name string form the caached array.
> +  //
> +  if (mCachePairCount > 0) {
> +    for (Count = mCachePairCount -1; Count >= 0; Count--) {
> +      if (Handle == mCacheHandleGuidTable[Count].Handle) {
> +        CopyGuid (ModuleGuid, &mCacheHandleGuidTable[Count].ModuleGuid);
> +        AsciiStrCpyS (NameString, EDKII_STRING_EVENT_RECORD_NAME_LENGTH, mCacheHandleGuidTable[Count].NameString);
> +        return EFI_SUCCESS;
> +      }
> +    }
> +  }
> +
> +  Status = EFI_INVALID_PARAMETER;
> +  LoadedImage     = NULL;
> +  ModuleGuidIsGet = FALSE;
> +
> +  //
> +  // Initialize GUID as zero value.
> +  //
> +  TempGuid    = &gZeroGuid;
> +  //
> +  // Initialize it as "" string.
> +  //
> +  NameString[0] = 0;
> +
> +  if (Handle != NULL) {
> +    //
> +    // Try Handle as ImageHandle.
> +    //
> +    Status = gBS->HandleProtocol (
> +                  Handle,
> +                  &gEfiLoadedImageProtocolGuid,
> +                  (VOID**) &LoadedImage
> +                  );
> +
> +    if (EFI_ERROR (Status)) {
> +      //
> +      // Try Handle as Controller Handle
> +      //
> +      Status = gBS->OpenProtocol (
> +                    Handle,
> +                    &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
> +       ) {
> +      //
> +      // Determine GUID associated with module logging performance
> +      //
> +      ModuleGuidIsGet = TRUE;
> +      FvFilePath      = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LoadedImage->FilePath;
> +      TempGuid        = &FvFilePath->FvFileName;
> +    }
> +
> +    //
> +    // Method 1 Get Module Name from PDB string.
> +    //
> +    PdbFileName = PeCoffLoaderGetPdbPointer (LoadedImage->ImageBase);
> +    if (PdbFileName != NULL && BufferSize > 0) {
> +      StartIndex = 0;
> +      for (Index = 0; PdbFileName[Index] != 0; Index++) {
> +        if ((PdbFileName[Index] == '\\') || (PdbFileName[Index] == '/')) {
> +          StartIndex = Index + 1;
> +        }
> +      }
> +      //
> +      // Copy the PDB file name to our temporary string.
> +      // If the length is bigger than BufferSize, trim the redudant characters to avoid overflow in array boundary.
> +      //
> +      for (Index = 0; Index < BufferSize - 1; Index++) {
> +        NameString[Index] = PdbFileName[Index + StartIndex];
> +        if (NameString[Index] == 0 || NameString[Index] == '.') {
> +          NameString[Index] = 0;
> +          break;
> +        }
> +      }
>
> -  This internal function searches for the gauge entry in the gauge array.
> -  If there is an entry that exactly matches the given keywords
> -  and its end time stamp is zero, then the index of that gauge entry is returned;
> -  otherwise, the the number of gauge entries in the array is returned.
> +      if (Index == BufferSize - 1) {
> +        NameString[Index] = 0;
> +      }
> +      //
> +      // Module Name is got.
> +      //
> +      goto Done;
> +    }
> +  }
>
> +  //
> +  // Method 2: Get the name string from ComponentName2 protocol
> +  //
> +  Status = gBS->HandleProtocol (
> +                  Handle,
> +                  &gEfiComponentName2ProtocolGuid,
> +                  (VOID **) &ComponentName2
> +                  );
> +  if (!EFI_ERROR (Status)) {
> +    //
> +    // Get the current platform language setting
> +    //
> +    if (mPlatformLanguage == NULL) {
> +      GetEfiGlobalVariable2 (L"PlatformLang", (VOID **) &mPlatformLanguage, NULL);
> +    }
> +    if (mPlatformLanguage != NULL) {
> +      Status = ComponentName2->GetDriverName (
> +                                 ComponentName2,
> +                                 mPlatformLanguage != NULL ? mPlatformLanguage : "en-US",
> +                                 &StringPtr
> +                                 );
> +      if (!EFI_ERROR (Status)) {
> +        for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
> +          NameString[Index] = (CHAR8) StringPtr[Index];
> +        }
> +        NameString[Index] = 0;
> +        //
> +        // Module Name is got.
> +        //
> +        goto Done;
> +      }
> +    }
> +  }
> +
> +  if (ModuleGuidIsGet) {
> +    //
> +    // Method 3 Try to get the image's FFS UI section by image GUID
> +    //
> +    StringPtr  = NULL;
> +    StringSize = 0;
> +    Status = GetSectionFromAnyFv (
> +              TempGuid,
> +              EFI_SECTION_USER_INTERFACE,
> +              0,
> +              (VOID **) &StringPtr,
> +              &StringSize
> +              );
> +
> +    if (!EFI_ERROR (Status)) {
> +      //
> +      // Method 3. Get the name string from FFS UI section
> +      //
> +      for (Index = 0; Index < BufferSize - 1 && StringPtr[Index] != 0; Index++) {
> +        NameString[Index] = (CHAR8) StringPtr[Index];
> +      }
> +      NameString[Index] = 0;
> +      FreePool (StringPtr);
> +    }
> +  }
> +
> +Done:
> +  //
> +  // Copy Module Guid
> +  //
> +  if (ModuleGuid != NULL) {
> +    CopyGuid (ModuleGuid, TempGuid);
> +    if (IsZeroGuid(TempGuid) && (Handle != NULL) && !ModuleGuidIsGet) {
> +        // Handle is GUID
> +      CopyGuid (ModuleGuid, (EFI_GUID *) Handle);
> +    }
> +  }
> +
> +  //
> +  // Cache the Handle and Guid pairs.
> +  //
> +  if (mCachePairCount < CACHE_HANDLE_GUID_COUNT) {
> +    mCacheHandleGuidTable[mCachePairCount].Handle = Handle;
> +    CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, ModuleGuid);
> +    AsciiStrCpyS (mCacheHandleGuidTable[mCachePairCount].NameString, EDKII_STRING_EVENT_RECORD_NAME_LENGTH, NameString);
> +    mCachePairCount ++;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Get the FPDT record info.
> +
> +  @param  IsStart                 TRUE if the performance log is start log.
>    @param  Handle                  Pointer to environment specific context used
>                                    to identify the component being measured.
>    @param  Token                   Pointer to a Null-terminated ASCII string
>                                    that identifies the component being measured.
>    @param  Module                  Pointer to a Null-terminated ASCII string
>                                    that identifies the module being measured.
> -  @param  Identifier              32-bit identifier.
> +  @param  RecordInfo              On return, pointer to the info of the record.
> +  @param  UseModuleName           Only useful for DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use
> +                                  Module name to fill the string field in the DYNAMIC_STRING_EVENT_RECORD.
>
> -  @retval The index of gauge entry in the array.
> +  @retval EFI_SUCCESS          Get record info successfully.
> +  @retval EFI_UNSUPPORTED      No matched FPDT record.
>
>  **/
> -UINT32
> -InternalSearchForGaugeEntry (
> -  IN CONST VOID                 *Handle,  OPTIONAL
> -  IN CONST CHAR8                *Token,   OPTIONAL
> -  IN CONST CHAR8                *Module,   OPTIONAL
> -  IN UINT32                     Identifier
> +EFI_STATUS
> +GetFpdtRecordInfo (
> +  IN BOOLEAN                  IsStart,
> +  IN CONST VOID               *Handle,
> +  IN CONST CHAR8              *Token,
> +  IN CONST CHAR8              *Module,
> +  OUT BASIC_RECORD_INFO       *RecordInfo,
> +  IN OUT BOOLEAN              *UseModuleName
>    )
>  {
> -  UINT32                    Index;
> -  UINT32                    Index2;
> -  UINT32                    NumberOfEntries;
> -  GAUGE_DATA_ENTRY_EX       *GaugeEntryExArray;
> +  UINT16              RecordType;
> +  UINTN               StringSize;
>
> -  if (Token == NULL) {
> -    Token = "";
> -  }
> -  if (Module == NULL) {
> -    Module = "";
> +  RecordType    = DYNAMIC_STRING_EVENT_TYPE;
> +
> +  //
> +  // Token to Type and Id.
> +  //
> +  if (Token != NULL) {
> +    if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) {                // "StartImage:"
> +      *UseModuleName = TRUE;
> +      RecordType     = GUID_EVENT_TYPE;
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = MODULE_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = MODULE_END_ID;
> +      }
> +    } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {          // "LoadImage:"
> +      *UseModuleName = TRUE;
> +      RecordType = GUID_QWORD_EVENT_TYPE;
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = MODULE_LOADIMAGE_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = MODULE_LOADIMAGE_END_ID;
> +      }
> +    } else if (AsciiStrCmp (Token, DRIVERBINDING_START_TOK) == 0) {  // "DB:Start:"
> +      *UseModuleName = TRUE;
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = MODULE_DB_START_ID;
> +        RecordType   = GUID_QWORD_EVENT_TYPE;
> +      } else {
> +        RecordInfo->ProgressID  = MODULE_DB_END_ID;
> +        RecordType   = GUID_QWORD_STRING_EVENT_TYPE;
> +      }
> +    } else if (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) { // "DB:Support:"
> +      *UseModuleName = TRUE;
> +      if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
> +        return RETURN_UNSUPPORTED;
> +      }
> +      RecordType     = GUID_QWORD_EVENT_TYPE;
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = MODULE_DB_SUPPORT_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = MODULE_DB_SUPPORT_END_ID;
> +      }
> +    } else if (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) {    // "DB:Stop:"
> +      *UseModuleName = TRUE;
> +      if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
> +         return RETURN_UNSUPPORTED;
> +      }
> +      RecordType     = GUID_QWORD_EVENT_TYPE;
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = MODULE_DB_STOP_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = MODULE_DB_STOP_END_ID;
> +      }
> +    } else if (AsciiStrCmp (Token, PEI_TOK) == 0 ||                   // "PEI"
> +               AsciiStrCmp (Token, DXE_TOK) == 0 ||                   // "DXE"
> +               AsciiStrCmp (Token, BDS_TOK) == 0) {                   // "BDS"
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = PERF_CROSSMODULE_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = PERF_CROSSMODULE_END_ID;
> +      }
> +    } else {                                                          // Pref used in Modules.
> +      if (IsStart) {
> +        RecordInfo->ProgressID  = PERF_INMODULE_START_ID;
> +      } else {
> +        RecordInfo->ProgressID  = PERF_INMODULE_END_ID;
> +      }
> +    }
> +  } else if (Handle!= NULL || Module != NULL) {                       // Pref used in Modules.
> +    if (IsStart) {
> +      RecordInfo->ProgressID    = PERF_INMODULE_START_ID;
> +    } else {
> +      RecordInfo->ProgressID    = PERF_INMODULE_END_ID;
> +    }
> +  } else {
> +    return EFI_UNSUPPORTED;
>    }
>
> -  NumberOfEntries = mGaugeData->NumberOfEntries;
> -  GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
> +  //
> +  // Get Record size baesed on the record type.
> +  // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with type of DYNAMIC_STRING_EVENT_TYPE.
> +  //
> +  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
> +    RecordType               = DYNAMIC_STRING_EVENT_TYPE;
> +    RecordInfo->RecordSize   = sizeof (DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE;
> +  } else {
> +    switch (RecordType) {
> +    case GUID_EVENT_TYPE:
> +      RecordInfo->RecordSize = sizeof (GUID_EVENT_RECORD);
> +      break;
>
> -  Index2 = 0;
> +    case DYNAMIC_STRING_EVENT_TYPE:
> +      if (*UseModuleName) {
> +        StringSize  = STRING_SIZE;
> +      } else if (Token  != NULL) {
> +        StringSize  = AsciiStrSize (Token);
> +      } else if (Module != NULL) {
> +        StringSize  = AsciiStrSize (Module);
> +      } else {
> +        StringSize  = STRING_SIZE;
> +      }
> +      if (StringSize > STRING_SIZE) {
> +        StringSize   = STRING_SIZE;
> +      }
> +      RecordInfo->RecordSize = (UINT8)(sizeof (DYNAMIC_STRING_EVENT_RECORD) + StringSize);
> +      break;
>
> -  for (Index = 0; Index < NumberOfEntries; Index++) {
> -    Index2 = NumberOfEntries - 1 - Index;
> -    if (GaugeEntryExArray[Index2].EndTimeStamp == 0 &&
> -        (GaugeEntryExArray[Index2].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
> -        AsciiStrnCmp (GaugeEntryExArray[Index2].Token, Token, DXE_PERFORMANCE_STRING_LENGTH) == 0 &&
> -        AsciiStrnCmp (GaugeEntryExArray[Index2].Module, Module, DXE_PERFORMANCE_STRING_LENGTH) == 0) {
> -      Index = Index2;
> +    case GUID_QWORD_EVENT_TYPE:
> +      RecordInfo->RecordSize = (UINT8)sizeof (GUID_QWORD_EVENT_RECORD);
>        break;
> +
> +    case GUID_QWORD_STRING_EVENT_TYPE:
> +      RecordInfo->RecordSize = (UINT8)sizeof (GUID_QWORD_STRING_EVENT_RECORD);
> +      break;
> +
> +    default:
> +      //
> +      // Record is unsupported yet, return EFI_UNSUPPORTED
> +      //
> +      return EFI_UNSUPPORTED;
>      }
>    }
>
> -  return Index;
> +  RecordInfo->Type = RecordType;
> +  return EFI_SUCCESS;
>  }
>
>  /**
> -  Adds a record at the end of the performance measurement log
> -  that records the start time of a performance measurement.
> -
> -  Adds a record to the end of the performance measurement log
> -  that contains the Handle, Token, Module and Identifier.
> -  The end time of the new record must be set to zero.
> -  If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
> -  If TimeStamp is zero, the start time in the record is filled in with the value
> -  read from the current time stamp.
> +  Add performance log to FPDT boot record table.
>
> +  @param  IsStart                 TRUE if the performance log is start log.
>    @param  Handle                  Pointer to environment specific context used
>                                    to identify the component being measured.
>    @param  Token                   Pointer to a Null-terminated ASCII string
>                                    that identifies the component being measured.
>    @param  Module                  Pointer to a Null-terminated ASCII string
>                                    that identifies the module being measured.
> -  @param  TimeStamp               64-bit time stamp.
> +  @param  Ticker                  64-bit time stamp.
>    @param  Identifier              32-bit identifier. If the value is 0, the created record
>                                    is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
>
> -  @retval EFI_SUCCESS             The data was read correctly from the device.
> +  @retval EFI_SUCCESS             Add FPDT boot record.
>    @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.
> +  @retval EFI_UNSUPPORTED         No matched FPDT record.
>
>  **/
>  EFI_STATUS
> -EFIAPI
> -StartGaugeEx (
> +InsertFpdtMeasurement (
> +  IN BOOLEAN      IsStart,
>    IN CONST VOID   *Handle,  OPTIONAL
>    IN CONST CHAR8  *Token,   OPTIONAL
>    IN CONST CHAR8  *Module,  OPTIONAL
> -  IN UINT64       TimeStamp,
> +  IN UINT64       Ticker,
>    IN UINT32       Identifier
>    )
>  {
> -  GAUGE_DATA_ENTRY_EX       *GaugeEntryExArray;
> -  UINTN                     GaugeDataSize;
> -  GAUGE_DATA_HEADER         *NewGaugeData;
> -  UINTN                     OldGaugeDataSize;
> -  GAUGE_DATA_HEADER         *OldGaugeData;
> -  UINT32                    Index;
> -  EFI_STATUS                Status;
> +  EFI_GUID                     ModuleGuid;
> +  CHAR8                        ModuleName[EDKII_STRING_EVENT_RECORD_NAME_LENGTH];
> +  UINT8                        FpdtRecord[MAX_RECORD_SIZE];
> +  EFI_STATUS                   Status;
> +  FPDT_RECORD_PTR              FpdtRecordPtr;
> +  BASIC_RECORD_INFO            RecordInfo;
> +  UINT64                       TimeStamp;
> +  UINTN                        DestMax;
> +  UINTN                        StrLength;
> +  CONST CHAR8                  *StringPtr;
> +  BOOLEAN                      UseModuleName;
> +
> +  StringPtr     = NULL;
> +  UseModuleName = FALSE;
> +  ZeroMem (ModuleName, sizeof (ModuleName));
> +  ZeroMem (FpdtRecord, sizeof (FpdtRecord));
>
> -  Status = EfiAcquireLockOrFail (&mPerfRecordLock);
> +  //
> +  // Get record info (type, size, ProgressID and Module Guid).
> +  //
> +  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, &UseModuleName);
>    if (EFI_ERROR (Status)) {
>      return Status;
>    }
>
> -  Index = mGaugeData->NumberOfEntries;
> -  if (Index >= mMaxGaugeRecords) {
> +  //
> +  // If PERF_START()/PERF_END() have specified the ProgressID,it has high priority.
> +  // !!! Note: If the Pref is not the known Token used in the core but have same
> +  // ID with the core Token, this case will not be supported.
> +  // And in currtnt usage mode, for the unkown ID, there is a general rule:
> +  // If it is start pref: the lower 4 bits of the ID should be 0.
> +  // If it is end pref: the lower 4 bits of the ID should not be 0.
> +  // If input ID doesn't follow the rule, we will adjust it.
> +  //
> +  if ((Identifier != 0) && (IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
> +    return EFI_UNSUPPORTED;
> +  } else if ((Identifier != 0) && (!IsKnownID (Identifier)) && (!IsKnownTokens (Token))) {
> +    if (IsStart && ((Identifier & 0x000F) != 0)) {
> +      Identifier &= 0xFFF0;
> +    } else if ((!IsStart) && ((Identifier & 0x000F) == 0)) {
> +      Identifier += 1;
> +    }
> +    RecordInfo.ProgressID = (UINT16)Identifier;
> +  }
> +
> +  if (mFpdtBufferIsReported) {
> +    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)FpdtRecord;
> +  } else {
> +    //
> +    // Check if pre-allocated buffer is full
>      //
> -    // Try to enlarge the scale of gauge array.
> +    if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
> +      mPerformancePointer = ReallocatePool (
> +                              mPerformanceLength,
> +                              mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER,
> +                              mPerformancePointer
> +                              );
> +
> +      if (mPerformancePointer == NULL) {
> +        return EFI_OUT_OF_RESOURCES;
> +      }
> +      mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER;
> +    }
>      //
> -    OldGaugeData      = mGaugeData;
> -    OldGaugeDataSize  = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords;
> +    // Covert buffer to FPDT Ptr Union type.
> +    //
> +    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + mPerformanceLength);
> +  }
> +  FpdtRecordPtr.RecordHeader->Length = 0;
>
> -    GaugeDataSize     = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords * 2;
> +  //
> +  // Get the TimeStamp.
> +  //
> +  if (Ticker == 0) {
> +    Ticker    = GetPerformanceCounter ();
> +    TimeStamp = GetTimeInNanoSecond (Ticker);
> +  } else if (Ticker == 1) {
> +    TimeStamp = 0;
> +  } else {
> +    TimeStamp = GetTimeInNanoSecond (Ticker);
> +  }
>
> -    NewGaugeData = AllocateZeroPool (GaugeDataSize);
> -    if (NewGaugeData == NULL) {
> -      EfiReleaseLock (&mPerfRecordLock);
> -      return EFI_OUT_OF_RESOURCES;
> +  //
> +  // Get the ModuleName and ModuleGuid form the handle.
> +  //
> +  GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof (ModuleName), &ModuleGuid);
> +
> +  //
> +  // Fill in the record information.
> +  //
> +  switch (RecordInfo.Type) {
> +  case GUID_EVENT_TYPE:
> +    FpdtRecordPtr.GuidEvent->Header.Type                = GUID_EVENT_TYPE;
> +    FpdtRecordPtr.GuidEvent->Header.Length              = RecordInfo.RecordSize;
> +    FpdtRecordPtr.GuidEvent->Header.Revision            = RECORD_REVISION_1;
> +    FpdtRecordPtr.GuidEvent->ProgressID                 = RecordInfo.ProgressID;
> +    FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
> +    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
> +    break;
> +
> +  case DYNAMIC_STRING_EVENT_TYPE:
> +    FpdtRecordPtr.DynamicStringEvent->Header.Type       = DYNAMIC_STRING_EVENT_TYPE;
> +    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordInfo.RecordSize;
> +    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = RECORD_REVISION_1;
> +    FpdtRecordPtr.DynamicStringEvent->ProgressID        = RecordInfo.ProgressID;
> +    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
> +    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
> +
> +    if (UseModuleName) {
> +      StringPtr     = ModuleName;
> +    } else if (Token != NULL) {
> +      StringPtr     = Token;
> +    } else if (Module != NULL) {
> +      StringPtr     = Module;
> +    } else if (ModuleName != NULL) {
> +      StringPtr     = ModuleName;
> +    }
> +    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
> +      StrLength     = AsciiStrLen (StringPtr);
> +      DestMax       = (RecordInfo.RecordSize - sizeof (DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
> +      if (StrLength >= DestMax) {
> +        StrLength   = DestMax -1;
> +      }
> +      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, StringPtr, StrLength);
>      }
> +    break;
> +
> +  case GUID_QWORD_EVENT_TYPE:
> +    FpdtRecordPtr.GuidQwordEvent->Header.Type           = GUID_QWORD_EVENT_TYPE;
> +    FpdtRecordPtr.GuidQwordEvent->Header.Length         = RecordInfo.RecordSize;
> +    FpdtRecordPtr.GuidQwordEvent->Header.Revision       = RECORD_REVISION_1;
> +    FpdtRecordPtr.GuidQwordEvent->ProgressID            = RecordInfo.ProgressID;
> +    FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
> +    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordEvent->Guid));
> +    if ((MODULE_LOADIMAGE_START_ID == RecordInfo.ProgressID) && AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {
> +      mLoadImageCount++;
> +      FpdtRecordPtr.GuidQwordEvent->Qword               = mLoadImageCount;
> +    }
> +    break;
> +
> +  case GUID_QWORD_STRING_EVENT_TYPE:
> +    FpdtRecordPtr.GuidQwordStringEvent->Header.Type     = GUID_QWORD_STRING_EVENT_TYPE;
> +    FpdtRecordPtr.GuidQwordStringEvent->Header.Length   = RecordInfo.RecordSize;
> +    FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = RECORD_REVISION_1;
> +    FpdtRecordPtr.GuidQwordStringEvent->ProgressID      = RecordInfo.ProgressID;
> +    FpdtRecordPtr.GuidQwordStringEvent->Timestamp       = TimeStamp;
> +    CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof (FpdtRecordPtr.GuidQwordStringEvent->Guid));
> +    break;
> +
> +  default:
> +    //
> +    // Record is not supported in current DXE phase, return EFI_ABORTED
> +    //
> +    return EFI_UNSUPPORTED;
> +  }
> +
> +  //
> +  // Report record one by one after records have been reported together.
> +  //
> +  if (mFpdtBufferIsReported) {
> +      //
> +      // Append Boot records to the boot performance table.
> +      //
> +      if (mBootRecordSize + FpdtRecordPtr.RecordHeader->Length > mBootRecordMaxSize) {
> +        if (!mLackSpaceIsReported) {
> +          DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save boot records\n"));
> +          mLackSpaceIsReported = TRUE;
> +        }
> +        return EFI_OUT_OF_RESOURCES;
> +      } else {
> +        //
> +        // Save boot record into BootPerformance table
> +        //
> +        CopyMem (mBootRecordBuffer + mBootRecordSize, FpdtRecordPtr.RecordHeader, FpdtRecordPtr.RecordHeader->Length);
> +        mBootRecordSize += FpdtRecordPtr.RecordHeader->Length;
> +        mAcpiBootPerformanceTable->Header.Length += FpdtRecordPtr.RecordHeader->Length;
> +      }
> +  } else {
> +    //
> +    // Update the cached FPDT record buffer.
> +    //
> +    mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Dumps all the PEI performance.
> +
> +  @param  HobStart      A pointer to a Guid.
>
> -    mGaugeData = NewGaugeData;
> -    mMaxGaugeRecords *= 2;
> +  This internal function dumps all the PEI performance log to the DXE performance gauge array.
> +  It retrieves the optional GUID HOB for PEI performance and then saves the performance data
> +  to DXE performance data structures.
>
> +**/
> +VOID
> +InternalGetPeiPerformance (
> +  VOID  *HobStart
> +  )
> +{
> +  UINT8                                *FirmwarePerformanceHob;
> +  PEI_EXT_FIRMWARE_PERF_HEADER         *PeiPerformanceLogHeader;
> +  UINT8                                *EventRec;
> +  EFI_HOB_GUID_TYPE                    *GuidHob;
> +
> +  GuidHob = GetNextGuidHob (&gEdkiiExtendedFirmwarePerformanceGuid, HobStart);
> +  while (GuidHob != NULL) {
> +    FirmwarePerformanceHob  = GET_GUID_HOB_DATA (GuidHob);
> +    PeiPerformanceLogHeader = (PEI_EXT_FIRMWARE_PERF_HEADER *)FirmwarePerformanceHob;
> +
> +    if (mPerformanceLength + PeiPerformanceLogHeader->SizeOfAllEntries > mMaxPerformanceLength) {
> +      mPerformancePointer = ReallocatePool (
> +                              mPerformanceLength,
> +                              mPerformanceLength +
> +                              (UINTN)PeiPerformanceLogHeader->SizeOfAllEntries +
> +                              FIRMWARE_RECORD_BUFFER,
> +                              mPerformancePointer
> +                              );
> +      ASSERT (mPerformancePointer != NULL);
> +      mMaxPerformanceLength = mPerformanceLength +
> +                              (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries) +
> +                              FIRMWARE_RECORD_BUFFER;
> +    }
> +
> +    EventRec = mPerformancePointer + mPerformanceLength;
> +    CopyMem (EventRec, FirmwarePerformanceHob + sizeof (PEI_EXT_FIRMWARE_PERF_HEADER), (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries));
>      //
> -    // Initialize new data array and migrate old data one.
> +    // Update the used buffer size.
>      //
> -    mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);
> +    mPerformanceLength += (UINTN)(PeiPerformanceLogHeader->SizeOfAllEntries);
> +    mLoadImageCount    += PeiPerformanceLogHeader->LoadImageCount;
>
> -    FreePool (OldGaugeData);
> +    //
> +    // Get next performance guid hob
> +    //
> +    GuidHob = GetNextGuidHob (&gEdkiiExtendedFirmwarePerformanceGuid, GET_NEXT_HOB (GuidHob));
>    }
> +}
>
> -  GaugeEntryExArray               = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
> -  GaugeEntryExArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
> +/**
> +  Report Boot Perforamnce table address as report status code.
>
> -  if (Token != NULL) {
> -    AsciiStrnCpyS (GaugeEntryExArray[Index].Token, DXE_PERFORMANCE_STRING_SIZE, Token, DXE_PERFORMANCE_STRING_LENGTH);
> -  }
> -  if (Module != NULL) {
> -    AsciiStrnCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, Module, DXE_PERFORMANCE_STRING_LENGTH);
> +  @param  Event    The event of notify protocol.
> +  @param  Context  Notify event context.
> +
> +**/
> +VOID
> +EFIAPI
> +ReportFpdtRecordBuffer (
> +  IN EFI_EVENT     Event,
> +  IN VOID          *Context
> +  )
> +{
> +  EFI_STATUS      Status;
> +  UINT64          BPDTAddr;
> +
> +  if (!mFpdtBufferIsReported) {
> +    Status = AllocateBootPerformanceTable ();
> +    if (!EFI_ERROR(Status)) {
> +      BPDTAddr = (UINT64)(UINTN)mAcpiBootPerformanceTable;
> +      REPORT_STATUS_CODE_EX (
> +          EFI_PROGRESS_CODE,
> +          EFI_SOFTWARE_DXE_BS_DRIVER,
> +          0,
> +          NULL,
> +          &gEfiFirmwarePerformanceGuid,
> +          &BPDTAddr,
> +          sizeof (UINT64)
> +          );
> +    }
> +    //
> +    // Free Cached FPDT record Buffer
> +    //
> +    if (mPerformancePointer != NULL) {
> +      FreePool (mPerformancePointer);
> +      mPerformancePointer   = NULL;
> +    }
> +    mPerformanceLength    = 0;
> +    mMaxPerformanceLength = 0;
> +    //
> +    // Set FPDT report state to TRUE.
> +    //
> +    mFpdtBufferIsReported = TRUE;
>    }
> +}
>
> -  GaugeEntryExArray[Index].EndTimeStamp = 0;
> -  GaugeEntryExArray[Index].Identifier = Identifier;
> +/**
> +  Adds a record at the end of the performance measurement log
> +  that records the start time of a performance measurement.
>
> -  if (TimeStamp == 0) {
> -    TimeStamp = GetPerformanceCounter ();
> -  }
> -  GaugeEntryExArray[Index].StartTimeStamp = TimeStamp;
> +  Adds a record to the end of the performance measurement log
> +  that contains the Handle, Token, Module and Identifier.
> +  The end time of the new record must be set to zero.
> +  If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
> +  If TimeStamp is zero, the start time in the record is filled in with the value
> +  read from the current time stamp.
>
> -  mGaugeData->NumberOfEntries++;
> +  @param  Handle                  Pointer to environment specific context used
> +                                  to identify the component being measured.
> +  @param  Token                   Pointer to a Null-terminated ASCII string
> +                                  that identifies the component being measured.
> +  @param  Module                  Pointer to a Null-terminated ASCII string
> +                                  that identifies the module being measured.
> +  @param  TimeStamp               64-bit time stamp.
> +  @param  Identifier              32-bit identifier. If the value is 0, the created record
> +                                  is same as the one created by StartGauge of PERFORMANCE_PROTOCOL.
>
> -  EfiReleaseLock (&mPerfRecordLock);
> +  @retval EFI_SUCCESS             The data was read correctly from the device.
> +  @retval EFI_OUT_OF_RESOURCES    There are not enough resources to record the measurement.
>
> -  return EFI_SUCCESS;
> +**/
> +EFI_STATUS
> +EFIAPI
> +StartGaugeEx (
> +  IN CONST VOID   *Handle,  OPTIONAL
> +  IN CONST CHAR8  *Token,   OPTIONAL
> +  IN CONST CHAR8  *Module,  OPTIONAL
> +  IN UINT64       TimeStamp,
> +  IN UINT32       Identifier
> +  )
> +{
> +  return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier);
>  }
>
>  /**
>    Searches the performance measurement log from the beginning of the log
>    for the first matching record that contains a zero end time and fills in a valid end time.
>
>    Searches the performance measurement log from the beginning of the log
> -  for the first record that matches Handle, Token and Module and has an end time value of zero.
> +  for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
>    If the record can not be found then return EFI_NOT_FOUND.
>    If the record is found and TimeStamp is not zero,
>    then the end time in the record is filled in with the value specified by TimeStamp.
>    If the record is found and TimeStamp is zero, then the end time in the matching record
>    is filled in with the current time stamp value.
> @@ -260,89 +1188,19 @@ EndGaugeEx (
>    IN CONST CHAR8  *Module,  OPTIONAL
>    IN UINT64       TimeStamp,
>    IN UINT32       Identifier
>    )
>  {
> -  GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
> -  UINT32              Index;
> -  EFI_STATUS          Status;
> -
> -  Status = EfiAcquireLockOrFail (&mPerfRecordLock);
> -  if (EFI_ERROR (Status)) {
> -    return Status;
> -  }
> -
> -  if (TimeStamp == 0) {
> -    TimeStamp = GetPerformanceCounter ();
> -  }
> -
> -  Index = InternalSearchForGaugeEntry (Handle, Token, Module, Identifier);
> -  if (Index >= mGaugeData->NumberOfEntries) {
> -    EfiReleaseLock (&mPerfRecordLock);
> -    return EFI_NOT_FOUND;
> -  }
> -  GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
> -  GaugeEntryExArray[Index].EndTimeStamp = TimeStamp;
> -
> -  EfiReleaseLock (&mPerfRecordLock);
> -  return EFI_SUCCESS;
> +  return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier);
>  }
>
>  /**
>    Retrieves a previously logged performance measurement.
>    It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
>    and then assign the Identifier with 0.
>
> -  Retrieves the performance log entry from the performance log specified by LogEntryKey.
> -  If it stands for a valid entry, then EFI_SUCCESS is returned and
> -  GaugeDataEntryEx stores the pointer to that entry.
> -
> -  This internal function is added to avoid releasing lock before each return statement.
> -
> -  @param  LogEntryKey             The key for the previous performance measurement log entry.
> -                                  If 0, then the first performance measurement log entry is retrieved.
> -  @param  GaugeDataEntryEx        The indirect pointer to the extended gauge data entry specified by LogEntryKey
> -                                  if the retrieval is successful.
> -
> -  @retval EFI_SUCCESS             The GuageDataEntryEx is successfully found based on LogEntryKey.
> -  @retval EFI_NOT_FOUND           The LogEntryKey is the last entry (equals to the total entry number).
> -  @retval EFI_INVALIDE_PARAMETER  The LogEntryKey is not a valid entry (greater than the total entry number).
> -  @retval EFI_INVALIDE_PARAMETER  GaugeDataEntryEx is NULL.
> -
> -**/
> -EFI_STATUS
> -EFIAPI
> -InternalGetGaugeEx (
> -  IN  UINTN                 LogEntryKey,
> -  OUT GAUGE_DATA_ENTRY_EX   **GaugeDataEntryEx
> -  )
> -{
> -  UINTN               NumberOfEntries;
> -  GAUGE_DATA_ENTRY_EX *GaugeEntryExArray;
> -
> -  NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries);
> -  if (LogEntryKey > NumberOfEntries) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> -  if (LogEntryKey == NumberOfEntries) {
> -    return EFI_NOT_FOUND;
> -  }
> -
> -  GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
> -
> -  if (GaugeDataEntryEx == NULL) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> -  *GaugeDataEntryEx = &GaugeEntryExArray[LogEntryKey];
> -
> -  return EFI_SUCCESS;
> -}
> -
> -/**
> -  Retrieves a previously logged performance measurement.
> -  It can also retrieve the log created by StartGauge and EndGauge of PERFORMANCE_PROTOCOL,
> -  and then assign the Identifier with 0.
> +    !!! Not support!!!
>
>    Retrieves the performance log entry from the performance log specified by LogEntryKey.
>    If it stands for a valid entry, then EFI_SUCCESS is returned and
>    GaugeDataEntryEx stores the pointer to that entry.
>
> @@ -362,22 +1220,11 @@ EFIAPI
>  GetGaugeEx (
>    IN  UINTN                 LogEntryKey,
>    OUT GAUGE_DATA_ENTRY_EX   **GaugeDataEntryEx
>    )
>  {
> -  EFI_STATUS                Status;
> -
> -  Status = EfiAcquireLockOrFail (&mPerfRecordLock);
> -  if (EFI_ERROR (Status)) {
> -    return Status;
> -  }
> -
> -  Status = InternalGetGaugeEx (LogEntryKey, GaugeDataEntryEx);
> -
> -  EfiReleaseLock (&mPerfRecordLock);
> -
> -  return Status;
> +  return EFI_UNSUPPORTED;
>  }
>
>  /**
>    Adds a record at the end of the performance measurement log
>    that records the start time of a performance measurement.
> @@ -452,10 +1299,12 @@ EndGauge (
>  /**
>    Retrieves a previously logged performance measurement.
>    It can also retrieve the log created by StartGaugeEx and EndGaugeEx of PERFORMANCE_EX_PROTOCOL,
>    and then eliminate the Identifier.
>
> +    !!! Not support!!!
> +
>    Retrieves the performance log entry from the performance log specified by LogEntryKey.
>    If it stands for a valid entry, then EFI_SUCCESS is returned and
>    GaugeDataEntry stores the pointer to that entry.
>
>    @param  LogEntryKey             The key for the previous performance measurement log entry.
> @@ -474,81 +1323,13 @@ EFIAPI
>  GetGauge (
>    IN  UINTN               LogEntryKey,
>    OUT GAUGE_DATA_ENTRY    **GaugeDataEntry
>    )
>  {
> -  EFI_STATUS          Status;
> -  GAUGE_DATA_ENTRY_EX *GaugeEntryEx;
> -
> -  GaugeEntryEx = NULL;
> -
> -  Status = GetGaugeEx (LogEntryKey, &GaugeEntryEx);
> -  if (EFI_ERROR (Status)) {
> -    return Status;
> -  }
> -
> -  if (GaugeDataEntry == NULL) {
> -    return EFI_INVALID_PARAMETER;
> -  }
> -
> -  *GaugeDataEntry = (GAUGE_DATA_ENTRY *) GaugeEntryEx;
> -
> -  return EFI_SUCCESS;
> +  return EFI_UNSUPPORTED;
>  }
>
> -/**
> -  Dumps all the PEI performance log to DXE performance gauge array.
> -
> -  This internal function dumps all the PEI performance log to the DXE performance gauge array.
> -  It retrieves the optional GUID HOB for PEI performance and then saves the performance data
> -  to DXE performance data structures.
> -
> -**/
> -VOID
> -InternalGetPeiPerformance (
> -  VOID
> -  )
> -{
> -  EFI_HOB_GUID_TYPE                 *GuidHob;
> -  PEI_PERFORMANCE_LOG_HEADER        *LogHob;
> -  PEI_PERFORMANCE_LOG_ENTRY         *LogEntryArray;
> -  UINT32                            *LogIdArray;
> -  GAUGE_DATA_ENTRY_EX               *GaugeEntryExArray;
> -  UINT32                            Index;
> -  UINT32                            NumberOfEntries;
> -
> -  NumberOfEntries = 0;
> -  GaugeEntryExArray = (GAUGE_DATA_ENTRY_EX *) (mGaugeData + 1);
> -
> -  //
> -  // Dump PEI Log Entries to DXE Guage Data structure.
> -  //
> -  GuidHob = GetFirstGuidHob (&gPerformanceProtocolGuid);
> -  if (GuidHob != NULL) {
> -    LogHob          = GET_GUID_HOB_DATA (GuidHob);
> -    LogEntryArray   = (PEI_PERFORMANCE_LOG_ENTRY *) (LogHob + 1);
> -
> -    NumberOfEntries = LogHob->NumberOfEntries;
> -    for (Index = 0; Index < NumberOfEntries; Index++) {
> -      GaugeEntryExArray[Index].Handle         = LogEntryArray[Index].Handle;
> -      AsciiStrCpyS (GaugeEntryExArray[Index].Token,  DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Token);
> -      AsciiStrCpyS (GaugeEntryExArray[Index].Module, DXE_PERFORMANCE_STRING_SIZE, LogEntryArray[Index].Module);
> -      GaugeEntryExArray[Index].StartTimeStamp = LogEntryArray[Index].StartTimeStamp;
> -      GaugeEntryExArray[Index].EndTimeStamp   = LogEntryArray[Index].EndTimeStamp;
> -      GaugeEntryExArray[Index].Identifier     = 0;
> -    }
> -
> -    GuidHob = GetFirstGuidHob (&gPerformanceExProtocolGuid);
> -    if (GuidHob != NULL) {
> -      LogIdArray    = GET_GUID_HOB_DATA (GuidHob);
> -      for (Index = 0; Index < NumberOfEntries; Index++) {
> -        GaugeEntryExArray[Index].Identifier   = LogIdArray[Index];
> -      }
> -    }
> -  }
> -  mGaugeData->NumberOfEntries = NumberOfEntries;
> -}
>
>  /**
>    The constructor function initializes Performance infrastructure for DXE phase.
>
>    The constructor function publishes Performance and PerformanceEx protocol, allocates memory to log DXE performance
> @@ -567,40 +1348,53 @@ DxeCorePerformanceLibConstructor (
>    IN EFI_HANDLE        ImageHandle,
>    IN EFI_SYSTEM_TABLE  *SystemTable
>    )
>  {
>    EFI_STATUS                Status;
> +  EFI_HANDLE                Handle;
> +  EFI_EVENT                 ReadyToBootEvent;
>    PERFORMANCE_PROPERTY      *PerformanceProperty;
>
> -
>    if (!PerformanceMeasurementEnabled ()) {
>      //
>      // Do not initialize performance infrastructure if not required.
>      //
>      return EFI_SUCCESS;
>    }
> +
> +  //
> +  // Dump normal PEI performance records
> +  //
> +  InternalGetPeiPerformance (GetHobList());
> +
>    //
> -  // Install the protocol interfaces.
> +  // Install the protocol interfaces for DXE performance library instance.
>    //
> +  Handle = NULL;
>    Status = gBS->InstallMultipleProtocolInterfaces (
> -                  &mHandle,
> +                  &Handle,
>                    &gPerformanceProtocolGuid,
>                    &mPerformanceInterface,
>                    &gPerformanceExProtocolGuid,
>                    &mPerformanceExInterface,
>                    NULL
>                    );
>    ASSERT_EFI_ERROR (Status);
>
> -  mMaxGaugeRecords = INIT_DXE_GAUGE_DATA_ENTRIES + (UINT16) (PcdGet16 (PcdMaxPeiPerformanceLogEntries16) != 0 ?
> -                                                             PcdGet16 (PcdMaxPeiPerformanceLogEntries16) :
> -                                                             PcdGet8 (PcdMaxPeiPerformanceLogEntries));
> -
> -  mGaugeData = AllocateZeroPool (sizeof (GAUGE_DATA_HEADER) + (sizeof (GAUGE_DATA_ENTRY_EX) * mMaxGaugeRecords));
> -  ASSERT (mGaugeData != NULL);
> +  //
> +  // Register ReadyToBoot event to report StatusCode data
> +  //
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_CALLBACK,
> +                  ReportFpdtRecordBuffer,
> +                  NULL,
> +                  &gEfiEventReadyToBootGuid,
> +                  &ReadyToBootEvent
> +                  );
>
> -  InternalGetPeiPerformance ();
> +  ASSERT_EFI_ERROR (Status);
>
>    Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **) &PerformanceProperty);
>    if (EFI_ERROR (Status)) {
>      //
>      // Install configuration table for performance property.
> @@ -651,19 +1445,19 @@ StartPerformanceMeasurementEx (
>    IN CONST CHAR8  *Module,  OPTIONAL
>    IN UINT64       TimeStamp,
>    IN UINT32       Identifier
>    )
>  {
> -  return (RETURN_STATUS) StartGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
> +  return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, Identifier);
>  }
>
>  /**
>    Searches the performance measurement log from the beginning of the log
>    for the first matching record that contains a zero end time and fills in a valid end time.
>
>    Searches the performance measurement log from the beginning of the log
> -  for the first record that matches Handle, Token and Module and has an end time value of zero.
> +  for the first record that matches Handle, Token, Module and Identifier and has an end time value of zero.
>    If the record can not be found then return RETURN_NOT_FOUND.
>    If the record is found and TimeStamp is not zero,
>    then the end time in the record is filled in with the value specified by TimeStamp.
>    If the record is found and TimeStamp is zero, then the end time in the matching record
>    is filled in with the current time stamp value.
> @@ -690,18 +1484,20 @@ EndPerformanceMeasurementEx (
>    IN CONST CHAR8  *Module,  OPTIONAL
>    IN UINT64       TimeStamp,
>    IN UINT32       Identifier
>    )
>  {
> -  return (RETURN_STATUS) EndGaugeEx (Handle, Token, Module, TimeStamp, Identifier);
> +  return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, Identifier);
>  }
>
>  /**
>    Attempts to retrieve a performance measurement log entry from the performance measurement log.
>    It can also retrieve the log created by StartPerformanceMeasurement and EndPerformanceMeasurement,
>    and then assign the Identifier with 0.
>
> +    !!! Not support!!!
> +
>    Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
>    zero on entry, then an attempt is made to retrieve the first entry from the performance log,
>    and the key for the second entry in the log is returned.  If the performance log is empty,
>    then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
>    log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
> @@ -729,63 +1525,29 @@ EndPerformanceMeasurementEx (
>                                    being measured.
>    @param  StartTimeStamp          Pointer to the 64-bit time stamp that was recorded when the measurement
>                                    was started.
>    @param  EndTimeStamp            Pointer to the 64-bit time stamp that was recorded when the measurement
>                                    was ended.
> -  @param  Identifier              Pointer to the 32-bit identifier that was recorded.
> +  @param  Identifier              Pointer to the 32-bit identifier that was recorded when the measurement
> +                                  was ended.
>
>    @return The key for the next performance log entry (in general case).
>
>  **/
>  UINTN
>  EFIAPI
>  GetPerformanceMeasurementEx (
> -  IN  UINTN       LogEntryKey,
> +  IN  UINTN       LogEntryKey,
>    OUT CONST VOID  **Handle,
>    OUT CONST CHAR8 **Token,
>    OUT CONST CHAR8 **Module,
>    OUT UINT64      *StartTimeStamp,
>    OUT UINT64      *EndTimeStamp,
>    OUT UINT32      *Identifier
>    )
>  {
> -  EFI_STATUS           Status;
> -  GAUGE_DATA_ENTRY_EX  *GaugeData;
> -
> -  GaugeData = NULL;
> -
> -  ASSERT (Handle != NULL);
> -  ASSERT (Token != NULL);
> -  ASSERT (Module != NULL);
> -  ASSERT (StartTimeStamp != NULL);
> -  ASSERT (EndTimeStamp != NULL);
> -  ASSERT (Identifier != NULL);
> -
> -  Status = GetGaugeEx (LogEntryKey++, &GaugeData);
> -
> -  //
> -  // Make sure that LogEntryKey is a valid log entry key,
> -  //
> -  ASSERT (Status != EFI_INVALID_PARAMETER);
> -
> -  if (EFI_ERROR (Status)) {
> -    //
> -    // The LogEntryKey is the last entry (equals to the total entry number).
> -    //
> -    return 0;
> -  }
> -
> -  ASSERT (GaugeData != NULL);
> -
> -  *Handle         = (VOID *) (UINTN) GaugeData->Handle;
> -  *Token          = GaugeData->Token;
> -  *Module         = GaugeData->Module;
> -  *StartTimeStamp = GaugeData->StartTimeStamp;
> -  *EndTimeStamp   = GaugeData->EndTimeStamp;
> -  *Identifier     = GaugeData->Identifier;
> -
> -  return LogEntryKey;
> +  return 0;
>  }
>
>  /**
>    Adds a record at the end of the performance measurement log
>    that records the start time of a performance measurement.
> @@ -816,11 +1578,11 @@ StartPerformanceMeasurement (
>    IN CONST CHAR8  *Token,   OPTIONAL
>    IN CONST CHAR8  *Module,  OPTIONAL
>    IN UINT64       TimeStamp
>    )
>  {
> -  return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
> +  return InsertFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 0);
>  }
>
>  /**
>    Searches the performance measurement log from the beginning of the log
>    for the first matching record that contains a zero end time and fills in a valid end time.
> @@ -852,18 +1614,20 @@ EndPerformanceMeasurement (
>    IN CONST CHAR8  *Token,   OPTIONAL
>    IN CONST CHAR8  *Module,  OPTIONAL
>    IN UINT64       TimeStamp
>    )
>  {
> -  return EndPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
> +  return InsertFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 0);
>  }
>
>  /**
>    Attempts to retrieve a performance measurement log entry from the performance measurement log.
>    It can also retrieve the log created by StartPerformanceMeasurementEx and EndPerformanceMeasurementEx,
>    and then eliminate the Identifier.
>
> +  !!! Not support!!!
> +
>    Attempts to retrieve the performance log entry specified by LogEntryKey.  If LogEntryKey is
>    zero on entry, then an attempt is made to retrieve the first entry from the performance log,
>    and the key for the second entry in the log is returned.  If the performance log is empty,
>    then no entry is retrieved and zero is returned.  If LogEntryKey is not zero, then the performance
>    log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
> @@ -905,12 +1669,11 @@ GetPerformanceMeasurement (
>    OUT CONST CHAR8 **Module,
>    OUT UINT64      *StartTimeStamp,
>    OUT UINT64      *EndTimeStamp
>    )
>  {
> -  UINT32 Identifier;
> -  return GetPerformanceMeasurementEx (LogEntryKey, Handle, Token, Module, StartTimeStamp, EndTimeStamp, &Identifier);
> +  return 0;
>  }
>
>  /**
>    Returns TRUE if the performance measurement macros are enabled.
>
> diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
> index 5b89ce2..71c181f 100644
> --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
> +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
> @@ -7,11 +7,11 @@
>  #  It initializes DXE phase performance logging by publishing the Performance and PerformanceEx Protocol,
>  #  which is consumed by DxePerformanceLib to logging performance data in DXE phase.
>  #  This library is mainly used by DxeCore to start performance logging to ensure that
>  #  Performance and PerformanceEx Protocol are installed at the very beginning of DXE phase.
>  #
> -#  Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>  # (C) Copyright 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
>  #  which accompanies this distribution.  The full text of the license may be found at
>  #  http://opensource.org/licenses/bsd-license.php
> @@ -48,27 +48,39 @@
>
>
>  [LibraryClasses]
>    MemoryAllocationLib
>    UefiBootServicesTableLib
> +  UefiRuntimeServicesTableLib
>    PcdLib
>    TimerLib
>    BaseMemoryLib
>    BaseLib
>    HobLib
>    DebugLib
>    UefiLib
> +  ReportStatusCodeLib
> +  DxeServicesLib
> +  PeCoffGetEntryPointLib
> +
> +[Protocols]
> +  gEfiSmmCommunicationProtocolGuid              ## SOMETIMES_CONSUMES
>
>
>  [Guids]
>    ## SOMETIMES_CONSUMES   ## HOB
>    ## PRODUCES             ## UNDEFINED # Install protocol
>    ## PRODUCES             ## SystemTable
>    gPerformanceProtocolGuid
>    ## SOMETIMES_CONSUMES   ## HOB
>    ## PRODUCES             ## UNDEFINED # Install protocol
>    gPerformanceExProtocolGuid
> +  gZeroGuid                                     ## SOMETIMES_CONSUMES ## GUID
> +  gEfiFirmwarePerformanceGuid                   ## SOMETIMES_PRODUCES ## UNDEFINED # StatusCode Data
> +  gEdkiiExtendedFirmwarePerformanceGuid         ## SOMETIMES_CONSUMES ## HOB # StatusCode Data
> +  gEfiEventReadyToBootGuid                      ## CONSUMES           ## Event
> +  gEdkiiPiSmmCommunicationRegionTableGuid       ## SOMETIMES_CONSUMES    ## SystemTable
>
>  [Pcd]
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries   ## CONSUMES
> -  gEfiMdeModulePkgTokenSpaceGuid.PcdMaxPeiPerformanceLogEntries16 ## CONSUMES
> -  gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask      ## CONSUMES
> +  gEfiMdePkgTokenSpaceGuid.PcdPerformanceLibraryPropertyMask         ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdEdkiiFpdtStringRecordEnableOnly  ## CONSUMES
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdExtFpdtBootRecordPadSize         ## CONSUMES
> diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
> index f1540d8..7e79675 100644
> --- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
> +++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
> @@ -2,11 +2,11 @@
>    Master header files for DxeCorePerformanceLib instance.
>
>    This header file holds the prototypes of the Performance and PerformanceEx Protocol published by this
>    library instance at its constructor.
>
> -Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>
> +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
>  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
>
> @@ -20,21 +20,36 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
>
>
>  #include <PiDxe.h>
>
>  #include <Guid/Performance.h>
> +#include <Guid/ExtendedFirmwarePerformance.h>
> +#include <Guid/ZeroGuid.h>
> +#include <Guid/EventGroup.h>
> +#include <Guid/FirmwarePerformance.h>
> +#include <Guid/PiSmmCommunicationRegionTable.h>
> +
> +#include <Protocol/DriverBinding.h>
> +#include <Protocol/LoadedImage.h>
> +#include <Protocol/ComponentName2.h>
> +#include <Protocol/DevicePathToText.h>
> +#include <Protocol/SmmCommunication.h>
>
>  #include <Library/PerformanceLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/HobLib.h>
>  #include <Library/BaseLib.h>
>  #include <Library/BaseMemoryLib.h>
>  #include <Library/TimerLib.h>
>  #include <Library/PcdLib.h>
>  #include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/UefiLib.h>
> +#include <Library/ReportStatusCodeLib.h>
> +#include <Library/DxeServicesLib.h>
> +#include <Library/PeCoffGetEntryPointLib.h>
>
>  //
>  // Interface declarations for PerformanceEx Protocol.
>  //
>  /**
> --
> 1.9.5.msysgit.1
>
> _______________________________________________
> edk2-devel mailing list
> edk2-devel@lists.01.org
> https://lists.01.org/mailman/listinfo/edk2-devel


  reply	other threads:[~2018-05-01 16:26 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-01-30 13:53 [PATCH v2 0/8] Update EDKII Performance infrastructure based on ACPI FPDT table Dandan Bi
2018-01-30 13:53 ` [PATCH v2 1/8] MdeModulePkg:Add definitions for new Performance infrastructure Dandan Bi
2018-01-31  2:07   ` Zeng, Star
2018-01-30 13:53 ` [PATCH v2 2/8] MdeModulePkg/PeiPerformance:Updated to track FPDT record in PEI phase Dandan Bi
2018-01-30 13:53 ` [PATCH v2 3/8] MdeModulePkg/DxeCorePerformanceLib:Track FPDT record in DXE phase Dandan Bi
2018-05-01 16:26   ` Ard Biesheuvel [this message]
2018-05-22  0:33     ` Bi, Dandan
2018-05-22  8:51       ` Ard Biesheuvel
2018-05-22  8:58         ` Zeng, Star
2018-05-22  9:02           ` Ard Biesheuvel
2018-05-22  9:38             ` Zeng, Star
2018-05-22 10:00               ` Laszlo Ersek
2018-05-22 10:38                 ` Zeng, Star
2018-05-22 10:43                   ` Ard Biesheuvel
2018-05-22 10:00               ` Ard Biesheuvel
2018-01-30 13:53 ` [PATCH v2 4/8] MdeModulePkg/SmmCorePerformanceLib:Track FPDT record in SMM phase Dandan Bi
2018-01-30 13:53 ` [PATCH v2 5/8] MdeModulePkg/FirmwarePerformancePei:Add FPDT records for S3 phase Dandan Bi
2018-01-30 13:53 ` [PATCH v2 6/8] MdeModulePkg/FirmwarePerfDxe:Enhance for new pref infrastructure Dandan Bi
2018-01-30 13:53 ` [PATCH v2 7/8] MdeModulePkg/FirmwarePerfSmm:Enhance " Dandan Bi
2018-01-30 13:53 ` [PATCH v2 8/8] ShellPkg/Dp: Updated to dump perf log based on FPDT table Dandan Bi
2020-04-28  7:45 ` [edk2-devel] [PATCH v2 0/8] Update EDKII Performance infrastructure based on ACPI " boonewang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CAKv+Gu8eUd7S4or41HAiUfb49ROVzJ+xaZG3nq8C_EKktNc=gA@mail.gmail.com' \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox