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