]> git.proxmox.com Git - mirror_edk2.git/blame - ShellPkg/Library/UefiDpLib/DpUtilities.c
PerformancePkg Dp_App: Remove TimerLib dependency
[mirror_edk2.git] / ShellPkg / Library / UefiDpLib / DpUtilities.c
CommitLineData
d41bc92c 1/** @file\r
2 Utility functions used by the Dp application.\r
3\r
3b672240 4 Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.\r
69af8476 5 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>\r
d41bc92c 6 This program and the accompanying materials\r
7 are licensed and made available under the terms and conditions of the BSD License\r
8 which accompanies this distribution. The full text of the license may be found at\r
9 http://opensource.org/licenses/bsd-license.php\r
10\r
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13**/\r
14\r
15#include <Library/BaseLib.h>\r
16#include <Library/BaseMemoryLib.h>\r
17#include <Library/MemoryAllocationLib.h>\r
18#include <Library/DebugLib.h>\r
19#include <Library/UefiBootServicesTableLib.h>\r
20#include <Library/TimerLib.h>\r
21#include <Library/PeCoffGetEntryPointLib.h>\r
22#include <Library/PrintLib.h>\r
23#include <Library/HiiLib.h>\r
24#include <Library/PcdLib.h>\r
25#include <Library/UefiLib.h>\r
26#include <Library/DevicePathLib.h>\r
a71003f2 27#include <Library/HandleParsingLib.h>\r
d41bc92c 28\r
29#include <Pi/PiFirmwareFile.h>\r
30#include <Library/DxeServicesLib.h>\r
31\r
32#include <Protocol/LoadedImage.h>\r
33#include <Protocol/DriverBinding.h>\r
34#include <Protocol/ComponentName2.h>\r
35#include <Protocol/DevicePath.h>\r
d41bc92c 36\r
37#include <Guid/Performance.h>\r
38\r
39#include "Dp.h"\r
40#include "Literals.h"\r
41#include "DpInternal.h"\r
42\r
43/** \r
44 Calculate an event's duration in timer ticks.\r
45 \r
46 Given the count direction and the event's start and end timer values,\r
47 calculate the duration of the event in timer ticks. Information for\r
48 the current measurement is pointed to by the parameter.\r
49 \r
50 If the measurement's start time is 1, it indicates that the developer\r
51 is indicating that the measurement began at the release of reset.\r
52 The start time is adjusted to the timer's starting count before performing\r
53 the elapsed time calculation.\r
54 \r
55 The calculated duration, in ticks, is the absolute difference between\r
56 the measurement's ending and starting counts.\r
57 \r
58 @param Measurement Pointer to a MEASUREMENT_RECORD structure containing\r
59 data for the current measurement.\r
60 \r
61 @return The 64-bit duration of the event.\r
62**/\r
63UINT64\r
64GetDuration (\r
65 IN OUT MEASUREMENT_RECORD *Measurement\r
66 )\r
67{\r
68 UINT64 Duration;\r
69 BOOLEAN Error;\r
70\r
69af8476
CS
71 if (Measurement->EndTimeStamp == 0) {\r
72 return 0;\r
73 }\r
74\r
d41bc92c 75 // PERF_START macros are called with a value of 1 to indicate\r
76 // the beginning of time. So, adjust the start ticker value\r
77 // to the real beginning of time.\r
78 // Assumes no wraparound. Even then, there is a very low probability\r
79 // of having a valid StartTicker value of 1.\r
80 if (Measurement->StartTimeStamp == 1) {\r
81 Measurement->StartTimeStamp = TimerInfo.StartCount;\r
82 }\r
83 if (TimerInfo.CountUp) {\r
84 Duration = Measurement->EndTimeStamp - Measurement->StartTimeStamp;\r
85 Error = (BOOLEAN)(Duration > Measurement->EndTimeStamp);\r
86 }\r
87 else {\r
88 Duration = Measurement->StartTimeStamp - Measurement->EndTimeStamp;\r
89 Error = (BOOLEAN)(Duration > Measurement->StartTimeStamp);\r
90 }\r
91\r
92 if (Error) {\r
93 DEBUG ((EFI_D_ERROR, ALit_TimerLibError));\r
94 Duration = 0;\r
95 }\r
96 return Duration;\r
97}\r
98\r
99/** \r
100 Determine whether the Measurement record is for an EFI Phase.\r
101 \r
102 The Token and Module members of the measurement record are checked.\r
103 Module must be empty and Token must be one of SEC, PEI, DXE, BDS, or SHELL.\r
104 \r
105 @param[in] Measurement A pointer to the Measurement record to test.\r
106 \r
107 @retval TRUE The measurement record is for an EFI Phase.\r
108 @retval FALSE The measurement record is NOT for an EFI Phase.\r
109**/\r
110BOOLEAN\r
111IsPhase(\r
112 IN MEASUREMENT_RECORD *Measurement\r
113 )\r
114{\r
115 BOOLEAN RetVal;\r
116\r
117 RetVal = (BOOLEAN)( ( *Measurement->Module == '\0') &&\r
118 ((AsciiStrnCmp (Measurement->Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0) ||\r
119 (AsciiStrnCmp (Measurement->Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0) ||\r
120 (AsciiStrnCmp (Measurement->Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0) ||\r
121 (AsciiStrnCmp (Measurement->Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0))\r
122 );\r
123 return RetVal;\r
124}\r
125\r
126/** \r
127 Get the file name portion of the Pdb File Name.\r
128 \r
129 The portion of the Pdb File Name between the last backslash and\r
130 either a following period or the end of the string is converted\r
131 to Unicode and copied into UnicodeBuffer. The name is truncated,\r
132 if necessary, to ensure that UnicodeBuffer is not overrun.\r
133 \r
134 @param[in] PdbFileName Pdb file name.\r
135 @param[out] UnicodeBuffer The resultant Unicode File Name.\r
136 \r
137**/\r
138VOID\r
2c55a81a 139DpGetShortPdbFileName (\r
d41bc92c 140 IN CHAR8 *PdbFileName,\r
141 OUT CHAR16 *UnicodeBuffer\r
142 )\r
143{\r
144 UINTN IndexA; // Current work location within an ASCII string.\r
145 UINTN IndexU; // Current work location within a Unicode string.\r
146 UINTN StartIndex;\r
147 UINTN EndIndex;\r
148\r
e75390f0 149 ZeroMem (UnicodeBuffer, (DP_GAUGE_STRING_LENGTH + 1) * sizeof (CHAR16));\r
d41bc92c 150\r
151 if (PdbFileName == NULL) {\r
e75390f0 152 StrnCpyS (UnicodeBuffer, DP_GAUGE_STRING_LENGTH + 1, L" ", 1);\r
d41bc92c 153 } else {\r
154 StartIndex = 0;\r
155 for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)\r
156 ;\r
157 for (IndexA = 0; PdbFileName[IndexA] != 0; IndexA++) {\r
158 if (PdbFileName[IndexA] == '\\') {\r
159 StartIndex = IndexA + 1;\r
160 }\r
161\r
162 if (PdbFileName[IndexA] == '.') {\r
163 EndIndex = IndexA;\r
164 }\r
165 }\r
166\r
167 IndexU = 0;\r
168 for (IndexA = StartIndex; IndexA < EndIndex; IndexA++) {\r
169 UnicodeBuffer[IndexU] = (CHAR16) PdbFileName[IndexA];\r
170 IndexU++;\r
b9ffeab7
SZ
171 if (IndexU >= DP_GAUGE_STRING_LENGTH) {\r
172 UnicodeBuffer[DP_GAUGE_STRING_LENGTH] = 0;\r
d41bc92c 173 break;\r
174 }\r
175 }\r
176 }\r
177}\r
178\r
179/** \r
180 Get a human readable name for an image handle.\r
181 The following methods will be tried orderly:\r
182 1. Image PDB\r
183 2. ComponentName2 protocol\r
184 3. FFS UI section\r
185 4. Image GUID\r
186 5. Image DevicePath\r
187 6. Unknown Driver Name\r
188\r
189 @param[in] Handle\r
190\r
191 @post The resulting Unicode name string is stored in the\r
192 mGaugeString global array.\r
193\r
194**/\r
195VOID\r
2c55a81a 196DpGetNameFromHandle (\r
d41bc92c 197 IN EFI_HANDLE Handle\r
198 )\r
199{\r
200 EFI_STATUS Status;\r
201 EFI_LOADED_IMAGE_PROTOCOL *Image;\r
202 CHAR8 *PdbFileName;\r
203 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;\r
204 EFI_STRING StringPtr;\r
205 EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath;\r
206 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
207 EFI_GUID *NameGuid;\r
208 CHAR16 *NameString;\r
209 UINTN StringSize;\r
210 CHAR8 *PlatformLanguage;\r
211 EFI_COMPONENT_NAME2_PROTOCOL *ComponentName2;\r
d41bc92c 212\r
3b672240
SZ
213 Image = NULL;\r
214 LoadedImageDevicePath = NULL;\r
215 DevicePath = NULL;\r
216\r
d41bc92c 217 //\r
218 // Method 1: Get the name string from image PDB\r
219 //\r
220 Status = gBS->HandleProtocol (\r
221 Handle,\r
222 &gEfiLoadedImageProtocolGuid,\r
223 (VOID **) &Image\r
224 );\r
225\r
226 if (EFI_ERROR (Status)) {\r
227 Status = gBS->OpenProtocol (\r
228 Handle,\r
229 &gEfiDriverBindingProtocolGuid,\r
230 (VOID **) &DriverBinding,\r
231 NULL,\r
232 NULL,\r
233 EFI_OPEN_PROTOCOL_GET_PROTOCOL\r
234 );\r
235 if (!EFI_ERROR (Status)) {\r
236 Status = gBS->HandleProtocol (\r
237 DriverBinding->ImageHandle,\r
238 &gEfiLoadedImageProtocolGuid,\r
239 (VOID **) &Image\r
240 );\r
241 }\r
242 }\r
243\r
244 if (!EFI_ERROR (Status)) {\r
245 PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);\r
246\r
247 if (PdbFileName != NULL) {\r
2c55a81a 248 DpGetShortPdbFileName (PdbFileName, mGaugeString);\r
d41bc92c 249 return;\r
250 }\r
251 }\r
252\r
253 //\r
254 // Method 2: Get the name string from ComponentName2 protocol\r
255 //\r
256 Status = gBS->HandleProtocol (\r
257 Handle,\r
258 &gEfiComponentName2ProtocolGuid,\r
259 (VOID **) &ComponentName2\r
260 );\r
261 if (!EFI_ERROR (Status)) {\r
262 //\r
263 // Get the current platform language setting\r
264 //\r
a71003f2 265 PlatformLanguage = GetBestLanguageForDriver(ComponentName2->SupportedLanguages, NULL, FALSE);\r
d41bc92c 266 Status = ComponentName2->GetDriverName (\r
267 ComponentName2,\r
268 PlatformLanguage != NULL ? PlatformLanguage : "en-US",\r
269 &StringPtr\r
270 );\r
271 if (!EFI_ERROR (Status)) {\r
272 SHELL_FREE_NON_NULL (PlatformLanguage);\r
4dc0d578 273 StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);\r
d41bc92c 274 mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;\r
275 return;\r
276 }\r
277 }\r
278\r
279 Status = gBS->HandleProtocol (\r
280 Handle,\r
281 &gEfiLoadedImageDevicePathProtocolGuid,\r
282 (VOID **) &LoadedImageDevicePath\r
283 );\r
284 if (!EFI_ERROR (Status) && (LoadedImageDevicePath != NULL)) {\r
285 DevicePath = LoadedImageDevicePath;\r
3b672240
SZ
286 } else if (Image != NULL) {\r
287 DevicePath = Image->FilePath;\r
288 }\r
d41bc92c 289\r
3b672240 290 if (DevicePath != NULL) {\r
d41bc92c 291 //\r
3b672240 292 // Try to get image GUID from image DevicePath\r
d41bc92c 293 //\r
294 NameGuid = NULL;\r
295 while (!IsDevicePathEndType (DevicePath)) {\r
296 NameGuid = EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) DevicePath);\r
297 if (NameGuid != NULL) {\r
298 break;\r
299 }\r
300 DevicePath = NextDevicePathNode (DevicePath);\r
301 }\r
302\r
303 if (NameGuid != NULL) {\r
304 //\r
305 // Try to get the image's FFS UI section by image GUID\r
306 //\r
307 NameString = NULL;\r
308 StringSize = 0;\r
309 Status = GetSectionFromAnyFv (\r
310 NameGuid,\r
311 EFI_SECTION_USER_INTERFACE,\r
312 0,\r
313 (VOID **) &NameString,\r
314 &StringSize\r
315 );\r
316\r
317 if (!EFI_ERROR (Status)) {\r
318 //\r
319 // Method 3. Get the name string from FFS UI section\r
320 //\r
4dc0d578 321 StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);\r
d41bc92c 322 mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;\r
323 FreePool (NameString);\r
324 } else {\r
325 //\r
326 // Method 4: Get the name string from image GUID\r
327 //\r
328 UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", NameGuid);\r
329 }\r
330 return;\r
331 } else {\r
332 //\r
333 // Method 5: Get the name string from image DevicePath\r
334 //\r
3b672240 335 NameString = ConvertDevicePathToText (DevicePath, TRUE, FALSE);\r
863986b3 336 if (NameString != NULL) {\r
4dc0d578 337 StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, NameString, DP_GAUGE_STRING_LENGTH);\r
863986b3
RN
338 mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;\r
339 FreePool (NameString);\r
340 return;\r
d41bc92c 341 }\r
342 }\r
343 }\r
344\r
345 //\r
346 // Method 6: Unknown Driver Name\r
347 //\r
348 StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_ERROR_NAME), NULL);\r
349 ASSERT (StringPtr != NULL);\r
4dc0d578 350 StrnCpyS (mGaugeString, DP_GAUGE_STRING_LENGTH + 1, StringPtr, DP_GAUGE_STRING_LENGTH);\r
d41bc92c 351 FreePool (StringPtr);\r
352}\r
353\r
354/** \r
355 Calculate the Duration in microseconds.\r
356 \r
357 Duration is multiplied by 1000, instead of Frequency being divided by 1000 or\r
358 multiplying the result by 1000, in order to maintain precision. Since Duration is\r
359 a 64-bit value, multiplying it by 1000 is unlikely to produce an overflow.\r
360 \r
361 The time is calculated as (Duration * 1000) / Timer_Frequency.\r
362 \r
363 @param[in] Duration The event duration in timer ticks.\r
364 \r
365 @return A 64-bit value which is the Elapsed time in microseconds.\r
366**/\r
367UINT64\r
368DurationInMicroSeconds (\r
369 IN UINT64 Duration\r
370 )\r
371{\r
372 UINT64 Temp;\r
373\r
374 Temp = MultU64x32 (Duration, 1000);\r
375 return DivU64x32 (Temp, TimerInfo.Frequency);\r
376}\r
377\r
378/** \r
379 Get index of Measurement Record's match in the CumData array.\r
380 \r
381 If the Measurement's Token value matches a Token in one of the CumData\r
382 records, the index of the matching record is returned. The returned\r
383 index is a signed value so that negative values can indicate that\r
384 the Measurement didn't match any entry in the CumData array.\r
385 \r
386 @param[in] Measurement A pointer to a Measurement Record to match against the CumData array.\r
387 \r
388 @retval <0 Token is not in the CumData array.\r
389 @retval >=0 Return value is the index into CumData where Token is found.\r
390**/\r
391INTN\r
392GetCumulativeItem(\r
393 IN MEASUREMENT_RECORD *Measurement\r
394 )\r
395{\r
396 INTN Index;\r
397\r
398 for( Index = 0; Index < (INTN)NumCum; ++Index) {\r
399 if (AsciiStrnCmp (Measurement->Token, CumData[Index].Name, PERF_TOKEN_LENGTH) == 0) {\r
400 return Index; // Exit, we found a match\r
401 }\r
402 }\r
403 // If the for loop exits, Token was not found.\r
404 return -1; // Indicate failure\r
405}\r