Home | History | Annotate | Download | only in GenericBdsLib
      1 /** @file
      2   This file include the file which can help to get the system
      3   performance, all the function will only include if the performance
      4   switch is set.
      5 
      6 Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 **/
     16 
     17 #include "InternalBdsLib.h"
     18 
     19 PERF_HEADER               mPerfHeader;
     20 PERF_DATA                 mPerfData;
     21 EFI_PHYSICAL_ADDRESS      mAcpiLowMemoryBase = 0x0FFFFFFFFULL;
     22 
     23 /**
     24   Get the short verion of PDB file name to be
     25   used in performance data logging.
     26 
     27   @param PdbFileName     The long PDB file name.
     28   @param GaugeString     The output string to be logged by performance logger.
     29 
     30 **/
     31 VOID
     32 GetShortPdbFileName (
     33   IN  CONST CHAR8  *PdbFileName,
     34   OUT       CHAR8  *GaugeString
     35   )
     36 {
     37   UINTN Index;
     38   UINTN Index1;
     39   UINTN StartIndex;
     40   UINTN EndIndex;
     41 
     42   if (PdbFileName == NULL) {
     43     AsciiStrCpy (GaugeString, " ");
     44   } else {
     45     StartIndex = 0;
     46     for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
     47       ;
     48 
     49     for (Index = 0; PdbFileName[Index] != 0; Index++) {
     50       if (PdbFileName[Index] == '\\') {
     51         StartIndex = Index + 1;
     52       }
     53 
     54       if (PdbFileName[Index] == '.') {
     55         EndIndex = Index;
     56       }
     57     }
     58 
     59     Index1 = 0;
     60     for (Index = StartIndex; Index < EndIndex; Index++) {
     61       GaugeString[Index1] = PdbFileName[Index];
     62       Index1++;
     63       if (Index1 == PERF_TOKEN_LENGTH - 1) {
     64         break;
     65       }
     66     }
     67 
     68     GaugeString[Index1] = 0;
     69   }
     70 
     71   return ;
     72 }
     73 
     74 /**
     75   Get the name from the Driver handle, which can be a handle with
     76   EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
     77   This name can be used in performance data logging.
     78 
     79   @param Handle          Driver handle.
     80   @param GaugeString     The output string to be logged by performance logger.
     81 
     82 **/
     83 VOID
     84 GetNameFromHandle (
     85   IN  EFI_HANDLE     Handle,
     86   OUT CHAR8          *GaugeString
     87   )
     88 {
     89   EFI_STATUS                  Status;
     90   EFI_LOADED_IMAGE_PROTOCOL   *Image;
     91   CHAR8                       *PdbFileName;
     92   EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
     93 
     94   AsciiStrCpy (GaugeString, " ");
     95 
     96   //
     97   // Get handle name from image protocol
     98   //
     99   Status = gBS->HandleProtocol (
    100                   Handle,
    101                   &gEfiLoadedImageProtocolGuid,
    102                   (VOID **) &Image
    103                   );
    104 
    105   if (EFI_ERROR (Status)) {
    106     Status = gBS->OpenProtocol (
    107                     Handle,
    108                     &gEfiDriverBindingProtocolGuid,
    109                     (VOID **) &DriverBinding,
    110                     NULL,
    111                     NULL,
    112                     EFI_OPEN_PROTOCOL_GET_PROTOCOL
    113                     );
    114     if (EFI_ERROR (Status)) {
    115       return ;
    116     }
    117     //
    118     // Get handle name from image protocol
    119     //
    120     Status = gBS->HandleProtocol (
    121                     DriverBinding->ImageHandle,
    122                     &gEfiLoadedImageProtocolGuid,
    123                     (VOID **) &Image
    124                     );
    125   }
    126 
    127   PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
    128 
    129   if (PdbFileName != NULL) {
    130     GetShortPdbFileName (PdbFileName, GaugeString);
    131   }
    132 
    133   return ;
    134 }
    135 
    136 /**
    137 
    138   Writes performance data of booting into the allocated memory.
    139   OS can process these records.
    140 
    141   @param  Event                 The triggered event.
    142   @param  Context               Context for this event.
    143 
    144 **/
    145 VOID
    146 EFIAPI
    147 WriteBootToOsPerformanceData (
    148   IN EFI_EVENT  Event,
    149   IN VOID       *Context
    150   )
    151 {
    152   EFI_STATUS                Status;
    153   UINT32                    LimitCount;
    154   EFI_HANDLE                *Handles;
    155   UINTN                     NoHandles;
    156   CHAR8                     GaugeString[PERF_TOKEN_LENGTH];
    157   UINT8                     *Ptr;
    158   UINT32                    Index;
    159   UINT64                    Ticker;
    160   UINT64                    Freq;
    161   UINT32                    Duration;
    162   UINTN                     LogEntryKey;
    163   CONST VOID                *Handle;
    164   CONST CHAR8               *Token;
    165   CONST CHAR8               *Module;
    166   UINT64                    StartTicker;
    167   UINT64                    EndTicker;
    168   UINT64                    StartValue;
    169   UINT64                    EndValue;
    170   BOOLEAN                   CountUp;
    171   UINTN                     EntryIndex;
    172   UINTN                     NumPerfEntries;
    173   //
    174   // List of flags indicating PerfEntry contains DXE handle
    175   //
    176   BOOLEAN                   *PerfEntriesAsDxeHandle;
    177   UINTN                     VarSize;
    178 
    179   //
    180   // Record the performance data for End of BDS
    181   //
    182   PERF_END(NULL, "BDS", NULL, 0);
    183 
    184   //
    185   // Retrieve time stamp count as early as possible
    186   //
    187   Ticker  = GetPerformanceCounter ();
    188 
    189   Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
    190 
    191   Freq    = DivU64x32 (Freq, 1000);
    192 
    193   mPerfHeader.CpuFreq = Freq;
    194 
    195   //
    196   // Record BDS raw performance data
    197   //
    198   if (EndValue >= StartValue) {
    199     mPerfHeader.BDSRaw = Ticker - StartValue;
    200     CountUp            = TRUE;
    201   } else {
    202     mPerfHeader.BDSRaw = StartValue - Ticker;
    203     CountUp            = FALSE;
    204   }
    205 
    206   if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
    207     VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
    208     Status = gRT->GetVariable (
    209                     L"PerfDataMemAddr",
    210                     &gPerformanceProtocolGuid,
    211                     NULL,
    212                     &VarSize,
    213                     &mAcpiLowMemoryBase
    214                     );
    215     if (EFI_ERROR (Status)) {
    216       //
    217       // Fail to get the variable, return.
    218       //
    219       return;
    220     }
    221   }
    222 
    223   //
    224   // Put Detailed performance data into memory
    225   //
    226   Handles = NULL;
    227   Status = gBS->LocateHandleBuffer (
    228                   AllHandles,
    229                   NULL,
    230                   NULL,
    231                   &NoHandles,
    232                   &Handles
    233                   );
    234   if (EFI_ERROR (Status)) {
    235     return ;
    236   }
    237 
    238   Ptr        = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
    239   LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
    240 
    241   NumPerfEntries = 0;
    242   LogEntryKey    = 0;
    243   while ((LogEntryKey = GetPerformanceMeasurement (
    244                           LogEntryKey,
    245                           &Handle,
    246                           &Token,
    247                           &Module,
    248                           &StartTicker,
    249                           &EndTicker)) != 0) {
    250     NumPerfEntries++;
    251   }
    252   PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN));
    253   ASSERT (PerfEntriesAsDxeHandle != NULL);
    254 
    255   //
    256   // Get DXE drivers performance
    257   //
    258   for (Index = 0; Index < NoHandles; Index++) {
    259     Ticker = 0;
    260     LogEntryKey = 0;
    261     EntryIndex  = 0;
    262     while ((LogEntryKey = GetPerformanceMeasurement (
    263                             LogEntryKey,
    264                             &Handle,
    265                             &Token,
    266                             &Module,
    267                             &StartTicker,
    268                             &EndTicker)) != 0) {
    269       if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) {
    270         PerfEntriesAsDxeHandle[EntryIndex] = TRUE;
    271       }
    272       EntryIndex++;
    273       if ((Handle == Handles[Index]) && (EndTicker != 0)) {
    274         if (StartTicker == 1) {
    275           StartTicker = StartValue;
    276         }
    277         if (EndTicker == 1) {
    278           EndTicker = StartValue;
    279         }
    280         Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
    281       }
    282     }
    283 
    284     Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
    285 
    286     if (Duration > 0) {
    287 
    288       GetNameFromHandle (Handles[Index], GaugeString);
    289 
    290       AsciiStrCpy (mPerfData.Token, GaugeString);
    291       mPerfData.Duration = Duration;
    292 
    293       CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
    294       Ptr += sizeof (PERF_DATA);
    295 
    296       mPerfHeader.Count++;
    297       if (mPerfHeader.Count == LimitCount) {
    298         goto Done;
    299       }
    300     }
    301   }
    302 
    303   //
    304   // Get inserted performance data
    305   //
    306   LogEntryKey = 0;
    307   EntryIndex  = 0;
    308   while ((LogEntryKey = GetPerformanceMeasurement (
    309                           LogEntryKey,
    310                           &Handle,
    311                           &Token,
    312                           &Module,
    313                           &StartTicker,
    314                           &EndTicker)) != 0) {
    315     if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) {
    316 
    317       ZeroMem (&mPerfData, sizeof (PERF_DATA));
    318 
    319       AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH);
    320       if (StartTicker == 1) {
    321         StartTicker = StartValue;
    322       }
    323       if (EndTicker == 1) {
    324         EndTicker = StartValue;
    325       }
    326       Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
    327 
    328       mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
    329 
    330       CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
    331       Ptr += sizeof (PERF_DATA);
    332 
    333       mPerfHeader.Count++;
    334       if (mPerfHeader.Count == LimitCount) {
    335         goto Done;
    336       }
    337     }
    338     EntryIndex++;
    339   }
    340 
    341 Done:
    342 
    343   FreePool (Handles);
    344   FreePool (PerfEntriesAsDxeHandle);
    345 
    346   mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
    347 
    348   //
    349   // Put performance data to Reserved memory
    350   //
    351   CopyMem (
    352     (UINTN *) (UINTN) mAcpiLowMemoryBase,
    353     &mPerfHeader,
    354     sizeof (PERF_HEADER)
    355     );
    356 
    357   return ;
    358 }
    359