Update the performance library instances in MdeModulePkg
to implement the APIs used for new added 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>
---
 .../DxeCorePerformanceLib/DxeCorePerformanceLib.c  | 664 +++++++++++++++++++--
 .../DxeCorePerformanceLib.inf                      |   1 +
 .../DxeCorePerformanceLibInternal.h                |   1 +
 .../Library/DxePerformanceLib/DxePerformanceLib.c  |  68 +++
 .../Library/PeiPerformanceLib/PeiPerformanceLib.c  | 442 ++++++++++++--
 .../SmmCorePerformanceLib/SmmCorePerformanceLib.c  | 440 ++++++++++++--
 .../Library/SmmPerformanceLib/SmmPerformanceLib.c  |  68 +++
 7 files changed, 1550 insertions(+), 134 deletions(-)

diff --git a/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c 
b/MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
index 79820605184..68724ce9e1c 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
 
@@ -814,49 +870,13 @@ InsertFpdtMeasurement (
       Identifier += 1;
     }
     RecordInfo.ProgressID = (UINT16)Identifier;
   }
 
-  if (mFpdtBufferIsReported) {
-    //
-    // Append Boot records to the boot performance table.
-    //
-    if (mBootRecordSize + RecordInfo.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);
-      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;
-      }
-      mMaxPerformanceLength = mPerformanceLength + RecordInfo.RecordSize + 
FIRMWARE_RECORD_BUFFER;
-    }
-    //
-    // Covert buffer to FPDT Ptr Union type.
-    //
-    FpdtRecordPtr.RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)(mPerformancePointer + mPerformanceLength);
-    mPerformanceLength += RecordInfo.RecordSize;
+  Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
   }
 
   //
   // Get the TimeStamp.
   //
@@ -942,11 +962,16 @@ InsertFpdtMeasurement (
     //
     // Record is not supported in current DXE phase, return EFI_ABORTED
     //
     return EFI_UNSUPPORTED;
   }
-
+  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.
@@ -1038,10 +1063,512 @@ ReportFpdtRecordBuffer (
     //
     mFpdtBufferIsReported = TRUE;
   }
 }
 
+/**
+  Get a string description for device for the given controller handle.
+  If ComponentName2 GetControllerName is supported, the value is
+  included in the string,followed by device path, otherwise just device path.
+
+  @param Handle              - Image handle
+  @param ControllerHandle    - Controller handle.
+  @param Length              - Pointer to record length to be updated
+
+  @retval EFI_SUCCESS     - Successfully got string description for device
+  @retval EFI_UNSUPPORTED - Neither ComponentName2 ControllerName nor 
DevicePath were found.
+
+**/
+EFI_STATUS
+GetDeviceInfoFromHandleAndUpdateLength (
+  IN CONST VOID        *Handle,
+  IN EFI_HANDLE        ControllerHandle,
+  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) {
+      //
+      // Only copy enough to fill MAX_PERF_RECORD_SIZE worth of the record
+      //
+      ControllerNameStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length) - 1;
+    }
+
+    mDevicePathString = AllocateZeroPool (ControllerNameStringSize + 1);
+    if (mDevicePathString == NULL) {
+      return EFI_OUT_OF_RESOURCES;
+    }
+
+    UnicodeStrToAsciiStrS(StringPtr, mDevicePathString, 
ControllerNameStringSize);
+
+    //
+    // Add a space in the end of the ControllerName
+    //
+    AsciiStringPtr = mDevicePathString + ControllerNameStringSize - 1;
+    *AsciiStringPtr = 0x20;
+    AsciiStringPtr++;
+    *AsciiStringPtr = 0;
+    ControllerNameStringSize++;
+
+    *Length += (UINT8)ControllerNameStringSize;
+  }
+
+  //
+  // 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 MAX_PERF_RECORD_SIZE worth of the record
+        //
+        DevicePathStringSize = FPDT_MAX_PERF_RECORD_SIZE - (*Length);
+      }
+      if (ControllerNameStringSize != 0) {
+        mDevicePathString = ReallocatePool(
+                          ControllerNameStringSize + 1,
+                          ControllerNameStringSize + DevicePathStringSize + 1,
+                          mDevicePathString
+                          );
+      } else {
+        mDevicePathString = AllocateZeroPool(DevicePathStringSize + 1);
+      }
+      if (mDevicePathString == NULL) {
+        return EFI_OUT_OF_RESOURCES;
+      }
+      if (ControllerNameStringSize != 0) {
+        AsciiStringPtr = mDevicePathString + ControllerNameStringSize - 1;
+      } else {
+        AsciiStringPtr = mDevicePathString;
+      }
+
+      UnicodeStrToAsciiStrS(StringPtr, AsciiStringPtr, DevicePathStringSize);
+      *Length += (UINT8)DevicePathStringSize;
+      return EFI_SUCCESS;
+    }
+  }
+
+  return EFI_UNSUPPORTED;
+}
+
+/**
+  Get the FPDT record size.
+
+  @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  Address                  Pointer to a location in memory relevant to 
the measurement.
+                                   For DriverBinding Perf, it's the Controller 
handle.
+                                   For other Perf, it's NULL.
+  @param  PerfId                   Performance identifier.
+  @param  RecordSize               On return, pointer to the size of record.
+
+  @retval EFI_SUCCESS              Get record size successfully.
+  @retval EFI_INVALID_PARAMETER    Invalid Performance identifier.
+
+**/
+EFI_STATUS
+GetFpdtRecordSize (
+  IN CONST VOID                    *Handle,
+  IN CONST CHAR8                   *String,
+  IN       UINT64                  Address,
+  IN       UINT16                  PerfId,
+  OUT      UINT8                   *RecordSize
+  )
+{
+  UINTN    StringSize;
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    if (PerfId == MODULE_DB_SUPPORT_START_ID || PerfId ==  
MODULE_DB_SUPPORT_END_ID) {
+      return EFI_UNSUPPORTED;
+    }
+    *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE);
+  } else {
+    switch (PerfId) {
+    case MODULE_START_ID:
+    case MODULE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
+      break;
+
+    case MODULE_LOADIMAGE_START_ID:
+    case MODULE_LOADIMAGE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+      break;
+
+    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:
+      *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+      break;
+
+    case MODULE_DB_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD);
+      GetDeviceInfoFromHandleAndUpdateLength(Handle, 
(EFI_HANDLE)(UINTN)Address, RecordSize);
+      break;
+
+    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;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8)(sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + 
StringSize);
+      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) {
+        return EFI_INVALID_PARAMETER;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
StringSize);
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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 PerfId            - Performance identifier describing the type of 
measurement
+
+  @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
+InsertFpdtRecord (
+  IN CONST VOID                    *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                    *Guid,    OPTIONAL
+  IN CONST CHAR8                   *String,  OPTIONAL
+  IN       UINT64                  Address,  OPTIONAL
+  IN       UINT16                  PerfId
+  )
+{
+  EFI_GUID                     ModuleGuid;
+  CHAR8                        
ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+  FPDT_RECORD_PTR              FpdtRecordPtr;
+  FPDT_RECORD_PTR              CachedFpdtRecordPtr;
+  UINT64                       TimeStamp;
+  UINT64                       TimeStampCounter;
+  CONST CHAR8                  *StringPtr;
+  UINT8                        RecordSize;
+  UINTN                        DestMax;
+  UINTN                        StringLen;
+  EFI_STATUS                   Status;
+
+  StringPtr     = NULL;
+  RecordSize    = 0;
+  ZeroMem (ModuleName, sizeof (ModuleName));
+
+  Status = GetFpdtRecordSize(CallerIdentifier, String, Address, PerfId, 
&RecordSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the TimeStamp.
+  //
+  TimeStampCounter = GetPerformanceCounter ();
+  TimeStamp        = GetTimeInNanoSecond (TimeStampCounter);
+
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    //
+    // Get the ModuleGuid and ModuleName from the handle.
+    //
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (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              = RecordSize;
+      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 (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 (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(CachedFpdtRecordPtr.GuidEvent->Guid));
+        mCachedLength = 0;
+      }
+    }
+    break;
+
+  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 ++;
+      if (mFpdtBufferIsReported) {
+        mCachedLength = mBootRecordSize;
+      } else {
+        mCachedLength = mPerformanceLength;
+      }
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = RecordSize;
+      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;
+      }
+    }
+    break;
+
+  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:
+    if (Address == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+    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         = RecordSize;
+      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 MODULE_DB_END_ID:
+    if (Address == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+    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   = RecordSize;
+      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));
+      DestMax = (RecordSize - sizeof (FPDT_GUID_QWORD_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      if (mDevicePathString != NULL) {
+        AsciiStrCpyS (FpdtRecordPtr.GuidQwordStringEvent->String, DestMax, 
mDevicePathString);
+        FreePool (mDevicePathString);
+        mDevicePathString = NULL;
+      }
+    }
+    break;
+
+  case PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (CallerIdentifier == NULL || Guid ==NULL || 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    = RecordSize;
+      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));
+      DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, 
StringPtr, StringLen);
+    }
+    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 (CallerIdentifier == NULL || String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier);
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, 
sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+      DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+    }
+    break;
+
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+    DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+    if (StringPtr != NULL && AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
+    }
+    if (StringPtr != NULL) {
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+    }
+    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+    AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+
+    if ((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) {
+      if (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.DynamicStringEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, 
DestMax, StringPtr, StringLen);
+        mCachedLength = 0;
+      }
+    }
+  }
+  if (mFpdtBufferIsReported) {
+    mBootRecordSize += FpdtRecordPtr.RecordHeader->Length;
+    mAcpiBootPerformanceTable->Header.Length += 
FpdtRecordPtr.RecordHeader->Length;
+  } else {
+    mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+  }
+  return EFI_SUCCESS;
+}
+
 /**
   The constructor function initializes Performance infrastructure for DXE 
phase.
 
   The constructor function publishes Performance and PerformanceEx protocol, 
allocates memory to log DXE performance
   and merges PEI performance data to DXE performance log.
@@ -1162,10 +1689,12 @@ CreatePerformanceMeasurement (
 
   if (Attribute == PerfStartEntry) {
     Status = InsertFpdtMeasurement (TRUE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
   } else if (Attribute == PerfEndEntry) {
     Status = InsertFpdtMeasurement (FALSE, CallerIdentifier, String, String, 
TimeStamp, Identifier);
+  } else if ( Attribute == PerfEntry) {
+    Status = InsertFpdtRecord (CallerIdentifier, Guid, String, Address, 
(UINT16) Identifier);
   }
   mLockInsertRecord = FALSE;
 
   return Status;
 }
@@ -1470,5 +1999,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..d7b652c5771 100644
--- a/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
+++ b/MdeModulePkg/Library/PeiPerformanceLib/PeiPerformanceLib.c
@@ -31,11 +31,88 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER 
EXPRESS OR IMPLIED.
 #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 > 
PeiPerformanceLogEntries * PEI_MAX_RECORD_SIZE) {
+      (*PeiPerformanceLogHeader)->HobIsFull = TRUE;
+    }
+    if (!(*PeiPerformanceLogHeader)->HobIsFull && 
(*PeiPerformanceLogHeader)->SizeOfAllEntries + RecordSize <= 
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
@@ -240,23 +317,19 @@ InsertPeiFpdtMeasurement (
   IN CONST CHAR8  *Module,  OPTIONAL
   IN UINT64       Ticker,
   IN UINT32       Identifier
   )
 {
-  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;
 
@@ -286,60 +359,13 @@ InsertPeiFpdtMeasurement (
       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) {
-    //
-    // PEI Performance HOB was not found, then build one.
-    //
-    PeiPerformanceSize      = sizeof (FPDT_PEI_EXT_PERF_HEADER) +
-                              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;
+  Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr, 
&PeiPerformanceLogHeader);
+  if (EFI_ERROR (Status)) {
+    return Status;
   }
 
   //
   // Get the TimeStamp.
   //
@@ -690,5 +716,309 @@ PerformanceMeasurementEnabled (
   VOID
   )
 {
   return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & 
PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
 }
+
+/**
+  Get the FPDT record size.
+
+  @param  String                   Pointer to a Null-terminated ASCII string
+                                   that identifies the component being 
measured.
+  @param  PerfId                   Performance identifier.
+  @param  RecordSize               On return, pointer to the size of record.
+
+  @retval EFI_SUCCESS              Get record size successfully.
+  @retval EFI_INVALID_PARAMETER    Invalid Performance identifier.
+
+**/
+EFI_STATUS
+GetFpdtRecordSize (
+  IN CONST CHAR8                   *String,
+  IN       UINT16                  PerfId,
+  OUT      UINT8                   *RecordSize
+  )
+{
+  UINTN StringSize;
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    *RecordSize = sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + STRING_SIZE;
+  } else {
+    switch (PerfId) {
+    case MODULE_START_ID:
+    case MODULE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
+      break;
+
+    case MODULE_LOADIMAGE_START_ID:
+    case MODULE_LOADIMAGE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+      break;
+
+    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;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + 
StringSize);
+      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) {
+        return EFI_INVALID_PARAMETER;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
StringSize);
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  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 PerfId            - Performance identifier describing the type of 
measurement
+
+  @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
+CreateFpdtRecord (
+  IN CONST VOID                    *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                    *Guid,    OPTIONAL
+  IN CONST CHAR8                   *String,  OPTIONAL
+  IN       UINT64                  Address,  OPTIONAL
+  IN       UINT16                  PerfId
+  )
+{
+  FPDT_PEI_EXT_PERF_HEADER              *PeiPerformanceLogHeader;
+  FPDT_RECORD_PTR                       FpdtRecordPtr;
+  CONST CHAR8                           *StringPtr;
+  EFI_STATUS                            Status;
+  UINT64                                TimeStamp;
+  UINT64                                TimeStampCounter;
+  UINT8                                 RecordSize;
+  UINTN                                 DestMax;
+  UINTN                                 StringLen;
+
+  StringPtr     = NULL;
+  RecordSize    = 0;
+
+  Status = GetFpdtRecordSize(String, PerfId, &RecordSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr, 
&PeiPerformanceLogHeader);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the TimeStamp.
+  //
+  TimeStampCounter = GetPerformanceCounter ();
+  TimeStamp        = GetTimeInNanoSecond (TimeStampCounter);
+
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    if (CallerIdentifier == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    StringPtr = PEIM_TOK;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidEvent->Header.Type       = FPDT_GUID_EVENT_TYPE;
+      FpdtRecordPtr.GuidEvent->Header.Length     = RecordSize;;
+      FpdtRecordPtr.GuidEvent->Header.Revision   = FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.GuidEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.GuidEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.GuidEvent->Guid, CallerIdentifier, sizeof 
(EFI_GUID));
+      PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize;
+    }
+    break;
+
+  case MODULE_LOADIMAGE_START_ID:
+  case MODULE_LOADIMAGE_END_ID:
+    if (CallerIdentifier == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    StringPtr = LOAD_IMAGE_TOK;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type     = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length   = RecordSize;;
+      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, CallerIdentifier, sizeof 
(EFI_GUID));
+      PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize;
+    }
+    break;
+
+  case PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (CallerIdentifier == NULL || Guid ==NULL || String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DualGuidStringEvent->Header.Type      = 
FPDT_DUAL_GUID_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DualGuidStringEvent->Header.Length    = RecordSize;
+      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));
+      DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, 
StringPtr, StringLen);
+      PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize;
+    }
+    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 (CallerIdentifier == NULL || String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, 
sizeof (EFI_GUID));
+      DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+      PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize;
+    }
+    break;
+
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+    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, CallerIdentifier, 
sizeof (EFI_GUID));
+    }
+    DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+    StringLen = AsciiStrLen (StringPtr);
+    if (StringLen >= DestMax) {
+      StringLen = DestMax -1;
+    }
+    AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+    PeiPerformanceLogHeader->SizeOfAllEntries += RecordSize;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  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)CreateFpdtRecord (CallerIdentifier, Guid, String, 
Address, (UINT16)Identifier);
+}
+
+/**
+  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..efbde88220b 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
 
@@ -506,49 +566,14 @@ InsertFpdtMeasurement (
       Identifier += 1;
     }
     RecordInfo.ProgressID = (UINT16)Identifier;
   }
 
-  if (mFpdtDataIsReported) {
-    //
-    // Append Boot records after Smm boot performance records have been 
reported.
-    //
-    if (mPerformanceLength + RecordInfo.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 + 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;
-      }
-      mSmmBootPerformanceTable->Header.Length = sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + mPerformanceLength;
-      mMaxPerformanceLength = mPerformanceLength + sizeof 
(SMM_BOOT_PERFORMANCE_TABLE) + RecordInfo.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);
+  Status = GetFpdtRecordPtr (RecordInfo.RecordSize, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
   }
-  FpdtRecordPtr.RecordHeader->Length = 0;
 
   //
   // Get the TimeStamp.
   //
   if (Ticker == 0) {
@@ -630,10 +655,289 @@ InsertFpdtMeasurement (
   mSmmBootPerformanceTable->Header.Length += 
FpdtRecordPtr.RecordHeader->Length;
 
   return EFI_SUCCESS;
 }
 
+/**
+  Get the FPDT record size.
+
+  @param  String                   Pointer to a Null-terminated ASCII string
+                                   that identifies the component being 
measured.
+  @param  PerfId                   Performance identifier.
+  @param  RecordSize               On return, pointer to the size of record.
+
+  @retval EFI_SUCCESS              Get record size successfully.
+  @retval EFI_INVALID_PARAMETER    Invalid Performance identifier.
+
+**/
+EFI_STATUS
+GetFpdtRecordSize (
+  IN CONST CHAR8                   *String,
+  IN       UINT16                  PerfId,
+  OUT      UINT8                   *RecordSize
+  )
+{
+  UINTN    StringSize;
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    *RecordSize = (UINT8)(sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
STRING_SIZE);
+  } else {
+    switch (PerfId) {
+    case MODULE_START_ID:
+    case MODULE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_EVENT_RECORD);
+      break;
+
+    case MODULE_LOADIMAGE_START_ID:
+    case MODULE_LOADIMAGE_END_ID:
+      *RecordSize = sizeof (FPDT_GUID_QWORD_EVENT_RECORD);
+      break;
+
+    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;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8) (sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD) + 
StringSize);
+      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) {
+        return EFI_INVALID_PARAMETER;
+      }
+      StringSize = AsciiStrSize (String);
+      if (StringSize > STRING_SIZE) {
+        StringSize = STRING_SIZE;
+      }
+      *RecordSize = (UINT8) (sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD) + 
StringSize);
+      break;
+
+    default:
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+  return EFI_SUCCESS;
+}
+
+/**
+  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 PerfId            - Performance identifier describing the type of 
measurement
+
+  @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
+InsertFpdtRecord (
+  IN CONST VOID                    *CallerIdentifier,  OPTIONAL
+  IN CONST VOID                    *Guid,    OPTIONAL
+  IN CONST CHAR8                   *String,  OPTIONAL
+  IN       UINT64                  Address,  OPTIONAL
+  IN       UINT16                  PerfId
+  )
+{
+  EFI_STATUS                   Status;
+  EFI_GUID                     ModuleGuid;
+  CHAR8                        
ModuleName[FPDT_STRING_EVENT_RECORD_NAME_LENGTH];
+  FPDT_RECORD_PTR              FpdtRecordPtr;
+  FPDT_RECORD_PTR              CachedFpdtRecordPtr;
+  UINT64                       TimeStamp;
+  UINT64                       TimeStampCounter;
+  CONST CHAR8                  *StringPtr;
+  UINT8                        RecordSize;
+  UINTN                        DestMax;
+  UINTN                        StringLen;
+
+  StringPtr     = NULL;
+  RecordSize    = 0;
+  ZeroMem (ModuleName, sizeof (ModuleName));
+
+  Status = GetFpdtRecordSize(String, PerfId, &RecordSize);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = GetFpdtRecordPtr (RecordSize, &FpdtRecordPtr);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Get the TimeStamp.
+  //
+  TimeStampCounter = GetPerformanceCounter ();
+  TimeStamp        = GetTimeInNanoSecond (TimeStampCounter);
+
+  switch (PerfId) {
+  case MODULE_START_ID:
+  case MODULE_END_ID:
+    //
+    // Get the ModuleGuid from the handle.
+    //
+    GetModuleInfoFromHandle ((EFI_HANDLE *)CallerIdentifier, ModuleName, 
sizeof (ModuleName), &ModuleGuid);
+    StringPtr = ModuleName;
+    if (PerfId == MODULE_START_ID) {
+      mCachedLength = mSmmBootPerformanceTable->Header.Length;
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidEvent->Header.Type                = 
FPDT_GUID_EVENT_TYPE;
+      FpdtRecordPtr.GuidEvent->Header.Length              = RecordSize;
+      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 (PerfId == MODULE_END_ID && mCachedLength != 0) {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+        CopyMem (&CachedFpdtRecordPtr.GuidEvent->Guid, &ModuleGuid, sizeof 
(CachedFpdtRecordPtr.GuidEvent->Guid));
+        mCachedLength = 0;
+      }
+    }
+    break;
+
+  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++;
+      mCachedLength = mSmmBootPerformanceTable->Header.Length;
+    }
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.GuidQwordEvent->Header.Type           = 
FPDT_GUID_QWORD_EVENT_TYPE;
+      FpdtRecordPtr.GuidQwordEvent->Header.Length         = RecordSize;
+      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 PERF_EVENTSIGNAL_START_ID:
+  case PERF_EVENTSIGNAL_END_ID:
+  case PERF_CALLBACK_START_ID:
+  case PERF_CALLBACK_END_ID:
+    if (CallerIdentifier == NULL || Guid ==NULL || 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    = RecordSize;
+      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));
+      DestMax = (RecordSize - sizeof (FPDT_DUAL_GUID_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DualGuidStringEvent->String, DestMax, 
StringPtr, StringLen);
+    }
+    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 (CallerIdentifier == NULL || String == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    CopyGuid (&ModuleGuid, (EFI_GUID *) CallerIdentifier);
+    StringPtr = String;
+    if (!PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+      FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+      FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+      FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+      FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+      FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+      CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, CallerIdentifier, 
sizeof (FpdtRecordPtr.DynamicStringEvent->Guid));
+      DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+      AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+    }
+    break;
+
+  default:
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (PcdGetBool (PcdEdkiiFpdtStringRecordEnableOnly)) {
+    FpdtRecordPtr.DynamicStringEvent->Header.Type       = 
FPDT_DYNAMIC_STRING_EVENT_TYPE;
+    FpdtRecordPtr.DynamicStringEvent->Header.Length     = RecordSize;
+    FpdtRecordPtr.DynamicStringEvent->Header.Revision   = 
FPDT_RECORD_REVISION_1;
+    FpdtRecordPtr.DynamicStringEvent->ProgressID        = PerfId;
+    FpdtRecordPtr.DynamicStringEvent->Timestamp         = TimeStamp;
+    DestMax = (RecordSize - sizeof (FPDT_DYNAMIC_STRING_EVENT_RECORD)) / 
sizeof (CHAR8);
+    if (StringPtr != NULL && AsciiStrLen (StringPtr) == 0) {
+      StringPtr = "unknown name";
+    }
+    if (StringPtr != NULL) {
+      StringLen = AsciiStrLen (StringPtr);
+      if (StringLen >= DestMax) {
+        StringLen = DestMax -1;
+      }
+    }
+
+    CopyMem (&FpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, sizeof 
(FpdtRecordPtr.DynamicStringEvent->Guid));
+    AsciiStrnCpyS (FpdtRecordPtr.DynamicStringEvent->String, DestMax, 
StringPtr, StringLen);
+
+    if ((PerfId == MODULE_LOADIMAGE_END_ID) || (PerfId == MODULE_END_ID)) {
+      if (mCachedLength != 0) {
+        CachedFpdtRecordPtr.RecordHeader = 
(EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER 
*)((UINT8*)mSmmBootPerformanceTable + mCachedLength);
+        CopyMem (&CachedFpdtRecordPtr.DynamicStringEvent->Guid, &ModuleGuid, 
sizeof (CachedFpdtRecordPtr.DynamicStringEvent->Guid));
+        AsciiStrnCpyS (CachedFpdtRecordPtr.DynamicStringEvent->String, 
DestMax, StringPtr, StringLen);
+        mCachedLength = 0;
+      }
+    }
+  }
+
+  //
+  // Update the cached FPDT record buffer.
+  //
+  mPerformanceLength += FpdtRecordPtr.RecordHeader->Length;
+  mSmmBootPerformanceTable->Header.Length += 
FpdtRecordPtr.RecordHeader->Length;
+
+  return EFI_SUCCESS;
+}
+
 /**
   SmmReadyToBoot protocol notification event handler.
 
   @param  Protocol   Points to the protocol's unique identifier
   @param  Interface  Points to the interface instance
@@ -814,15 +1118,19 @@ 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);
+  } else if (Attribute == PerfEntry) {
+    Status = InsertFpdtRecord (CallerIdentifier, Guid, String, Address, 
(UINT16) Identifier);
   }
   ReleaseSpinLock (&mSmmFpdtLock);
   return Status;
 }
 
@@ -1125,5 +1433,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