]> git.proxmox.com Git - mirror_edk2.git/blobdiff - EdkUnixPkg/Library/EdkGenericBdsLib/Performance.c
Unix version of EFI emulator
[mirror_edk2.git] / EdkUnixPkg / Library / EdkGenericBdsLib / Performance.c
diff --git a/EdkUnixPkg/Library/EdkGenericBdsLib/Performance.c b/EdkUnixPkg/Library/EdkGenericBdsLib/Performance.c
new file mode 100644 (file)
index 0000000..4bf5e8a
--- /dev/null
@@ -0,0 +1,399 @@
+/*++\r
+\r
+Copyright (c) 2006, Intel Corporation                                                         \r
+All rights reserved. This program and the accompanying materials                          \r
+are licensed and made available under the terms and conditions of the BSD License         \r
+which accompanies this distribution.  The full text of the license may be found at        \r
+http://opensource.org/licenses/bsd-license.php                                            \r
+                                                                                          \r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
+\r
+Module Name:\r
+\r
+  Performance.c\r
+\r
+Abstract:\r
+\r
+  This file include the file which can help to get the system\r
+  performance, all the function will only include if the performance\r
+  switch is set.\r
+\r
+--*/\r
+\r
+#include "Performance.h"\r
+\r
+VOID\r
+ClearDebugRegisters (\r
+  VOID\r
+  )\r
+{\r
+  //\r
+  // BugBug: We should not need to do this. We need to root cause this bug!!!!\r
+  //\r
+  AsmWriteDr0 (0);\r
+  AsmWriteDr1 (0);\r
+}\r
+\r
+STATIC\r
+VOID\r
+GetShortPdbFileName (\r
+  CHAR8  *PdbFileName,\r
+  CHAR8  *GaugeString\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+Arguments:\r
+\r
+Returns:\r
+\r
+--*/\r
+{\r
+  UINTN Index;\r
+  UINTN Index1;\r
+  UINTN StartIndex;\r
+  UINTN EndIndex;\r
+\r
+  if (PdbFileName == NULL) {\r
+    AsciiStrCpy (GaugeString, " ");\r
+  } else {\r
+    StartIndex = 0;\r
+    for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
+      ;\r
+\r
+    for (Index = 0; PdbFileName[Index] != 0; Index++) {\r
+      if (PdbFileName[Index] == '\\') {\r
+        StartIndex = Index + 1;\r
+      }\r
+\r
+      if (PdbFileName[Index] == '.') {\r
+        EndIndex = Index;\r
+      }\r
+    }\r
+\r
+    Index1 = 0;\r
+    for (Index = StartIndex; Index < EndIndex; Index++) {\r
+      GaugeString[Index1] = PdbFileName[Index];\r
+      Index1++;\r
+      if (Index1 == PERF_TOKEN_LENGTH - 1) {\r
+        break;\r
+      }\r
+    }\r
+\r
+    GaugeString[Index1] = 0;\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+\r
+\r
+STATIC\r
+CHAR8 *\r
+GetPdbPath (\r
+  VOID *ImageBase\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Located PDB path name in PE image\r
+\r
+Arguments:\r
+\r
+  ImageBase - base of PE to search\r
+\r
+Returns:\r
+\r
+  Pointer into image at offset of PDB file name if PDB file name is found,\r
+  Otherwise a pointer to an empty string.\r
+\r
+--*/\r
+{\r
+  PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;\r
+\r
+  ZeroMem (&ImageContext, sizeof (ImageContext));\r
+  ImageContext.Handle    = ImageBase;\r
+  ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;\r
+\r
+  PeCoffLoaderGetImageInfo (&ImageContext);\r
+\r
+  return ImageContext.PdbPointer;\r
+}\r
+\r
+\r
+STATIC\r
+VOID\r
+GetNameFromHandle (\r
+  IN  EFI_HANDLE     Handle,\r
+  OUT CHAR8          *GaugeString\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  EFI_LOADED_IMAGE_PROTOCOL   *Image;\r
+  CHAR8                       *PdbFileName;\r
+  EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
+\r
+  AsciiStrCpy (GaugeString, " ");\r
+\r
+  //\r
+  // Get handle name from image protocol\r
+  //\r
+  Status = gBS->HandleProtocol (\r
+                  Handle,\r
+                  &gEfiLoadedImageProtocolGuid,\r
+                  (VOID **)&Image\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    Status = gBS->OpenProtocol (\r
+                    Handle,\r
+                    &gEfiDriverBindingProtocolGuid,\r
+                    (VOID **) &DriverBinding,\r
+                    NULL,\r
+                    NULL,\r
+                    EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
+                    );\r
+    if (EFI_ERROR (Status)) {\r
+      return ;\r
+    }\r
+    //\r
+    // Get handle name from image protocol\r
+    //\r
+    Status = gBS->HandleProtocol (\r
+                    DriverBinding->ImageHandle,\r
+                    &gEfiLoadedImageProtocolGuid,\r
+                    (VOID **)&Image\r
+                    );\r
+  }\r
+\r
+  PdbFileName = GetPdbPath (Image->ImageBase);\r
+\r
+  if (PdbFileName != NULL) {\r
+    GetShortPdbFileName (PdbFileName, GaugeString);\r
+  }\r
+\r
+  return ;\r
+}\r
+\r
+\r
+\r
+VOID\r
+WriteBootToOsPerformanceData (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  \r
+  Allocates a block of memory and writes performance data of booting to OS into it.\r
+\r
+Arguments:\r
+  \r
+  None\r
+  \r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  EFI_STATUS                Status;\r
+  EFI_CPU_ARCH_PROTOCOL     *Cpu;\r
+  EFI_PHYSICAL_ADDRESS      mAcpiLowMemoryBase;\r
+  UINT32                    mAcpiLowMemoryLength;\r
+  UINT32                    LimitCount;\r
+  PERF_HEADER               mPerfHeader;\r
+  PERF_DATA                 mPerfData;\r
+  EFI_HANDLE                *Handles;\r
+  UINTN                     NoHandles;\r
+  CHAR8                     GaugeString[PERF_TOKEN_LENGTH];\r
+  UINT8                     *Ptr;\r
+  UINT32                    mIndex;\r
+  UINT64                    Ticker;\r
+  UINT64                    Freq;\r
+  UINT32                    Duration;\r
+  UINT64                    CurrentTicker;\r
+  UINT64                    TimerPeriod;\r
+  UINTN                     LogEntryKey;\r
+  CONST VOID                *Handle;\r
+  CONST CHAR8               *Token;\r
+  CONST CHAR8               *Module;\r
+  UINT64                    StartTicker;\r
+  UINT64                    EndTicker;\r
+\r
+  //\r
+  // Retrive time stamp count as early as possilbe\r
+  //\r
+  Ticker = AsmReadTsc ();\r
+\r
+  //\r
+  // Allocate a block of memory that contain performance data to OS\r
+  //\r
+  mAcpiLowMemoryBase = 0xFFFFFFFF;\r
+  Status = gBS->AllocatePages (\r
+                  AllocateMaxAddress,\r
+                  EfiReservedMemoryType,\r
+                  4,\r
+                  &mAcpiLowMemoryBase\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    return ;\r
+  }\r
+\r
+  mAcpiLowMemoryLength  = EFI_PAGES_TO_SIZE(4);\r
+\r
+  Ptr                   = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));\r
+  LimitCount            = (mAcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);\r
+\r
+  //\r
+  // Initialize performance data structure\r
+  //\r
+  ZeroMem (&mPerfHeader, sizeof (PERF_HEADER));\r
+\r
+  //\r
+  // Get CPU frequency\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiCpuArchProtocolGuid,\r
+                  NULL,\r
+                  (VOID **)&Cpu\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (mAcpiLowMemoryBase, 4);\r
+    return ;\r
+  }\r
+  //\r
+  // Get Cpu Frequency\r
+  //\r
+  Status = Cpu->GetTimerValue (Cpu, 0, &(CurrentTicker), &TimerPeriod);\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (mAcpiLowMemoryBase, 4);\r
+    return ;\r
+  }\r
+\r
+  Freq                = DivU64x32 (1000000000000UL, (UINTN) TimerPeriod);\r
+\r
+  mPerfHeader.CpuFreq = Freq;\r
+\r
+  //\r
+  // Record BDS raw performance data\r
+  //\r
+  mPerfHeader.BDSRaw = Ticker;\r
+\r
+  //\r
+  // Put Detailed performance data into memory\r
+  //\r
+  Handles = NULL;\r
+  Status = gBS->LocateHandleBuffer (\r
+                  AllHandles,\r
+                  NULL,\r
+                  NULL,\r
+                  &NoHandles,\r
+                  &Handles\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    gBS->FreePages (mAcpiLowMemoryBase, 4);\r
+    return ;\r
+  }\r
+  //\r
+  // Get DXE drivers performance\r
+  //\r
+  for (mIndex = 0; mIndex < NoHandles; mIndex++) {\r
+    Ticker = 0;\r
+    LogEntryKey = 0;\r
+    while ((LogEntryKey = GetPerformanceMeasurement (\r
+                            LogEntryKey,\r
+                            &Handle,\r
+                            &Token,\r
+                            &Module,\r
+                            &StartTicker,\r
+                            &EndTicker)) != 0) {\r
+      if ((Handle == Handles[mIndex]) && (StartTicker < EndTicker)) {\r
+        Ticker += (EndTicker - StartTicker);\r
+      }\r
+    }\r
+\r
+    Duration = (UINT32) DivU64x32 (\r
+                          Ticker,\r
+                          (UINT32) Freq\r
+                          );\r
+\r
+    if (Duration > 0) {\r
+      ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
+\r
+      GetNameFromHandle (Handles[mIndex], GaugeString);\r
+\r
+      AsciiStrCpy (mPerfData.Token, GaugeString);\r
+      mPerfData.Duration = Duration;\r
+\r
+      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
+      Ptr += sizeof (PERF_DATA);\r
+\r
+      mPerfHeader.Count++;\r
+      if (mPerfHeader.Count == LimitCount) {\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
+  gBS->FreePool (Handles);\r
+\r
+  //\r
+  // Get inserted performance data\r
+  //\r
+  LogEntryKey = 0;\r
+  while ((LogEntryKey = GetPerformanceMeasurement (\r
+                          LogEntryKey,\r
+                          &Handle,\r
+                          &Token,\r
+                          &Module,\r
+                          &StartTicker,\r
+                          &EndTicker)) != 0) {\r
+    if ((Handle == NULL) && (StartTicker <= EndTicker)) {\r
+\r
+      ZeroMem (&mPerfData, sizeof (PERF_DATA));\r
+\r
+      AsciiStrnCpy (mPerfData.Token, Token, DXE_PERFORMANCE_STRING_SIZE);\r
+      mPerfData.Duration = (UINT32) DivU64x32 (\r
+                                      EndTicker - StartTicker,\r
+                                      (UINT32) Freq\r
+                                      );\r
+\r
+      CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));\r
+      Ptr += sizeof (PERF_DATA);\r
+\r
+      mPerfHeader.Count++;\r
+      if (mPerfHeader.Count == LimitCount) {\r
+        goto Done;\r
+      }\r
+    }\r
+  }\r
+\r
+Done:\r
+\r
+  ClearDebugRegisters ();\r
+\r
+  mPerfHeader.Signiture = 0x66726550;\r
+\r
+  //\r
+  // Put performance data to memory\r
+  //\r
+  CopyMem (\r
+    (UINT32 *) (UINT32) mAcpiLowMemoryBase,\r
+    &mPerfHeader,\r
+    sizeof (PERF_HEADER)\r
+    );\r
+\r
+  gRT->SetVariable (\r
+        L"PerfDataMemAddr",\r
+        &gEfiGlobalVariableGuid,\r
+        EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r
+        sizeof (UINT32),\r
+        (VOID *) &mAcpiLowMemoryBase\r
+        );\r
+\r
+  return ;\r
+}\r