Update the performance library instances in MdeModulePkg
to implement the APIs used for new added Perf macros.

V2:
Share the common logics of creating FPDT record for
new added Perf macros and existing Perf macros.

Cc: Liming Gao <liming....@intel.com>
Cc: Star Zeng <star.z...@intel.com>
Contributed-under: TianoCore Contribution Agreement 1.1
Signed-off-by: Dandan Bi <dandan...@intel.com>
---
 .../Include/Guid/ExtendedFirmwarePerformance.h     |   6 -
 .../DxeCorePerformanceLib/DxeCorePerformanceLib.c  | 864 +++++++++++++++------
 .../DxeCorePerformanceLib.inf                      |   1 +
 .../DxeCorePerformanceLibInternal.h                |   1 +
 .../Library/DxePerformanceLib/DxePerformanceLib.c  |  68 ++
 .../Library/PeiPerformanceLib/PeiPerformanceLib.c  | 632 +++++++++------
 .../SmmCorePerformanceLib/SmmCorePerformanceLib.c  | 645 +++++++++------
 .../Library/SmmPerformanceLib/SmmPerformanceLib.c  |  68 ++
 8 files changed, 1565 insertions(+), 720 deletions(-)

diff --git a/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h 
b/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h
index 465b4082750..dedb0b82f0d 100644
--- a/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h
+++ b/MdeModulePkg/Include/Guid/ExtendedFirmwarePerformance.h
@@ -218,16 +218,10 @@ typedef struct {
   CHAR8                                       String[0];
 } FPDT_GUID_QWORD_STRING_EVENT_RECORD;
 
 #pragma pack()
 
-typedef struct {
-  UINT16                                      ProgressID;
-  UINT16                                      Type;
-  UINT8                                       RecordSize;
-} FPDT_BASIC_RECORD_INFO;
-
 //
 // Union of all FPDT records
 //
 typedef union {
   EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER  RecordHeader;
diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c 
b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
index 79820605184..efff5134c7b 100644
--- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
+++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
@@ -69,17 +69,19 @@ UINTN           mCachePairCount = 0;
 UINT32  mLoadImageCount       = 0;
 UINT32  mPerformanceLength    = 0;
 UINT32  mMaxPerformanceLength = 0;
 UINT32  mBootRecordSize       = 0;
 UINT32  mBootRecordMaxSize    = 0;
+UINT32  mCachedLength         = 0;
 
 BOOLEAN mFpdtBufferIsReported = FALSE;
 BOOLEAN mLackSpaceIsReported  = FALSE;
 CHAR8   *mPlatformLanguage    = NULL;
 UINT8   *mPerformancePointer  = NULL;
 UINT8   *mBootRecordBuffer    = NULL;
 BOOLEAN  mLockInsertRecord    = FALSE;
+CHAR8   *mDevicePathString    = NULL;
 
 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL  *mDevicePathToText = NULL;
 
 //
 // Interfaces for PerformanceMeasurement Protocol.
@@ -88,10 +90,64 @@ EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL 
mPerformanceMeasurementInterface = {
   CreatePerformanceMeasurement,
   };
 
 PERFORMANCE_PROPERTY  mPerformanceProperty;
 
+/**
+  Return the pointer to the FPDT record in the allocated memory.
+
+  @param  RecordSize             The size of FPDT record.
+  @param  FpdtRecordPtr          Pointer the FPDT record in the allocated 
memory.
+
+  @retval EFI_SUCCESS            Successfully get the pointer to the FPDT 
record.
+  @retval EFI_OUT_OF_RESOURCES   Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+  IN     UINT8               RecordSize,
+  IN OUT FPDT_RECORD_PTR     *FpdtRecordPtr
+)
+{
+  if (mFpdtBufferIsReported) {
+    //
+    // Append Boot records to the boot performance table.
+    //
+    if (mBootRecordSize + RecordSize > 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
+      //
+      FpdtRecordPtr->RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + 
mBootRecordSize);
+    }
+  } else {
+    //
+    // Check if pre-allocated buffer is full
+    //
+    if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+      mPerformancePointer = ReallocatePool (
+                              mPerformanceLength,
+                              mPerformanceLength + RecordSize + 
FIRMWARE_RECORD_BUFFER,
+                              mPerformancePointer
+                              );
+      if (mPerformancePointer == NULL) {
+         return EFI_OUT_OF_RESOURCES;
+       }
+      mMaxPerformanceLength = mPerformanceLength + RecordSize + 
FIRMWARE_RECORD_BUFFER;
+    }
+    //
+    // Covert buffer to FPDT Ptr Union type.
+    //
+    FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)(mPerformancePointer + mPerformanceLength);
+  }
+  return EFI_SUCCESS;
+}
+
 /**
 Check whether the Token is a known one which is uesed by core.
 
 @param  Token      Pointer to a Null-terminated ASCII string
 
@@ -585,282 +641,355 @@ Done:
 
   return Status;
 }
 
 /**
-  Get the FPDT record info.
+  Get the FPDT record identifier.
 
-  @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  RecordInfo              On return, pointer to the info of the record.
-  @param  UseModuleName           Only useful for 
FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use
-                                  Module name to fill the string field in the 
FPDT_DYNAMIC_STRING_EVENT_RECORD.
+  @param Attribute                The attribute of the Record.
+                                  PerfStartEntry: Start Record.
+                                  PerfEndEntry: End Record.
+  @param  Handle                  Pointer to environment specific context used 
to identify the component being measured.
+  @param  String                  Pointer to a Null-terminated ASCII string 
that identifies the component being measured.
+  @param  ProgressID              On return, pointer to the ProgressID.
 
-  @retval EFI_SUCCESS          Get record info successfully.
-  @retval EFI_UNSUPPORTED      No matched FPDT record.
+  @retval EFI_SUCCESS              Get record info successfully.
+  @retval EFI_INVALID_PARAMETER    No matched FPDT record.
 
 **/
 EFI_STATUS
-GetFpdtRecordInfo (
-  IN BOOLEAN                  IsStart,
-  IN CONST VOID               *Handle,
-  IN CONST CHAR8              *Token,
-  IN CONST CHAR8              *Module,
-  OUT FPDT_BASIC_RECORD_INFO  *RecordInfo,
-  IN OUT BOOLEAN              *UseModuleName
+GetFpdtRecordId (
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute,
+  IN CONST VOID                       *Handle,
+  IN CONST CHAR8                      *String,
+  OUT UINT16                          *ProgressID
   )
 {
-  UINT16              RecordType;
-  UINTN               StringSize;
-
-  RecordType    = FPDT_DYNAMIC_STRING_EVENT_TYPE;
-
   //
-  // Token to Type and Id.
+  // Token to PerfId.
   //
-  if (Token != NULL) {
-    if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) {                // 
"StartImage:"
-      *UseModuleName = TRUE;
-      RecordType     = FPDT_GUID_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_START_ID;
+  if (String != NULL) {
+    if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {                // 
"StartImage:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_END_ID;
+        *ProgressID  = MODULE_END_ID;
       }
-    } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {          // 
"LoadImage:"
-      *UseModuleName = TRUE;
-      RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_START_ID;
+    } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {          // 
"LoadImage:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_LOADIMAGE_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_END_ID;
+        *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   = FPDT_GUID_QWORD_EVENT_TYPE;
+    } else if (AsciiStrCmp (String, DRIVERBINDING_START_TOK) == 0) {  // 
"DB:Start:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_DB_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_DB_END_ID;
-        RecordType   = FPDT_GUID_QWORD_STRING_EVENT_TYPE;
+        *ProgressID  = MODULE_DB_END_ID;
       }
-    } else if (AsciiStrCmp (Token, DRIVERBINDING_SUPPORT_TOK) == 0) { // 
"DB:Support:"
-      *UseModuleName = TRUE;
+    } else if (AsciiStrCmp (String, DRIVERBINDING_SUPPORT_TOK) == 0) { // 
"DB:Support:"
       if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
         return RETURN_UNSUPPORTED;
       }
-      RecordType     = FPDT_GUID_QWORD_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_DB_SUPPORT_START_ID;
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_DB_SUPPORT_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_DB_SUPPORT_END_ID;
+        *ProgressID  = MODULE_DB_SUPPORT_END_ID;
       }
-    } else if (AsciiStrCmp (Token, DRIVERBINDING_STOP_TOK) == 0) {    // 
"DB:Stop:"
-      *UseModuleName = TRUE;
+    } else if (AsciiStrCmp (String, DRIVERBINDING_STOP_TOK) == 0) {    // 
"DB:Stop:"
       if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
          return RETURN_UNSUPPORTED;
       }
-      RecordType     = FPDT_GUID_QWORD_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_DB_STOP_START_ID;
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_DB_STOP_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_DB_STOP_END_ID;
+        *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 if (AsciiStrCmp (String, PEI_TOK) == 0 ||                   // "PEI"
+               AsciiStrCmp (String, DXE_TOK) == 0 ||                   // "DXE"
+               AsciiStrCmp (String, BDS_TOK) == 0) {                   // "BDS"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = PERF_CROSSMODULE_START_ID;
       } else {
-        RecordInfo->ProgressID  = PERF_CROSSMODULE_END_ID;
+        *ProgressID  = PERF_CROSSMODULE_END_ID;
       }
     } else {                                                          // Pref 
used in Modules.
-      if (IsStart) {
-        RecordInfo->ProgressID  = PERF_INMODULE_START_ID;
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = PERF_INMODULE_START_ID;
       } else {
-        RecordInfo->ProgressID  = PERF_INMODULE_END_ID;
+        *ProgressID  = PERF_INMODULE_END_ID;
       }
     }
-  } else if (Handle!= NULL || Module != NULL) {                       // Pref 
used in Modules.
-    if (IsStart) {
-      RecordInfo->ProgressID    = PERF_INMODULE_START_ID;
+  } else if (Handle!= NULL) {                                         // Pref 
used in Modules.
+    if (Attribute == PerfStartEntry) {
+      *ProgressID    = PERF_INMODULE_START_ID;
     } else {
-      RecordInfo->ProgressID    = PERF_INMODULE_END_ID;
+      *ProgressID    = PERF_INMODULE_END_ID;
     }
   } else {
-    return EFI_UNSUPPORTED;
+    return EFI_INVALID_PARAMETER;
   }
+  return EFI_SUCCESS;
+}
+
+/**
+  Copies the string from Source into Destination and updates Length with the
+  size of the string.
+
+  @param Destination - destination of the string copy
+  @param Source      - pointer to the source string which will get copied
+  @param Length      - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+  IN OUT CHAR8  *Destination,
+  IN     CONST CHAR8  *Source,
+  IN OUT UINT8  *Length
+  )
+{
+  UINTN  StringLen;
+  UINTN  DestMax;
+
+  ASSERT (Source != NULL);
 
-  //
-  // Get Record size baesed on the record type.
-  // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with 
type of FPDT_DYNAMIC_STRING_EVENT_TYPE.
-  //
   if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
-    RecordType               = FPDT_DYNAMIC_STRING_EVENT_TYPE;
-    RecordInfo->RecordSize   = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE;
+    DestMax = STRING_SIZE;
   } else {
-    switch (RecordType) {
-    case FPDT_GUID_EVENT_TYPE:
-      RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
-      break;
-
-    case FPDT_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 
(FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);
-      break;
+    DestMax = AsciiStrSize (Source);
+    if (DestMax > STRING_SIZE) {
+      DestMax = STRING_SIZE;
+    }
+  }
+  StringLen = AsciiStrLen (Source);
+  if (StringLen >= DestMax) {
+    StringLen = DestMax -1;
+  }
+
+  AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+  *Length += (UINT8)DestMax;
+
+  return;
+}
+
+/**
+  Get a string description for device for the given controller handle and 
update record
+  length. If ComponentName2 GetControllerName is supported, the value is 
included in the string,
+  followed by device path, otherwise just device path.
 
-    case FPDT_GUID_QWORD_EVENT_TYPE:
-      RecordInfo->RecordSize = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
-      break;
+  @param Handle              - Image handle
+  @param ControllerHandle    - Controller handle.
+  @param ComponentNameString - Pointer to a location where the string will be 
saved
+  @param Length              - Pointer to record length to be updated
 
-    case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
-      RecordInfo->RecordSize = (UINT8)sizeof 
(FPDT_GUID_QWORD_STRING_EVENT_RECORD);
-      break;
+  @retval EFI_SUCCESS     - Successfully got string description for device
+  @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor 
DevicePath were found
 
-    default:
+**/
+EFI_STATUS
+GetDeviceInfoFromHandleAndUpdateLength (
+  IN CONST VOID        *Handle,
+  IN EFI_HANDLE        ControllerHandle,
+  OUT CHAR8            *ComponentNameString,
+  IN OUT UINT8         *Length
+  )
+{
+  EFI_DEVICE_PATH_PROTOCOL      *DevicePathProtocol;
+  EFI_COMPONENT_NAME2_PROTOCOL  *ComponentName2;
+  EFI_STATUS                    Status;
+  CHAR16                        *StringPtr;
+  CHAR8                         *AsciiStringPtr;
+  UINTN                         ControllerNameStringSize;
+  UINTN                         DevicePathStringSize;
+
+  ControllerNameStringSize = 0;
+
+  Status = gBS->HandleProtocol (
+                  (EFI_HANDLE) Handle,
+                  &gEfiComponentName2ProtocolGuid,
+                  (VOID **) &ComponentName2
+                  );
+
+  if (!EFI_ERROR(Status)) {
+    //
+    // Get the current platform language setting
+    //
+    if (mPlatformLanguage == NULL) {
+      GetEfiGlobalVariable2 (L"PlatformLang", (VOID **)&mPlatformLanguage, 
NULL);
+    }
+
+    Status = ComponentName2->GetControllerName (
+                               ComponentName2,
+                               ControllerHandle,
+                               NULL,
+                               mPlatformLanguage != NULL ? mPlatformLanguage : 
"en-US",
+                               &StringPtr
+                               );
+  }
+
+  if (!EFI_ERROR (Status)) {
+    //
+    // This will produce the size of the unicode string, which is twice as 
large as the ASCII one
+    // This must be an even number, so ok to divide by 2
+    //
+    ControllerNameStringSize = StrSize(StringPtr) / 2;
+
+    //
+    // The + 1 is because we want to add a space between the ControllerName 
and the device path
+    //
+    if ((ControllerNameStringSize + (*Length) + 1) > 
FPDT_MAX_PERF_RECORD_SIZE) {
       //
-      // Record is unsupported yet, return EFI_UNSUPPORTED
+      // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the record
       //
-      return EFI_UNSUPPORTED;
+      ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1;
     }
+
+    UnicodeStrToAsciiStrS(StringPtr, ComponentNameString, 
ControllerNameStringSize);
+
+    //
+    // Add a space in the end of the ControllerName
+    //
+    AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1;
+    *AsciiStringPtr = 0x20;
+    AsciiStringPtr++;
+    *AsciiStringPtr = 0;
+    ControllerNameStringSize++;
+
+    *Length += (UINT8)ControllerNameStringSize;
   }
 
-  RecordInfo->Type = RecordType;
-  return EFI_SUCCESS;
+  //
+  // This function returns the device path protocol from the handle specified 
by Handle.  If Handle is
+  // NULL or Handle does not contain a device path protocol, then NULL is 
returned.
+  //
+  DevicePathProtocol = DevicePathFromHandle(ControllerHandle);
+
+  if (DevicePathProtocol != NULL) {
+    StringPtr = ConvertDevicePathToText (DevicePathProtocol, TRUE, FALSE);
+    if (StringPtr != NULL) {
+      //
+      // This will produce the size of the unicode string, which is twice as 
large as the ASCII one
+      // This must be an even number, so ok to divide by 2
+      //
+      DevicePathStringSize = StrSize(StringPtr) / 2;
+
+      if ((DevicePathStringSize + (*Length)) > FPDT_MAX_PERF_RECORD_SIZE) {
+        //
+        // Only copy enough to fill FPDT_MAX_PERF_RECORD_SIZE worth of the 
record
+        //
+        DevicePathStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length);
+      }
+
+      if (ControllerNameStringSize != 0) {
+        AsciiStringPtr = ComponentNameString + ControllerNameStringSize - 1;
+      } else {
+        AsciiStringPtr = ComponentNameString;
+      }
+
+      UnicodeStrToAsciiStrS(StringPtr, AsciiStringPtr, DevicePathStringSize);
+      *Length += (UINT8)DevicePathStringSize;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_UNSUPPORTED;
 }
 
 /**
-  Add performance log to FPDT boot record table.
+  Create performance record with event description and a timestamp.
 
-  @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  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.
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID.
+  @param Guid              - Pointer to a GUID.
+  @param String            - Pointer to a string describing the measurement.
+  @param Ticker            - 64-bit time stamp.
+  @param Address           - Pointer to a location in memory relevant to the 
measurement.
+  @param PerfId            - Performance identifier describing the type of 
measurement.
+  @param Attribute         - The attribute of the measurement. According to 
attribute can create a start
+                             record for PERF_START/PERF_START_EX, or a end 
record for PERF_END/PERF_END_EX,
+                             or a general record for other Perf macros.
 
-  @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.
+  @retval EFI_SUCCESS           - Successfully created performance record.
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+                                  pointer or invalid PerfId.
+
+  @retval EFI_SUCCESS           - Successfully created performance record
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+                                  pointer or invalid PerfId
 
 **/
 EFI_STATUS
-InsertFpdtMeasurement (
-  IN BOOLEAN      IsStart,
-  IN CONST VOID   *Handle,  OPTIONAL
-  IN CONST CHAR8  *Token,   OPTIONAL
-  IN CONST CHAR8  *Module,  OPTIONAL
-  IN UINT64       Ticker,
-  IN UINT32       Identifier
+InsertFpdtRecord (
+  IN CONST VOID                        *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                        *Guid,    OPTIONAL
+  IN CONST CHAR8                       *String,  OPTIONAL
+  IN       UINT64                      Ticker,
+  IN       UINT64                      Address,  OPTIONAL
+  IN       UINT16                      PerfId,
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
   )
 {
   EFI_GUID                     ModuleGuid;
   CHAR8                        
ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
-  EFI_STATUS                   Status;
   FPDT_RECORD_PTR              FpdtRecordPtr;
-  FPDT_BASIC_RECORD_INFO       RecordInfo;
+  FPDT_RECORD_PTR              CachedFpdtRecordPtr;
   UINT64                       TimeStamp;
-  UINTN                        DestMax;
-  UINTN                        StrLength;
   CONST CHAR8                  *StringPtr;
-  BOOLEAN                      UseModuleName;
+  UINTN                        DestMax;
+  UINTN                        StringLen;
+  EFI_STATUS                   Status;
+  UINT16                       ProgressId;
 
   StringPtr     = NULL;
-  UseModuleName = FALSE;
+  ProgressId    = 0;
   ZeroMem (ModuleName, sizeof (ModuleName));
 
   //
-  // Get record info (type, size, ProgressID and Module Guid).
-  //
-  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, 
&UseModuleName);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // If PERF_START()/PERF_END() have specified the ProgressID,it has high 
priority.
-  // !!! Note: If the Perf 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.
+  // 1. Get the Perf Id for records from PERF_START/PERF_END, 
PERF_START_EX/PERF_END_EX.
+  //    notes: For other Perf macros (Attribute == PerfEntry), their Id is 
known.
   //
-  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) {
+  if (Attribute != PerfEntry) {
     //
-    // Append Boot records to the boot performance table.
+    // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has 
high priority.
+    // !!! Note: If the Perf 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 (mBootRecordSize + RecordInfo.RecordSize > mBootRecordMaxSize) {
-      if (!mLackSpaceIsReported) {
-        DEBUG ((DEBUG_INFO, "DxeCorePerformanceLib: No enough space to save 
boot records\n"));
-        mLackSpaceIsReported = TRUE;
+    if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+      return EFI_INVALID_PARAMETER;
+    } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens 
(String))) {
+      if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
+        PerfId &= 0xFFF0;
+      } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+        PerfId += 1;
       }
-      return EFI_OUT_OF_RESOURCES;
-    } else {
+    } else if (PerfId == 0) {
       //
-      // Save boot record into BootPerformance table
+      // Get ProgressID form the String Token.
       //
-      FpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + 
mBootRecordSize);
-      mBootRecordSize += RecordInfo.RecordSize;
-      mAcpiBootPerformanceTable->Header.Length += RecordInfo.RecordSize;
-    }
-  } else {
-    //
-    // Check if pre-allocated buffer is full
-    //
-    if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
-      mPerformancePointer = ReallocatePool (
-                              mPerformanceLength,
-                              mPerformanceLength + RecordInfo.RecordSize + 
FIRMWARE_RECORD_BUFFER,
-                              mPerformancePointer
-                              );
-
-      if (mPerformancePointer == NULL) {
-        return EFI_OUT_OF_RESOURCES;
+      Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, 
&ProgressId);
+      if (EFI_ERROR (Status)) {
+        return Status;
       }
-      mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + 
FIRMWARE_RECORD_BUFFER;
+      PerfId = ProgressId;
     }
-    //
-    // Covert buffer to FPDT Ptr Union type.
-    //
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)(mPerformancePointer + mPerformanceLength);
-    mPerformanceLength += RecordInfo.RecordSize;
   }
 
   //
-  // Get the TimeStamp.
+  // 2. Get the buffer to store the FPDT record.
+  //
+  Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  //3. Get the TimeStamp.
   //
   if (Ticker == 0) {
     Ticker    = GetPerformanceCounter ();
     TimeStamp = GetTimeInNanoSecond (Ticker);
   } else if (Ticker == 1) {
@@ -868,85 +997,252 @@ InsertFpdtMeasurement (
   } else {
     TimeStamp = GetTimeInNanoSecond (Ticker);
   }
 
   //
-  // Get the ModuleName and ModuleGuid form the handle.
-  //
-  GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof 
(ModuleName), &ModuleGuid);
-
-  //
-  // Fill in the record information.
+  // 4. Fill in the FPDT record according to different Performance Identifier.
   //
-  switch (RecordInfo.Type) {
-  case FPDT_GUID_EVENT_TYPE:
-    FpdtRecordPtr.GuidEvent->Header.Type                = FPDT_GUID_EVENT_TYPE;
-    FpdtRecordPtr.GuidEvent->Header.Length              = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.GuidEvent->Header.Revision            = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidEvent->ProgressID                 = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
-    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidEvent->Guid));
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    //
+    // Cache the offset of start image start record and use to update the 
start image end record if needed.
+    //
+    if (Attribute == PerfEntry && PerfId == MODULE_START_ID) {
+      if (mFpdtBufferIsReported) {
+        mCachedLength = mBootRecordSize;
+      } else {
+        mCachedLength = mPerformanceLength;
+      }
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidEvent->Header.Type                = 
FPDT_GUID_EVENT_TYPE;
+      FpdtRecordPtr.GuidEvent->Header.Length              = sizeof 
(FPDT_GUID_EVENT_RECORD);
+      FpdtRecordPtr.GuidEvent->Header.Revision            = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidEvent->ProgressID                 = PerfId;
+      FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
+      CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidEvent->Guid));
+      if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength 
!= 0) {
+        if (mFpdtBufferIsReported) {
+          CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + 
mCachedLength);
+        } else {
+          CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + 
mCachedLength);
+        }
+        CopyMem (&FpdtRecordPtr.GuidEvent->Guid, 
&CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+        mCachedLength = 0;
+      }
+    }
     break;
 
-  case FPDT_DYNAMIC_STRING_EVENT_TYPE:
-    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
-    FpdtRecordPtr.DynamicStringEvent->Header.Length     = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_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;
+  case MODULE_LOADIMAGE_START_ID:
+  case MODULE_LOADIMAGE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (PerfId == MODULE_LOADIMAGE_START_ID) {
+      mLoadImageCount ++;
+      //
+      // Cache the offset of load image start record and use to be updated by 
the load image end record if needed.
+      //
+      if (CallerIdentifier == NULL && Attribute == PerfEntry) {
+        if (mFpdtBufferIsReported) {
+          mCachedLength = mBootRecordSize;
+        } else {
+          mCachedLength = mPerformanceLength;
+        }
+      }
     }
-    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
-      StrLength     = AsciiStrLen (StringPtr);
-      DestMax       = (RecordInfo.RecordSize - sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
-      if (StrLength >= DestMax) {
-        StrLength   = DestMax -1;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = sizeof 
(FPDT_GUID_QWORD_EVENT_RECORD);
+      FpdtRecordPtr.GuidQwordEvent->Header.Revision       = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidQwordEvent->ProgressID            = PerfId;
+      FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
+      FpdtRecordPtr.GuidQwordEvent->Qword                 = mLoadImageCount;
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordEvent->Guid));
+      if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
+        if (mFpdtBufferIsReported) {
+          CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + 
mCachedLength);
+        } else {
+          CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + 
mCachedLength);
+        }
+        CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
+        mCachedLength = 0;
       }
-      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StrLength);
-    } else {
-      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, 
FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
     }
     break;
 
-  case FPDT_GUID_QWORD_EVENT_TYPE:
-    FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
-    FpdtRecordPtr.GuidQwordEvent->Header.Length         = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.GuidQwordEvent->Header.Revision       = 
FPDT_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;
+  case MODULE_DB_START_ID:
+  case MODULE_DB_SUPPORT_START_ID:
+  case MODULE_DB_SUPPORT_END_ID:
+  case MODULE_DB_STOP_START_ID:
+  case MODULE_DB_STOP_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = sizeof 
(FPDT_GUID_QWORD_EVENT_RECORD);
+      FpdtRecordPtr.GuidQwordEvent->Header.Revision       = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidQwordEvent->ProgressID            = PerfId;
+      FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
+      FpdtRecordPtr.GuidQwordEvent->Qword                 = Address;
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordEvent->Guid));
     }
     break;
 
-  case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
-    FpdtRecordPtr.GuidQwordStringEvent->Header.Type     = 
FPDT_GUID_QWORD_STRING_EVENT_TYPE;
-    FpdtRecordPtr.GuidQwordStringEvent->Header.Length   = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidQwordStringEvent->ProgressID      = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidQwordStringEvent->Timestamp       = TimeStamp;
-    CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordStringEvent->Guid));
+  case MODULE_DB_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordStringEvent->Header.Type     = 
FPDT_GUID_QWORD_STRING_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordStringEvent->Header.Length   = sizeof 
(FPDT_GUID_QWORD_STRING_EVENT_RECORD);;
+      FpdtRecordPtr.GuidQwordStringEvent->Header.Revision = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidQwordStringEvent->ProgressID      = PerfId;
+      FpdtRecordPtr.GuidQwordStringEvent->Timestamp       = TimeStamp;
+      FpdtRecordPtr.GuidQwordStringEvent->Qword           = Address;
+      CopyMem (&FpdtRecordPtr.GuidQwordStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordStringEvent->Guid));
+      if (Address != 0) {
+        GetDeviceInfoFromHandleAndUpdateLength(CallerIdentifier, 
(EFI_HANDLE)(UINTN)Address, FpdtRecordPtr.GuidQwordStringEvent->String, 
&FpdtRecordPtr.GuidQwordStringEvent->Header.Length);
+      }
+    }
     break;
 
-  default:
+  case PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
     //
-    // Record is not supported in current DXE phase, return EFI_ABORTED
+    // Cache the event guid in string event record when 
PcdEdkiiFpdtStringRecordEnableOnly == TRUE
     //
-    return EFI_UNSUPPORTED;
+    CopyGuid (&ModuleGuid, Guid);
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DualGuidStringEvent->Header.Type      = 
FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DualGuidStringEvent->Header.Length    = sizeof 
(FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DualGuidStringEvent->Header.Revision  = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DualGuidStringEvent->ProgressID       = PerfId;
+      FpdtRecordPtr.DualGuidStringEvent->Timestamp        = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, 
sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof 
(FpdtRecordPtr.DualGuidStringEvent->Guid2));
+      CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, 
&FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+    }
+    break;
+
+  case PERF_EVENT_ID:
+  case PERF_FUNCTION_START_ID:
+  case PERF_FUNCTION_END_ID:
+  case PERF_INMODULE_START_ID:
+  case PERF_INMODULE_END_ID:
+  case PERF_CROSSMODULE_START_ID:
+  case PERF_CROSSMODULE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    if (String != NULL) {
+      StringPtr = String;
+    } else {
+      StringPtr = ModuleName;
+    }
+    if (AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+      CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
+    }
+    break;
+
+  default:
+    if (Attribute != PerfEntry) {
+      GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+      if (String != NULL) {
+        StringPtr = String;
+      } else {
+        StringPtr = ModuleName;
+      }
+      if (AsciiStrLen (StringPtr) == 0) {
+        StringPtr = "unknown name";
+      }
+      if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+        FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+        FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+        FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+        FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+        CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
+      }
+    } else {
+      return EFI_INVALID_PARAMETER;
+    }
+    break;
+  }
+
+  //
+  // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record 
for all Perf entries.
+  //
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    if (StringPtr == NULL ||PerfId == MODULE_DB_SUPPORT_START_ID || PerfId == 
MODULE_DB_SUPPORT_END_ID) {
+      return EFI_INVALID_PARAMETER;
+    }
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+    if (AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
+    }
+    CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
+
+    if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
+    }
+    if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && 
mCachedLength != 0) {
+      if (mFpdtBufferIsReported) {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mBootRecordBuffer + 
mCachedLength);
+      } else {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(mPerformancePointer + 
mCachedLength);
+      }
+      if (PerfId == MODULE_LOADIMAGE_END_ID) {
+        DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - 
sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        StringLen = AsciiStrLen (StringPtr);
+        if (StringLen >= DestMax) {
+          StringLen = DestMax -1;
+        }
+        CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, 
DestMax, StringPtr, StringLen);
+      } else if (PerfId == MODULE_END_ID) {
+        DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        StringLen = AsciiStrLen 
(CachedFpdtRecordPtr.DynamicStringEvent->String);
+        if (StringLen >= DestMax) {
+          StringLen = DestMax -1;
+        }
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, 
&CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof 
(CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
+      }
+      mCachedLength = 0;
+    }
   }
 
+  //
+  // 5. Update the length of the used buffer after fill in the record.
+  //
+  if (mFpdtBufferIsReported) {
+    mBootRecordSize += FpdtRecordPtr.RecordHeader->Length;
+    mAcpiBootPerformanceTable->Header.Length += 
FpdtRecordPtr.RecordHeader->Length;
+  } else {
+    mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+  }
   return EFI_SUCCESS;
 }
 
 /**
   Dumps all the PEI performance.
@@ -1158,15 +1454,12 @@ CreatePerformanceMeasurement (
   if (mLockInsertRecord) {
     return EFI_INVALID_PARAMETER;
   }
   mLockInsertRecord = TRUE;
 
-  if (Attribute == PerfStartEntry) {
-    Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
-  } else if (Attribute == PerfEndEntry) {
-    Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
-  }
+  Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, 
Address, (UINT16)Identifier, Attribute);
+
   mLockInsertRecord = FALSE;
 
   return Status;
 }
 
@@ -1470,5 +1763,60 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
 }
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID
+  @param Guid              - Pointer to a GUID
+  @param String            - Pointer to a string describing the measurement
+  @param Address           - Pointer to a location in memory relevant to the 
measurement
+  @param Identifier        - Performance identifier describing the type of 
measurement
+
+  @retval RETURN_SUCCESS           - Successfully created performance record
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - 
NULL
+                                     pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+  IN CONST VOID   *CallerIdentifier,
+  IN CONST VOID   *Guid,    OPTIONAL
+  IN CONST CHAR8  *String,  OPTIONAL
+  IN UINT64       Address, OPTIONAL
+  IN UINT32       Identifier
+  )
+{
+  return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, 
String, 0, Address, Identifier, PerfEntry);
+}
+
+/**
+  Check whether the specified performance measurement can be logged.
+
+  This function returns TRUE when the 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of 
PcdPerformanceLibraryPropertyMask is set
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+  @param Type        - Type of the performance measurement entry.
+
+  @retval TRUE         The performance measurement can be logged.
+  @retval FALSE        The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+  IN  CONST UINTN        Type
+  )
+{
+  //
+  // When Performance measurement is enabled and the type is not filtered, the 
performance can be logged.
+  //
+  if (PerformanceMeasurementEnabled () && 
(PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git 
a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf 
b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
index 68cd76da5b3..3e77f9cd57a 100644
--- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
+++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.inf
@@ -59,10 +59,11 @@
   DebugLib
   UefiLib
   ReportStatusCodeLib
   DxeServicesLib
   PeCoffGetEntryPointLib
+  DevicePathLib
 
 [Protocols]
   gEfiSmmCommunicationProtocolGuid              ## SOMETIMES_CONSUMES
 
 
diff --git 
a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h 
b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
index f9800e34941..a96f4081503 100644
--- a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
+++ b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLibInternal.h
@@ -40,10 +40,11 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #include <Library/HobLib.h>
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/TimerLib.h>
 #include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
 #include <Library/UefiBootServicesTableLib.h>
 #include <Library/UefiRuntimeServicesTableLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiLib.h>
 #include <Library/ReportStatusCodeLib.h>
diff --git a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c 
b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
index 9ed50d22b8d..664e8261af9 100644
--- a/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
+++ b/MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.c
@@ -376,5 +376,73 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
 }
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID
+  @param Guid              - Pointer to a GUID
+  @param String            - Pointer to a string describing the measurement
+  @param Address           - Pointer to a location in memory relevant to the 
measurement
+  @param Identifier        - Performance identifier describing the type of 
measurement
+
+  @retval RETURN_SUCCESS           - Successfully created performance record
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - 
NULL
+                                     pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+  IN CONST VOID   *CallerIdentifier,
+  IN CONST VOID   *Guid,    OPTIONAL
+  IN CONST CHAR8  *String,  OPTIONAL
+  IN  UINT64       Address, OPTIONAL
+  IN UINT32       Identifier
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GetPerformanceMeasurementProtocol ();
+  if (EFI_ERROR (Status)) {
+    return RETURN_OUT_OF_RESOURCES;
+  }
+
+  if (mPerformanceMeasurement != NULL) {
+    Status = mPerformanceMeasurement->CreatePerformanceMeasurement 
(CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+  } else {
+    ASSERT (FALSE);
+  }
+
+  return (RETURN_STATUS) Status;
+}
+
+/**
+  Check whether the specified performance measurement can be logged.
+
+  This function returns TRUE when the 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of 
PcdPerformanceLibraryPropertyMask is set
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+  @param Type        - Type of the performance measurement entry.
+
+  @retval TRUE         The performance measurement can be logged.
+  @retval FALSE        The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+  IN  CONST UINTN        Type
+  )
+{
+  //
+  // When Performance measurement is enabled and the type is not filtered, the 
performance can be logged.
+  //
+  if (PerformanceMeasurementEnabled () && 
(PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c 
b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
index f770a35a995..cd1b0e34ef7 100644
--- a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
+++ b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
@@ -21,21 +21,100 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 
 
 #include <PiPei.h>
 
 #include <Guid/ExtendedFirmwarePerformance.h>
+#include <Guid/PerformanceMeasurement.h>
 
 #include <Library/PerformanceLib.h>
 #include <Library/DebugLib.h>
 #include <Library/HobLib.h>
 #include <Library/BaseLib.h>
 #include <Library/TimerLib.h>
 #include <Library/PcdLib.h>
 #include <Library/BaseMemoryLib.h>
 
 #define  STRING_SIZE            (FPDT_STRING_EVENT_RECORD_NAME_LENGTH * sizeof 
(CHAR8))
-#define  MAX_RECORD_SIZE        (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE)
+#define  PEI_MAX_RECORD_SIZE    (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + 
STRING_SIZE)
+
+
+/**
+  Return the pointer to the FPDT record in the allocated memory.
+
+  @param  RecordSize                The size of FPDT record.
+  @param  FpdtRecordPtr             Pointer the FPDT record in the allocated 
memory.
+  @param  PeiPerformanceLogHeader   Pointer to the header of the PEI 
Performance records in the GUID Hob.
+
+  @retval EFI_SUCCESS               Successfully get the pointer to the FPDT 
record.
+  @retval EFI_OUT_OF_RESOURCES      Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+  IN     UINT8                     RecordSize,
+  IN OUT FPDT_RECORD_PTR           *FpdtRecordPtr,
+  IN OUT FPDT_PEI_EXT_PERF_HEADER  **PeiPerformanceLogHeader
+)
+{
+  UINT16                                PeiPerformanceLogEntries;
+  UINTN                                 PeiPerformanceSize;
+  UINT8                                 *PeiFirmwarePerformance;
+  EFI_HOB_GUID_TYPE                     *GuidHob;
+
+  //
+  // Get the number of PeiPerformanceLogEntries form PCD.
+  //
+  PeiPerformanceLogEntries = (UINT16) (PcdGet16 
(PcdMaxPeiPerformanceLogEntries16) != 0 ?
+                                       PcdGet16 
(PcdMaxPeiPerformanceLogEntries16) :
+                                       PcdGet8 
(PcdMaxPeiPerformanceLogEntries));
+
+  //
+  // Create GUID HOB Data.
+  //
+  GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);
+  PeiFirmwarePerformance = NULL;
+  while (GuidHob != NULL) {
+    //
+    // PEI Performance HOB was found, then return the existing one.
+    //
+    PeiFirmwarePerformance  = (UINT8*)GET_GUID_HOB_DATA (GuidHob);
+    *PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER 
*)PeiFirmwarePerformance;
+    if (!(*PeiPerformanceLogHeader)->HobIsFull && 
(*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize > 
(UINTN)(PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {
+      (*PeiPerformanceLogHeader)->HobIsFull = TRUE;
+    }
+    if (!(*PeiPerformanceLogHeader)->HobIsFull && 
(*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= 
(UINTN)(PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE)) {
+      FpdtRecordPtr->RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof 
(FPDT_PEI_EXT_PERF_HEADER) + (*PeiPerformanceLogHeader)->SizeOfAllEntries);
+      break;
+    }
+    //
+    // Previous HOB is used, then find next one.
+    //
+    GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, 
GET_NEXT_HOB (GuidHob));
+  }
+
+  if (GuidHob == NULL) {
+    //
+    // PEI Performance HOB was not found, then build one.
+    //
+    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +
+                              PEI_MAX_RECORD_SIZE * PeiPerformanceLogEntries;
+    PeiFirmwarePerformance  = (UINT8*)BuildGuidHob 
(&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);
+    if (PeiFirmwarePerformance != NULL) {
+      ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);
+      (*PeiPerformanceLogHeader) = (FPDT_PEI_EXT_PERF_HEADER 
*)PeiFirmwarePerformance;
+      FpdtRecordPtr->RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof 
(FPDT_PEI_EXT_PERF_HEADER));
+    }
+  }
+
+  if (PeiFirmwarePerformance == NULL) {
+    //
+    // there is no enough resource to store performance data
+    //
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  return EFI_SUCCESS;
+}
 
 /**
 Check whether the Token is a known one which is uesed by core.
 
 @param  Token      Pointer to a Null-terminated ASCII string
@@ -98,252 +177,197 @@ IsKnownID (
     return FALSE;
   }
 }
 
 /**
-  Get the FPDT record info.
+  Get the FPDT record identifier.
 
-  @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  RecordInfo              On return, pointer to the info of the record.
+  @param Attribute                The attribute of the Record.
+                                  PerfStartEntry: Start Record.
+                                  PerfEndEntry: End Record.
+  @param  Handle                  Pointer to environment specific context used 
to identify the component being measured.
+  @param  String                  Pointer to a Null-terminated ASCII string 
that identifies the component being measured.
+  @param  ProgressID              On return, pointer to the ProgressID.
 
-  @retval EFI_SUCCESS             Get record info successfully.
-  @retval EFI_UNSUPPORTED         No matched FPDT record.
+  @retval EFI_SUCCESS              Get record info successfully.
+  @retval EFI_INVALID_PARAMETER    No matched FPDT record.
 
 **/
 EFI_STATUS
-GetFpdtRecordInfo (
-  IN BOOLEAN                 IsStart,
+GetFpdtRecordId (
+  IN BOOLEAN                 Attribute,
   IN CONST VOID              *Handle,
-  IN CONST CHAR8             *Token,
-  IN CONST CHAR8             *Module,
-  OUT FPDT_BASIC_RECORD_INFO *RecordInfo
+  IN CONST CHAR8             *String,
+  OUT UINT16                 *ProgressID
   )
 {
-  UINTN     StringSize;
-  UINT16    RecordType;
-
-  RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
-
   //
   // Get the ProgressID based on the Token.
   // When PcdEdkiiFpdtStringRecordEnableOnly is TRUE, all records are with 
type of FPDT_DYNAMIC_STRING_EVENT_TYPE.
   //
-  if (Token != NULL) {
-    if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {               // 
"LoadImage:"
-      if (IsStart) {
-        RecordInfo->ProgressID = MODULE_LOADIMAGE_START_ID;
+  if (String != NULL) {
+    if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {               // 
"LoadImage:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID = MODULE_LOADIMAGE_START_ID;
       } else {
-        RecordInfo->ProgressID = MODULE_LOADIMAGE_END_ID;
+        *ProgressID = MODULE_LOADIMAGE_END_ID;
       }
-      if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
-        RecordType = FPDT_GUID_QWORD_EVENT_TYPE;
-      }
-    } else if (AsciiStrCmp (Token, SEC_TOK) == 0 ||               // "SEC"
-               AsciiStrCmp (Token, PEI_TOK) == 0) {               // "PEI"
-      if (IsStart) {
-        RecordInfo->ProgressID = PERF_CROSSMODULE_START_ID;
+    } else if (AsciiStrCmp (String, SEC_TOK) == 0 ||               // "SEC"
+               AsciiStrCmp (String, PEI_TOK) == 0) {               // "PEI"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID = PERF_CROSSMODULE_START_ID;
       } else {
-        RecordInfo->ProgressID = PERF_CROSSMODULE_END_ID;
+        *ProgressID = PERF_CROSSMODULE_END_ID;
       }
-    } else if (AsciiStrCmp (Token, PEIM_TOK) == 0) {              // "PEIM"
-      if (IsStart) {
-        RecordInfo->ProgressID = MODULE_START_ID;
+    } else if (AsciiStrCmp (String, PEIM_TOK) == 0) {              // "PEIM"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID = MODULE_START_ID;
       } else {
-        RecordInfo->ProgressID = MODULE_END_ID;
-      }
-      if(!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
-        RecordType = FPDT_GUID_EVENT_TYPE;
+        *ProgressID = MODULE_END_ID;
       }
     } else {                                                      //Pref used 
in Modules.
-      if (IsStart) {
-        RecordInfo->ProgressID = PERF_INMODULE_START_ID;
+      if (Attribute == PerfStartEntry) {
+        *ProgressID = PERF_INMODULE_START_ID;
       } else {
-        RecordInfo->ProgressID = PERF_INMODULE_END_ID;
+        *ProgressID = PERF_INMODULE_END_ID;
       }
     }
-  } else if (Module != NULL || Handle != NULL) {                  //Pref used 
in Modules.
-    if (IsStart) {
-      RecordInfo->ProgressID = PERF_INMODULE_START_ID;
+  } else if (Handle != NULL) {                                    //Pref used 
in Modules.
+    if (Attribute == PerfStartEntry) {
+      *ProgressID = PERF_INMODULE_START_ID;
     } else {
-      RecordInfo->ProgressID = PERF_INMODULE_END_ID;
+      *ProgressID = PERF_INMODULE_END_ID;
     }
   } else {
-    return EFI_UNSUPPORTED;
+    return EFI_INVALID_PARAMETER;
   }
 
-  //
-  // Get the Guid and string.
-  //
-  if(PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
-    RecordInfo->RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE;
-  } else {
-    switch (RecordType) {
-    case FPDT_GUID_EVENT_TYPE:
-      RecordInfo->RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
-      break;
+  return EFI_SUCCESS;
+}
 
-    case FPDT_GUID_QWORD_EVENT_TYPE:
-      RecordInfo->RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
-      break;
+/**
+  Copies the string from Source into Destination and updates Length with the
+  size of the string.
 
-    case FPDT_DYNAMIC_STRING_EVENT_TYPE:
-      if (Token != NULL) {
-        StringSize = AsciiStrSize (Token);
-      } else if (Module != NULL) {
-        StringSize = AsciiStrSize (Module);
-      } else {
-        StringSize = STRING_SIZE;
-      }
-      RecordInfo->RecordSize  = (UINT8)(sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);
-      break;
+  @param Destination - destination of the string copy
+  @param Source      - pointer to the source string which will get copied
+  @param Length      - pointer to a length variable to be updated
 
-    default:
-      //
-      // Other type is unsupported in PEI phase yet, return EFI_UNSUPPORTED
-      //
-      return EFI_UNSUPPORTED;
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+  IN OUT CHAR8  *Destination,
+  IN     CONST CHAR8  *Source,
+  IN OUT UINT8  *Length
+  )
+{
+  UINTN  StringLen;
+  UINTN  DestMax;
+
+  ASSERT (Source != NULL);
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    DestMax = STRING_SIZE;
+  } else {
+    DestMax = AsciiStrSize (Source);
+    if (DestMax > STRING_SIZE) {
+      DestMax = STRING_SIZE;
     }
   }
-  RecordInfo->Type = RecordType;
-  return EFI_SUCCESS;
+  StringLen = AsciiStrLen (Source);
+  if (StringLen >= DestMax) {
+    StringLen = DestMax -1;
+  }
+
+  AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+  *Length += (UINT8)DestMax;
+
+  return;
 }
 
+
 /**
   Convert PEI performance log to FPDT String boot record.
 
-  @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  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              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.
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID.
+  @param Guid              - Pointer to a GUID.
+  @param String            - Pointer to a string describing the measurement.
+  @param Ticker            - 64-bit time stamp.
+  @param Address           - Pointer to a location in memory relevant to the 
measurement.
+  @param PerfId            - Performance identifier describing the type of 
measurement.
+  @param Attribute         - The attribute of the measurement. According to 
attribute can create a start
+                             record for PERF_START/PERF_START_EX, or a end 
record for PERF_END/PERF_END_EX,
+                             or a general record for other Perf macros.
+
+  @retval EFI_SUCCESS           - Successfully created performance record.
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+                                  pointer or invalid PerfId.
 
 **/
 EFI_STATUS
-InsertPeiFpdtMeasurement (
-  IN BOOLEAN      IsStart,
-  IN CONST VOID   *Handle,  OPTIONAL
-  IN CONST CHAR8  *Token,   OPTIONAL
-  IN CONST CHAR8  *Module,  OPTIONAL
-  IN UINT64       Ticker,
-  IN UINT32       Identifier
+InsertFpdtRecord (
+  IN CONST VOID                        *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                        *Guid,    OPTIONAL
+  IN CONST CHAR8                       *String,  OPTIONAL
+  IN       UINT64                      Ticker,
+  IN       UINT64                      Address,  OPTIONAL
+  IN       UINT16                      PerfId,
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
   )
 {
-  EFI_HOB_GUID_TYPE                     *GuidHob;
-  UINTN                                 PeiPerformanceSize;
-  UINT8                                 *PeiFirmwarePerformance;
-  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;
   FPDT_RECORD_PTR                       FpdtRecordPtr;
-  FPDT_BASIC_RECORD_INFO                RecordInfo;
   CONST VOID                            *ModuleGuid;
-  UINTN                                 DestMax;
-  UINTN                                 StrLength;
   CONST CHAR8                           *StringPtr;
   EFI_STATUS                            Status;
-  UINT16                                PeiPerformanceLogEntries;
   UINT64                                TimeStamp;
+  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;
 
   StringPtr = NULL;
   FpdtRecordPtr.RecordHeader = NULL;
   PeiPerformanceLogHeader = NULL;
 
   //
-  // Get record info (type, size, ProgressID and Module Guid).
-  //
-  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // If PERF_START()/PERF_END() have specified the ProgressID,it has high 
priority.
-  // !!! Note: If the Perf 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.
+  // 1. Get the Perf Id for records from PERF_START/PERF_END, 
PERF_START_EX/PERF_END_EX.
+  //    notes: For other Perf macros (Attribute == PerfEntry), their Id is 
known.
   //
-  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;
-  }
-
-  //
-  // Get the number of PeiPerformanceLogEntries form PCD.
-  //
-  PeiPerformanceLogEntries = (UINT16) (PcdGet16 
(PcdMaxPeiPerformanceLogEntries16) != 0 ?
-                                       PcdGet16 
(PcdMaxPeiPerformanceLogEntries16) :
-                                       PcdGet8 
(PcdMaxPeiPerformanceLogEntries));
-
-  //
-  // Create GUID HOB Data.
-  //
-  GuidHob = GetFirstGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid);
-  PeiFirmwarePerformance = NULL;
-  while (GuidHob != NULL) {
-    //
-    // PEI Performance HOB was found, then return the existing one.
-    //
-    PeiFirmwarePerformance  = (UINT8*)GET_GUID_HOB_DATA (GuidHob);
-    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER 
*)PeiFirmwarePerformance;
-    if (!PeiPerformanceLogHeader->HobIsFull && 
PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize > 
PeiPerformanceLogEntries * MAX_RECORD_SIZE) {
-      PeiPerformanceLogHeader->HobIsFull = TRUE;
-    }
-    if (!PeiPerformanceLogHeader->HobIsFull && 
PeiPerformanceLogHeader->SizeOfAllEntries + RecordInfo.RecordSize <= 
PeiPerformanceLogEntries * MAX_RECORD_SIZE) {
-      FpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)(PeiFirmwarePerformance + sizeof 
(FPDT_PEI_EXT_PERF_HEADER) + PeiPerformanceLogHeader->SizeOfAllEntries);
-      break;
-    }
-    //
-    // Previous HOB is used, then find next one.
-    //
-    GuidHob = GetNextGuidHob (&gEdkiiFpdtExtendedFirmwarePerformanceGuid, 
GET_NEXT_HOB (GuidHob));
-  }
-
-  if (GuidHob == NULL) {
+  if (Attribute != PerfEntry) {
     //
-    // PEI Performance HOB was not found, then build one.
+    // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has 
high priority.
+    // !!! Note: If the Perf 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.
     //
-    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +
-                              MAX_RECORD_SIZE * PeiPerformanceLogEntries;
-    PeiFirmwarePerformance  = (UINT8*)BuildGuidHob 
(&gEdkiiFpdtExtendedFirmwarePerformanceGuid, PeiPerformanceSize);
-    if (PeiFirmwarePerformance != NULL) {
-      ZeroMem (PeiFirmwarePerformance, PeiPerformanceSize);
+    if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+      return EFI_UNSUPPORTED;
+    } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens 
(String))) {
+      if (Attribute == PerfStartEntry && ((PerfId & 0x000F) != 0)) {
+        PerfId &= 0xFFF0;
+      } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+        PerfId += 1;
+      }
+    } else if (PerfId == 0) {
+      Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, &PerfId);
+      if (EFI_ERROR (Status)) {
+        return Status;
+      }
     }
-    PeiPerformanceLogHeader = (FPDT_PEI_EXT_PERF_HEADER 
*)PeiFirmwarePerformance;
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)(PeiFirmwarePerformance + sizeof (FPDT_PEI_EXT_PERF_HEADER));
   }
 
-  if (PeiFirmwarePerformance == NULL) {
-    //
-    // there is no enough resource to store performance data
-    //
-    return EFI_OUT_OF_RESOURCES;
+  //
+  // 2. Get the buffer to store the FPDT record.
+  //
+  Status = GetFpdtRecordPtr (PEI_MAX_RECORD_SIZE, &FpdtRecordPtr, 
&PeiPerformanceLogHeader);
+  if (EFI_ERROR (Status)) {
+    return Status;
   }
 
   //
-  // Get the TimeStamp.
+  // 3 Get the TimeStamp.
   //
   if (Ticker == 0) {
     Ticker    = GetPerformanceCounter ();
     TimeStamp = GetTimeInNanoSecond (Ticker);
   } else if (Ticker == 1) {
@@ -351,74 +375,142 @@ InsertPeiFpdtMeasurement (
   } else {
     TimeStamp = GetTimeInNanoSecond (Ticker);
   }
 
   //
-  // Get the ModuleGuid.
+  // 4.Get the ModuleGuid.
   //
-  if (Handle != NULL) {
-    ModuleGuid = Handle;
+  if (CallerIdentifier != NULL) {
+    ModuleGuid = CallerIdentifier;
   } else {
     ModuleGuid = &gEfiCallerIdGuid;
   }
 
-  switch (RecordInfo.Type) {
-  case FPDT_GUID_EVENT_TYPE:
-    FpdtRecordPtr.GuidEvent->Header.Type       = FPDT_GUID_EVENT_TYPE;
-    FpdtRecordPtr.GuidEvent->Header.Length     = RecordInfo.RecordSize;;
-    FpdtRecordPtr.GuidEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidEvent->ProgressID        = RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidEvent->Timestamp         = TimeStamp;
-    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;
+  //
+  // 5. Fill in the FPDT record according to different Performance Identifier.
+  //
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    StringPtr = PEIM_TOK;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidEvent->Header.Type       = FPDT_GUID_EVENT_TYPE;
+      FpdtRecordPtr.GuidEvent->Header.Length     = sizeof 
(FPDT_GUID_EVENT_RECORD);
+      FpdtRecordPtr.GuidEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.GuidEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.GuidEvent->Guid, ModuleGuid, sizeof (EFI_GUID));
+    }
     break;
 
-  case FPDT_GUID_QWORD_EVENT_TYPE:
-    FpdtRecordPtr.GuidQwordEvent->Header.Type     = FPDT_GUID_QWORD_EVENT_TYPE;
-    FpdtRecordPtr.GuidQwordEvent->Header.Length   = RecordInfo.RecordSize;;
-    FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidQwordEvent->ProgressID      = RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidQwordEvent->Timestamp       = TimeStamp;
-    PeiPerformanceLogHeader->LoadImageCount++;
-    FpdtRecordPtr.GuidQwordEvent->Qword           = 
PeiPerformanceLogHeader->LoadImageCount;
-    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof 
(EFI_GUID));
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;
+  case MODULE_LOADIMAGE_START_ID:
+  case MODULE_LOADIMAGE_END_ID:
+    StringPtr = LOAD_IMAGE_TOK;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type     = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length   = sizeof 
(FPDT_GUID_QWORD_EVENT_RECORD);
+      FpdtRecordPtr.GuidQwordEvent->Header.Revision = FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidQwordEvent->ProgressID      = PerfId;
+      FpdtRecordPtr.GuidQwordEvent->Timestamp       = TimeStamp;
+      if (PerfId == MODULE_LOADIMAGE_START_ID) {
+        PeiPerformanceLogHeader->LoadImageCount++;
+      }
+      FpdtRecordPtr.GuidQwordEvent->Qword           = 
PeiPerformanceLogHeader->LoadImageCount;
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, ModuleGuid, sizeof 
(EFI_GUID));
+    }
     break;
 
-  case FPDT_DYNAMIC_STRING_EVENT_TYPE:
-    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
-    FpdtRecordPtr.DynamicStringEvent->Header.Length     = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.DynamicStringEvent->ProgressID        = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
-    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof 
(EFI_GUID));
-    PeiPerformanceLogHeader->SizeOfAllEntries += RecordInfo.RecordSize;
-
-    if (Token != NULL) {
-      StringPtr                     = Token;
-    } else if (Module != NULL) {
-      StringPtr                     = Module;
+  case PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (String != NULL && AsciiStrLen (String) != 0) {
+      StringPtr = String;
+    } else {
+      StringPtr = "unknown name";
     }
-    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
-      DestMax                       = (RecordInfo.RecordSize - sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
-      StrLength                     = AsciiStrLen (StringPtr);
-      if (StrLength >= DestMax) {
-        StrLength                   = DestMax -1;
-      }
-      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StrLength);
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DualGuidStringEvent->Header.Type      = 
FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DualGuidStringEvent->Header.Length    = sizeof 
(FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DualGuidStringEvent->Header.Revision  = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DualGuidStringEvent->ProgressID       = PerfId;
+      FpdtRecordPtr.DualGuidStringEvent->Timestamp        = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, ModuleGuid, sizeof 
(FpdtRecordPtr.DualGuidStringEvent->Guid1));
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof 
(FpdtRecordPtr.DualGuidStringEvent->Guid2));
+    }
+    break;
+
+  case PERF_EVENT_ID:
+  case PERF_FUNCTION_START_ID:
+  case PERF_FUNCTION_END_ID:
+  case PERF_INMODULE_START_ID:
+  case PERF_INMODULE_END_ID:
+  case PERF_CROSSMODULE_START_ID:
+  case PERF_CROSSMODULE_END_ID:
+    if (String != NULL && AsciiStrLen (String) != 0) {
+      StringPtr = String;
     } else {
-      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, 
FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
+      StringPtr = "unknown name";
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof 
(EFI_GUID));
+      CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
     }
     break;
 
   default:
-    //
-    // Record is not supported in current PEI phase, return EFI_ABORTED
-    //
-    return EFI_UNSUPPORTED;
+    if (Attribute != PerfEntry) {
+     if (String != NULL && AsciiStrLen (String) != 0) {
+       StringPtr = String;
+     } else {
+       StringPtr = "unknown name";
+     }
+     if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+       FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+       FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+       FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+       FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+       FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+       CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+       CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
+     }
+  } else {
+    return EFI_INVALID_PARAMETER;
+  }
+   break;
+  }
+
+  //
+  // 5.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record 
for all Perf entries.
+  //
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+    if (Guid != NULL) {
+      //
+      // Cache the event guid in string event record.
+      //
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, Guid, sizeof 
(EFI_GUID));
+    } else {
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, ModuleGuid, sizeof 
(EFI_GUID));
+    }
+    CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
   }
 
+  //
+  // 6. Update the length of the used buffer after fill in the record.
+  //
+  PeiPerformanceLogHeader->SizeOfAllEntries += 
FpdtRecordPtr.RecordHeader->Length;
+
   return EFI_SUCCESS;
 }
 
 /**
   Creates a record for the beginning of a performance measurement.
@@ -452,11 +544,22 @@ StartPerformanceMeasurementEx (
   IN CONST CHAR8  *Module,  OPTIONAL
   IN UINT64       TimeStamp,
   IN UINT32       Identifier
   )
 {
-  return InsertPeiFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 
Identifier);
+  CONST CHAR8     *String;
+
+  if (Token != NULL) {
+    String = Token;
+  } else if (Module != NULL) {
+    String = Module;
+  } else {
+    String = NULL;
+  }
+
+  return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, 
(UINT16)Identifier, PerfStartEntry);
+
 }
 
 /**
 
   Creates a record for the end of a performance measurement.
@@ -487,11 +590,21 @@ EndPerformanceMeasurementEx (
   IN CONST CHAR8  *Module,  OPTIONAL
   IN UINT64       TimeStamp,
   IN UINT32       Identifier
   )
 {
-  return InsertPeiFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 
Identifier);
+  CONST CHAR8     *String;
+
+  if (Token != NULL) {
+    String = Token;
+  } else if (Module != NULL) {
+    String = Module;
+  } else {
+    String = NULL;
+  }
+
+  return (RETURN_STATUS)InsertFpdtRecord (Handle, NULL, String, TimeStamp, 0, 
(UINT16)Identifier, PerfEndEntry);
 }
 
 /**
   Attempts to retrieve a performance measurement log entry from the 
performance measurement log.
   It can also retrieve the log created by StartPerformanceMeasurement and 
EndPerformanceMeasurement,
@@ -580,11 +693,11 @@ StartPerformanceMeasurement (
   IN CONST CHAR8  *Token,   OPTIONAL
   IN CONST CHAR8  *Module,  OPTIONAL
   IN UINT64       TimeStamp
   )
 {
-  return InsertPeiFpdtMeasurement (TRUE, Handle, Token, Module, TimeStamp, 0);
+  return StartPerformanceMeasurementEx (Handle, Token, Module, TimeStamp, 0);
 }
 
 /**
 
   Creates a record for the end of a performance measurement.
@@ -612,11 +725,11 @@ EndPerformanceMeasurement (
   IN CONST CHAR8  *Token,   OPTIONAL
   IN CONST CHAR8  *Module,  OPTIONAL
   IN UINT64       TimeStamp
   )
 {
-  return InsertPeiFpdtMeasurement (FALSE, Handle, Token, Module, TimeStamp, 0);
+  return EndPerformanceMeasurementEx (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,
@@ -690,5 +803,60 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
 }
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID
+  @param Guid              - Pointer to a GUID
+  @param String            - Pointer to a string describing the measurement
+  @param Address           - Pointer to a location in memory relevant to the 
measurement
+  @param Identifier        - Performance identifier describing the type of 
measurement
+
+  @retval RETURN_SUCCESS           - Successfully created performance record
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - 
NULL
+                                     pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+  IN CONST VOID   *CallerIdentifier,
+  IN CONST VOID   *Guid,    OPTIONAL
+  IN CONST CHAR8  *String,  OPTIONAL
+  IN UINT64       Address, OPTIONAL
+  IN UINT32       Identifier
+  )
+{
+  return (RETURN_STATUS)InsertFpdtRecord (CallerIdentifier, Guid, String, 0, 
Address, (UINT16)Identifier, PerfEntry);
+}
+
+/**
+  Check whether the specified performance measurement can be logged.
+
+  This function returns TRUE when the 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of 
PcdPerformanceLibraryPropertyMask is set
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+  @param Type        - Type of the performance measurement entry.
+
+  @retval TRUE         The performance measurement can be logged.
+  @retval FALSE        The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+  IN  CONST UINTN        Type
+  )
+{
+  //
+  // When Performance measurement is enabled and the type is not filtered, the 
performance can be logged.
+  //
+  if (PerformanceMeasurementEnabled () && 
(PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
diff --git a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c 
b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
index e630773562f..0c00fb51e82 100644
--- a/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
+++ b/MdeModulePkg/Library/SmmCorePerformanceLib/SmmCorePerformanceLib.c
@@ -45,23 +45,83 @@ typedef struct {
 HANDLE_GUID_MAP      mCacheHandleGuidTable[CACHE_HANDLE_GUID_COUNT];
 UINTN                mCachePairCount = 0;
 
 UINT32               mPerformanceLength    = 0;
 UINT32               mMaxPerformanceLength = 0;
+UINT32               mLoadImageCount       = 0;
 BOOLEAN              mFpdtDataIsReported   = FALSE;
 BOOLEAN              mLackSpaceIsReport    = FALSE;
 CHAR8                *mPlatformLanguage    = NULL;
 SPIN_LOCK            mSmmFpdtLock;
 PERFORMANCE_PROPERTY  mPerformanceProperty;
+UINT32               mCachedLength         = 0;
 
 //
 // Interfaces for SMM PerformanceMeasurement Protocol.
 //
 EDKII_PERFORMANCE_MEASUREMENT_PROTOCOL mPerformanceMeasurementInterface = {
   CreatePerformanceMeasurement,
 };
 
+/**
+  Return the pointer to the FPDT record in the allocated memory.
+
+  @param  RecordSize             The size of FPDT record.
+  @param  FpdtRecordPtr          Pointer the FPDT record in the allocated 
memory.
+
+  @retval EFI_SUCCESS            Successfully get the pointer to the FPDT 
record.
+  @retval EFI_OUT_OF_RESOURCES   Ran out of space to store the records.
+**/
+EFI_STATUS
+GetFpdtRecordPtr (
+  IN     UINT8               RecordSize,
+  IN OUT FPDT_RECORD_PTR     *FpdtRecordPtr
+)
+{
+  if (mFpdtDataIsReported) {
+    //
+    // Append Boot records after Smm boot performance records have been 
reported.
+    //
+    if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+      if (!mLackSpaceIsReport) {
+        DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save 
boot records\n"));
+        mLackSpaceIsReport = TRUE;
+      }
+      return EFI_OUT_OF_RESOURCES;
+    } else {
+      //
+      // Covert buffer to FPDT Ptr Union type.
+      //
+      FpdtRecordPtr->RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+    }
+  } else {
+    //
+    // Check if pre-allocated buffer is full
+    //
+    if (mPerformanceLength + RecordSize > mMaxPerformanceLength) {
+      mSmmBootPerformanceTable = ReallocatePool (
+                                   mPerformanceLength,
+                                   mPerformanceLength + sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + RecordSize + FIRMWARE_RECORD_BUFFER,
+                                   mSmmBootPerformanceTable
+                              );
+
+      if (mSmmBootPerformanceTable == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      mSmmBootPerformanceTable->Header.Length = sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength;
+      mMaxPerformanceLength = mPerformanceLength + sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + RecordSize + FIRMWARE_RECORD_BUFFER;
+    }
+    //
+    // Covert buffer to FPDT Ptr Union type.
+    //
+    FpdtRecordPtr->RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
+  }
+  FpdtRecordPtr->RecordHeader->Length = 0;
+  return EFI_SUCCESS;
+}
+
+
 /**
 Check whether the Token is a known one which is uesed by core.
 
 @param  Token      Pointer to a Null-terminated ASCII string
 
@@ -123,117 +183,63 @@ IsKnownID (
     return FALSE;
   }
 }
 
 /**
-  Get the FPDT record info.
+  Get the FPDT record identifier.
 
-  @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  RecordInfo              On return, pointer to the info of the record.
-  @param  UseModuleName           Only useful for 
FPDT_DYNAMIC_STRING_EVENT_TYPE, indicate that whether need use
-                                  Module name to fill the string field in the 
FPDT_DYNAMIC_STRING_EVENT_RECORD.
+  @param Attribute                The attribute of the Record.
+                                  PerfStartEntry: Start Record.
+                                  PerfEndEntry: End Record.
+  @param  Handle                  Pointer to environment specific context used 
to identify the component being measured.
+  @param  String                  Pointer to a Null-terminated ASCII string 
that identifies the component being measured.
+  @param  ProgressID              On return, pointer to the ProgressID.
 
-  @retval EFI_SUCCESS             Get record info successfully.
-  @retval EFI_UNSUPPORTED         No matched FPDT record.
+  @retval EFI_SUCCESS              Get record info successfully.
+  @retval EFI_INVALID_PARAMETER    No matched FPDT record.
 
 **/
 EFI_STATUS
-GetFpdtRecordInfo (
-  IN BOOLEAN                  IsStart,
-  IN CONST VOID               *Handle,
-  IN CONST CHAR8              *Token,
-  IN CONST CHAR8              *Module,
-  OUT FPDT_BASIC_RECORD_INFO  *RecordInfo,
-  IN OUT BOOLEAN              *UseModuleName
+GetFpdtRecordId (
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute,
+  IN CONST VOID                        *Handle,
+  IN CONST CHAR8                       *String,
+  OUT UINT16                           *ProgressID
   )
 {
-  UINT16              RecordType;
-  UINTN               StringSize;
-
-  RecordType = FPDT_DYNAMIC_STRING_EVENT_TYPE;
-
   //
-  // Token to Type and Id.
+  // Token to Id.
   //
-  if (Token != NULL) {
-    if (AsciiStrCmp (Token, START_IMAGE_TOK) == 0) {              // 
"StartImage:"
-      *UseModuleName = TRUE;
-      RecordType     = FPDT_GUID_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_START_ID;
+  if (String != NULL) {
+    if (AsciiStrCmp (String, START_IMAGE_TOK) == 0) {              // 
"StartImage:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_END_ID;
+        *ProgressID  = MODULE_END_ID;
       }
-    } else if (AsciiStrCmp (Token, LOAD_IMAGE_TOK) == 0) {        // 
"LoadImage:"
-      *UseModuleName = TRUE;
-      RecordType     = FPDT_GUID_QWORD_EVENT_TYPE;
-      if (IsStart) {
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_START_ID;
+    } else if (AsciiStrCmp (String, LOAD_IMAGE_TOK) == 0) {        // 
"LoadImage:"
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = MODULE_LOADIMAGE_START_ID;
       } else {
-        RecordInfo->ProgressID  = MODULE_LOADIMAGE_END_ID;
+        *ProgressID  = MODULE_LOADIMAGE_END_ID;
       }
     } else {                                                      // Pref used 
in Modules
-      if (IsStart) {
-        RecordInfo->ProgressID  = PERF_INMODULE_START_ID;
+      if (Attribute == PerfStartEntry) {
+        *ProgressID  = PERF_INMODULE_START_ID;
       } else {
-        RecordInfo->ProgressID  = PERF_INMODULE_END_ID;
+        *ProgressID  = PERF_INMODULE_END_ID;
       }
     }
-  } else if (Handle != NULL || Module != NULL) {                 // Pref used 
in Modules
-    if (IsStart) {
-      RecordInfo->ProgressID    = PERF_INMODULE_START_ID;
+  } else if (Handle != NULL) {                                    // Pref used 
in Modules
+    if (Attribute == PerfStartEntry) {
+      *ProgressID    = PERF_INMODULE_START_ID;
     } else {
-      RecordInfo->ProgressID    = PERF_INMODULE_END_ID;
+      *ProgressID    = PERF_INMODULE_END_ID;
     }
   } else {
     return EFI_UNSUPPORTED;
   }
-
-  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
-    RecordType               = FPDT_DYNAMIC_STRING_EVENT_TYPE;
-    RecordInfo->RecordSize   = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE;
-  } else {
-    switch (RecordType) {
-    case FPDT_GUID_EVENT_TYPE:
-      RecordInfo->RecordSize  = sizeof (FPDT_GUID_EVENT_RECORD);
-      break;
-
-    case FPDT_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 
(FPDT_DYNAMIC_STRING_EVENT_RECORD) + StringSize);
-      break;
-
-    case FPDT_GUID_QWORD_EVENT_TYPE:
-      RecordInfo->RecordSize  = (UINT8)sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
-      break;
-
-    default:
-      //
-      // Record type is unsupported in SMM phase.
-      //
-      return EFI_UNSUPPORTED;
-    }
-  }
-
-  RecordInfo->Type = RecordType;
   return EFI_SUCCESS;
 }
 
 /**
   Get a human readable module name and module guid for the given image handle.
@@ -435,123 +441,144 @@ Done:
 
   return Status;
 }
 
 /**
-  Add performance log to FPDT boot record table.
+  Copies the string from Source into Destination and updates Length with the
+  size of the string.
 
-  @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  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.
+  @param Destination - destination of the string copy
+  @param Source      - pointer to the source string which will get copied
+  @param Length      - pointer to a length variable to be updated
+
+**/
+VOID
+CopyStringIntoPerfRecordAndUpdateLength (
+  IN OUT CHAR8  *Destination,
+  IN     CONST CHAR8  *Source,
+  IN OUT UINT8  *Length
+  )
+{
+  UINTN  StringLen;
+  UINTN  DestMax;
+
+  ASSERT (Source != NULL);
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    DestMax = STRING_SIZE;
+  } else {
+    DestMax = AsciiStrSize (Source);
+    if (DestMax > STRING_SIZE) {
+      DestMax = STRING_SIZE;
+    }
+  }
+  StringLen = AsciiStrLen (Source);
+  if (StringLen >= DestMax) {
+    StringLen = DestMax -1;
+  }
 
-  @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.
+  AsciiStrnCpyS(Destination, DestMax, Source, StringLen);
+  *Length += (UINT8)DestMax;
+
+  return;
+}
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID.
+  @param Guid              - Pointer to a GUID.
+  @param String            - Pointer to a string describing the measurement.
+  @param Ticker            - 64-bit time stamp.
+  @param Address           - Pointer to a location in memory relevant to the 
measurement.
+  @param PerfId            - Performance identifier describing the type of 
measurement.
+  @param Attribute         - The attribute of the measurement. According to 
attribute can create a start
+                             record for PERF_START/PERF_START_EX, or a end 
record for PERF_END/PERF_END_EX,
+                             or a general record for other Perf macros.
+
+  @retval EFI_SUCCESS           - Successfully created performance record.
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records.
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+                                  pointer or invalid PerfId.
+
+  @retval EFI_SUCCESS           - Successfully created performance record
+  @retval EFI_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval EFI_INVALID_PARAMETER - Invalid parameter passed to function - NULL
+                                  pointer or invalid PerfId
 
 **/
 EFI_STATUS
-InsertFpdtMeasurement (
-  IN BOOLEAN      IsStart,
-  IN CONST VOID   *Handle,  OPTIONAL
-  IN CONST CHAR8  *Token,   OPTIONAL
-  IN CONST CHAR8  *Module,  OPTIONAL
-  IN UINT64       Ticker,
-  IN UINT32       Identifier
+InsertFpdtRecord (
+  IN CONST VOID                        *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                        *Guid,    OPTIONAL
+  IN CONST CHAR8                       *String,  OPTIONAL
+  IN       UINT64                      Ticker,
+  IN       UINT64                      Address,  OPTIONAL
+  IN       UINT16                      PerfId,
+  IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
   )
+
 {
+  EFI_STATUS                   Status;
   EFI_GUID                     ModuleGuid;
   CHAR8                        
ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
-  EFI_STATUS                   Status;
   FPDT_RECORD_PTR              FpdtRecordPtr;
+  FPDT_RECORD_PTR              CachedFpdtRecordPtr;
   UINT64                       TimeStamp;
-  FPDT_BASIC_RECORD_INFO       RecordInfo;
-  UINTN                        DestMax;
-  UINTN                        StrLength;
   CONST CHAR8                  *StringPtr;
-  BOOLEAN                      UseModuleName;
+  UINTN                        DestMax;
+  UINTN                        StringLen;
+  UINT16                       ProgressId;
 
   StringPtr     = NULL;
-  UseModuleName = FALSE;
   ZeroMem (ModuleName, sizeof (ModuleName));
 
   //
-  // Get record info includes type, size, ProgressID.
-  //
-  Status = GetFpdtRecordInfo (IsStart, Handle, Token, Module, &RecordInfo, 
&UseModuleName);
-  if (EFI_ERROR (Status)) {
-    return Status;
-  }
-
-  //
-  // If PERF_START()/PERF_END() have specified the ProgressID,it has high 
priority.
-  // !!! Note: If the Perf 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.
+  // 1. Get the Perf Id for records from PERF_START/PERF_END, 
PERF_START_EX/PERF_END_EX.
+  //    notes: For other Perf macros (Attribute == PerfEntry), their Id is 
known.
   //
-  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 (mFpdtDataIsReported) {
+  if (Attribute != PerfEntry) {
     //
-    // Append Boot records after Smm boot performance records have been 
reported.
+    // If PERF_START_EX()/PERF_END_EX() have specified the ProgressID,it has 
high priority.
+    // !!! Note: If the Perf 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 (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
-      if (!mLackSpaceIsReport) {
-        DEBUG ((DEBUG_INFO, "SmmCorePerformanceLib: No enough space to save 
boot records\n"));
-        mLackSpaceIsReport = TRUE;
+    if ((PerfId != 0) && (IsKnownID (PerfId)) && (!IsKnownTokens (String))) {
+      return EFI_INVALID_PARAMETER;
+    } else if ((PerfId != 0) && (!IsKnownID (PerfId)) && (!IsKnownTokens 
(String))) {
+      if ((Attribute == PerfStartEntry) && ((PerfId & 0x000F) != 0)) {
+        PerfId &= 0xFFF0;
+      } else if ((Attribute == PerfEndEntry) && ((PerfId & 0x000F) == 0)) {
+        PerfId += 1;
       }
-      return EFI_OUT_OF_RESOURCES;
-    } else {
+    }
+    if (PerfId == 0) {
       //
-      // Covert buffer to FPDT Ptr Union type.
+      // Get ProgressID form the String Token.
       //
-      FpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
-    }
-  } else {
-    //
-    // Check if pre-allocated buffer is full
-    //
-    if (mPerformanceLength + RecordInfo.RecordSize > mMaxPerformanceLength) {
-      mSmmBootPerformanceTable = ReallocatePool (
-                                   mPerformanceLength,
-                                   mPerformanceLength + sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER,
-                                   mSmmBootPerformanceTable
-                              );
-
-      if (mSmmBootPerformanceTable == NULL) {
-        return EFI_OUT_OF_RESOURCES;
+      Status = GetFpdtRecordId (Attribute, CallerIdentifier, String, 
&ProgressId);
+      if (EFI_ERROR (Status)) {
+        return Status;
       }
-      mSmmBootPerformanceTable->Header.Length = sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength;
-      mMaxPerformanceLength = mPerformanceLength + sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.RecordSize + FIRMWARE_RECORD_BUFFER;
+      PerfId = ProgressId;
     }
-    //
-    // Covert buffer to FPDT Ptr Union type.
-    //
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mSmmBootPerformanceTable->Header.Length);
   }
-  FpdtRecordPtr.RecordHeader->Length = 0;
 
   //
-  // Get the TimeStamp.
+  // 2. Get the buffer to store the FPDT record.
+  //
+  Status = GetFpdtRecordPtr (FPDT_MAX_PERF_RECORD_SIZE, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // 3. Get the TimeStamp.
   //
   if (Ticker == 0) {
     Ticker    = GetPerformanceCounter ();
     TimeStamp = GetTimeInNanoSecond (Ticker);
   } else if (Ticker == 1) {
@@ -559,74 +586,190 @@ InsertFpdtMeasurement (
   } else {
     TimeStamp = GetTimeInNanoSecond (Ticker);
   }
 
   //
-  // Get the ModuleName and ModuleGuid form the handle.
+  // 4. Fill in the FPDT record according to different Performance Identifier.
   //
-  GetModuleInfoFromHandle ((EFI_HANDLE *)Handle, ModuleName, sizeof 
(ModuleName), &ModuleGuid);
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    //
+    // Cache the offset of start image start record and use to update the 
start image end record if needed.
+    //
+    if (PerfId == MODULE_START_ID && Attribute == PerfEntry) {
+      mCachedLength = mSmmBootPerformanceTable->Header.Length;
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidEvent->Header.Type                = 
FPDT_GUID_EVENT_TYPE;
+      FpdtRecordPtr.GuidEvent->Header.Length              = sizeof 
(FPDT_GUID_EVENT_RECORD);
+      FpdtRecordPtr.GuidEvent->Header.Revision            = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidEvent->ProgressID                 = PerfId;
+      FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
+      CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidEvent->Guid));
+      if (CallerIdentifier == NULL && PerfId == MODULE_END_ID && mCachedLength 
!= 0) {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+        CopyMem (&FpdtRecordPtr.GuidEvent->Guid, 
&CachedFpdtRecordPtr.GuidEvent->Guid, sizeof (FpdtRecordPtr.GuidEvent->Guid));
+        mCachedLength = 0;
+      }
+    }
+    break;
 
-  //
-  // Fill in the record information.
-  //
-  switch (RecordInfo.Type) {
-  case FPDT_GUID_EVENT_TYPE:
-    FpdtRecordPtr.GuidEvent->Header.Type                = FPDT_GUID_EVENT_TYPE;
-    FpdtRecordPtr.GuidEvent->Header.Length              = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.GuidEvent->Header.Revision            = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidEvent->ProgressID                 = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidEvent->Timestamp                  = TimeStamp;
-    CopyMem (&FpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidEvent->Guid));
+  case MODULE_LOADIMAGE_START_ID:
+  case MODULE_LOADIMAGE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (PerfId == MODULE_LOADIMAGE_START_ID) {
+      mLoadImageCount++;
+      //
+      // Cache the offset of load image start record and use to be updated by 
the load image end record if needed.
+      //
+      if (CallerIdentifier == NULL && Attribute == PerfEntry) {
+        mCachedLength = mSmmBootPerformanceTable->Header.Length;
+      }
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = sizeof 
(FPDT_GUID_QWORD_EVENT_RECORD);
+      FpdtRecordPtr.GuidQwordEvent->Header.Revision       = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidQwordEvent->ProgressID            = PerfId;
+      FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
+      FpdtRecordPtr.GuidQwordEvent->Qword                 = mLoadImageCount;
+      CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordEvent->Guid));
+      if (PerfId == MODULE_LOADIMAGE_END_ID && mCachedLength != 0) {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+        CopyMem (&CachedFpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.GuidQwordEvent->Guid));
+        mCachedLength = 0;
+      }
+    }
     break;
 
-  case FPDT_DYNAMIC_STRING_EVENT_TYPE:
-    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
-    FpdtRecordPtr.DynamicStringEvent->Header.Length     = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.DynamicStringEvent->ProgressID        = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
-    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+  case PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    //
+    // Cache the event guid in string event record when 
PcdEdkiiFpdtStringRecordEnableOnly == TRUE
+    //
+    CopyGuid (&ModuleGuid, Guid);
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DualGuidStringEvent->Header.Type      = 
FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DualGuidStringEvent->Header.Length    = sizeof 
(FPDT_DUAL_GUID_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DualGuidStringEvent->Header.Revision  = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DualGuidStringEvent->ProgressID       = PerfId;
+      FpdtRecordPtr.DualGuidStringEvent->Timestamp        = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid1, CallerIdentifier, 
sizeof (FpdtRecordPtr.DualGuidStringEvent->Guid1));
+      CopyMem (&FpdtRecordPtr.DualGuidStringEvent->Guid2, Guid, sizeof 
(FpdtRecordPtr.DualGuidStringEvent->Guid2));
+      CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DualGuidStringEvent->String, StringPtr, 
&FpdtRecordPtr.DualGuidStringEvent->Header.Length);
+    }
+    break;
 
-    if (UseModuleName) {
-      StringPtr     = ModuleName;
-    } else if (Token != NULL) {
-      StringPtr     = Token;
-    } else if (Module != NULL) {
-      StringPtr     = Module;
-    } else if (ModuleName != NULL) {
-      StringPtr     = ModuleName;
+  case PERF_EVENT_ID:
+  case PERF_FUNCTION_START_ID:
+  case PERF_FUNCTION_END_ID:
+  case PERF_INMODULE_START_ID:
+  case PERF_INMODULE_END_ID:
+  case PERF_CROSSMODULE_START_ID:
+  case PERF_CROSSMODULE_END_ID:
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    if (String != NULL) {
+      StringPtr = String;
+    } else {
+      StringPtr = ModuleName;
+    }
+    if (AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
     }
-    if (StringPtr != NULL && AsciiStrLen (StringPtr) != 0) {
-      StrLength     = AsciiStrLen (StringPtr);
-      DestMax       = (RecordInfo.RecordSize - sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD)) / sizeof (CHAR8);
-      if (StrLength >= DestMax) {
-        StrLength   = DestMax -1;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+      CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
+    }
+    break;
+
+  default:
+    if (Attribute != PerfEntry) {
+      GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+      if (String != NULL) {
+        StringPtr = String;
+      } else {
+        StringPtr = ModuleName;
+      }
+      if (AsciiStrLen (StringPtr) == 0) {
+        StringPtr = "unknown name";
+      }
+      if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+        FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+        FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+        FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+        FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+        CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
       }
-      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StrLength);
     } else {
-      AsciiStrCpyS (FpdtRecordPtr.DynamicStringEvent->String, 
FPDT_STRING_EVENT_RECORD_NAME_LENGTH, "unknown name");
+      return EFI_INVALID_PARAMETER;
     }
     break;
+  }
 
-  case FPDT_GUID_QWORD_EVENT_TYPE:
-    FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
-    FpdtRecordPtr.GuidQwordEvent->Header.Length         = 
RecordInfo.RecordSize;
-    FpdtRecordPtr.GuidQwordEvent->Header.Revision       = 
FPDT_RECORD_REVISION_1;
-    FpdtRecordPtr.GuidQwordEvent->ProgressID            = 
RecordInfo.ProgressID;
-    FpdtRecordPtr.GuidQwordEvent->Timestamp             = TimeStamp;
-    CopyMem (&FpdtRecordPtr.GuidQwordEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.GuidQwordEvent->Guid));
-    break;
+  //
+  // 4.2 When PcdEdkiiFpdtStringRecordEnableOnly==TRUE, create string record 
for all Perf entries.
+  //
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    if (StringPtr == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+    if (AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
+    }
+    CopyStringIntoPerfRecordAndUpdateLength 
(FpdtRecordPtr.DynamicStringEvent->String, StringPtr, 
&FpdtRecordPtr.DynamicStringEvent->Header.Length);
 
-  default:
-    //
-    // Record is not supported in current SMM phase, return EFI_UNSUPPORTED
-    //
-    return EFI_UNSUPPORTED;
+    if ((PerfId == MODULE_LOADIMAGE_START_ID) || (PerfId == MODULE_END_ID)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Length = (UINT8)(sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD)+ STRING_SIZE);
+    }
+    if ((PerfId == MODULE_LOADIMAGE_END_ID || PerfId == MODULE_END_ID) && 
mCachedLength != 0) {
+      CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+      if (PerfId == MODULE_LOADIMAGE_END_ID) {
+        DestMax = CachedFpdtRecordPtr.DynamicStringEvent->Header.Length - 
sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        StringLen = AsciiStrLen (StringPtr);
+        if (StringLen >= DestMax) {
+          StringLen = DestMax -1;
+        }
+        CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, 
DestMax, StringPtr, StringLen);
+      } else if (PerfId == MODULE_END_ID) {
+        DestMax = FpdtRecordPtr.DynamicStringEvent->Header.Length - sizeof 
(FPDT_DYNAMIC_STRING_EVENT_RECORD);
+        StringLen = AsciiStrLen 
(CachedFpdtRecordPtr.DynamicStringEvent->String);
+        if (StringLen >= DestMax) {
+          StringLen = DestMax -1;
+        }
+        CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, 
&CachedFpdtRecordPtr.DynamicStringEvent->Guid, sizeof 
(CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
CachedFpdtRecordPtr.DynamicStringEvent->String, StringLen);
+      }
+      mCachedLength = 0;
+    }
   }
 
   //
-  // Update the cached FPDT record buffer.
+  // 5. Update the length of the used buffer after fill in the record.
   //
   mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
   mSmmBootPerformanceTable->Header.Length += 
FpdtRecordPtr.RecordHeader->Length;
 
   return EFI_SUCCESS;
@@ -814,16 +957,14 @@ CreatePerformanceMeasurement(
   IN       PERF_MEASUREMENT_ATTRIBUTE  Attribute
   )
 {
   EFI_STATUS   Status;
 
+  Status = EFI_SUCCESS;
+
   AcquireSpinLock (&mSmmFpdtLock);
-  if (Attribute == PerfStartEntry) {
-    Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
-  } else if (Attribute == PerfEndEntry) {
-    Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
-  }
+  Status = InsertFpdtRecord (CallerIdentifier, Guid, String, TimeStamp, 
Address, (UINT16)Identifier, Attribute);
   ReleaseSpinLock (&mSmmFpdtLock);
   return Status;
 }
 
 /**
@@ -1125,5 +1266,61 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
 }
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID
+  @param Guid              - Pointer to a GUID
+  @param String            - Pointer to a string describing the measurement
+  @param Address           - Pointer to a location in memory relevant to the 
measurement
+  @param Identifier        - Performance identifier describing the type of 
measurement
+
+  @retval RETURN_SUCCESS           - Successfully created performance record
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - 
NULL
+                                     pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+  IN CONST VOID   *CallerIdentifier,
+  IN CONST VOID   *Guid,    OPTIONAL
+  IN CONST CHAR8  *String,  OPTIONAL
+  IN UINT64       Address, OPTIONAL
+  IN UINT32       Identifier
+  )
+{
+  return (RETURN_STATUS)CreatePerformanceMeasurement (CallerIdentifier, Guid, 
String, 0, Address, Identifier, PerfEntry);
+}
+
+/**
+  Check whether the specified performance measurement can be logged.
+
+  This function returns TRUE when the 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of 
PcdPerformanceLibraryPropertyMask is set
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+  @param Type        - Type of the performance measurement entry.
+
+  @retval TRUE         The performance measurement can be logged.
+  @retval FALSE        The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+  IN  CONST UINTN        Type
+  )
+{
+  //
+  // When Performance measurement is enabled and the type is not filtered, the 
performance can be logged.
+  //
+  if (PerformanceMeasurementEnabled () && 
(PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
+
diff --git a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c 
b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
index fd820c0e49c..830037befa6 100644
--- a/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
+++ b/MdeModulePkg/Library/SmmPerformanceLib/SmmPerformanceLib.c
@@ -395,5 +395,73 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return mPerformanceMeasurementEnabled;
 }
+
+/**
+  Create performance record with event description and a timestamp.
+
+  @param CallerIdentifier  - Image handle or pointer to caller ID GUID
+  @param Guid              - Pointer to a GUID
+  @param String            - Pointer to a string describing the measurement
+  @param Address           - Pointer to a location in memory relevant to the 
measurement
+  @param Identifier        - Performance identifier describing the type of 
measurement
+
+  @retval RETURN_SUCCESS           - Successfully created performance record
+  @retval RETURN_OUT_OF_RESOURCES  - Ran out of space to store the records
+  @retval RETURN_INVALID_PARAMETER - Invalid parameter passed to function - 
NULL
+                                     pointer or invalid PerfId
+
+**/
+RETURN_STATUS
+EFIAPI
+LogPerformanceMeasurement (
+  IN CONST VOID   *CallerIdentifier,
+  IN CONST VOID   *Guid,    OPTIONAL
+  IN CONST CHAR8  *String,  OPTIONAL
+  IN UINT64       Address, OPTIONAL
+  IN UINT32       Identifier
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = GetPerformanceMeasurementProtocol ();
+  if (EFI_ERROR (Status)) {
+    return RETURN_OUT_OF_RESOURCES;
+  }
+
+  if (mPerformanceMeasurement != NULL) {
+    Status = mPerformanceMeasurement->CreatePerformanceMeasurement 
(CallerIdentifier, Guid, String, 0, Address, Identifier, PerfEntry);
+  } else {
+    ASSERT (FALSE);
+  }
+
+  return (RETURN_STATUS) Status;
+}
+
+/**
+  Check whether the specified performance measurement can be logged.
+
+  This function returns TRUE when the 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of 
PcdPerformanceLibraryPropertyMask is set
+  and the Type disable bit in PcdPerformanceLibraryPropertyMask is not set.
+
+  @param Type        - Type of the performance measurement entry.
+
+  @retval TRUE         The performance measurement can be logged.
+  @retval FALSE        The performance measurement can NOT be logged.
+
+**/
+BOOLEAN
+EFIAPI
+LogPerformanceMeasurementEnabled (
+  IN  CONST UINTN        Type
+  )
+{
+  //
+  // When Performance measurement is enabled and the type is not filtered, the 
performance can be logged.
+  //
+  if (PerformanceMeasurementEnabled () && 
(PcdGet8(PcdPerformanceLibraryPropertyMask) & Type) == 0) {
+    return TRUE;
+  }
+  return FALSE;
+}
-- 
2.14.3.windows.1

_______________________________________________
edk2-devel mailing list
edk2-devel@lists.01.org
https://lists.01.org/mailman/listinfo/edk2-devel

Reply via email to