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 - 2015, 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     AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
     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) {
     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   AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
     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_SIZE];
    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                     VarSize;
    172   BOOLEAN                   Found;
    173 
    174   //
    175   // Record the performance data for End of BDS
    176   //
    177   PERF_END(NULL, "BDS", NULL, 0);
    178 
    179   //
    180   // Retrieve time stamp count as early as possible
    181   //
    182   Ticker  = GetPerformanceCounter ();
    183 
    184   Freq    = GetPerformanceCounterProperties (&StartValue, &EndValue);
    185 
    186   Freq    = DivU64x32 (Freq, 1000);
    187 
    188   mPerfHeader.CpuFreq = Freq;
    189 
    190   //
    191   // Record BDS raw performance data
    192   //
    193   if (EndValue >= StartValue) {
    194     mPerfHeader.BDSRaw = Ticker - StartValue;
    195     CountUp            = TRUE;
    196   } else {
    197     mPerfHeader.BDSRaw = StartValue - Ticker;
    198     CountUp            = FALSE;
    199   }
    200 
    201   //
    202   // Reset the entry count
    203   //
    204   mPerfHeader.Count = 0;
    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   //
    242   // Get performance data
    243   //
    244   LogEntryKey = 0;
    245   while ((LogEntryKey = GetPerformanceMeasurement (
    246                           LogEntryKey,
    247                           &Handle,
    248                           &Token,
    249                           &Module,
    250                           &StartTicker,
    251                           &EndTicker)) != 0) {
    252     if (EndTicker != 0) {
    253       if (StartTicker == 1) {
    254         StartTicker = StartValue;
    255       }
    256       if (EndTicker == 1) {
    257         EndTicker = StartValue;
    258       }
    259       Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
    260 
    261       Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
    262       if (Duration == 0) {
    263         continue;
    264       }
    265 
    266       ZeroMem (&mPerfData, sizeof (PERF_DATA));
    267 
    268       mPerfData.Duration = Duration;
    269 
    270       //
    271       // See if the Handle is in the handle buffer
    272       //
    273       Found = FALSE;
    274       for (Index = 0; Index < NoHandles; Index++) {
    275         if (Handle == Handles[Index]) {
    276           GetNameFromHandle (Handles[Index], GaugeString);
    277           AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
    278           Found = TRUE;
    279           break;
    280         }
    281       }
    282 
    283       if (!Found) {
    284         AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
    285       }
    286 
    287       CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
    288       Ptr += sizeof (PERF_DATA);
    289 
    290       mPerfHeader.Count++;
    291       if (mPerfHeader.Count == LimitCount) {
    292         goto Done;
    293       }
    294     }
    295   }
    296 
    297 Done:
    298 
    299   FreePool (Handles);
    300 
    301   mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
    302 
    303   //
    304   // Put performance data to Reserved memory
    305   //
    306   CopyMem (
    307     (UINTN *) (UINTN) mAcpiLowMemoryBase,
    308     &mPerfHeader,
    309     sizeof (PERF_HEADER)
    310     );
    311 
    312   return ;
    313 }
    314