]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Library/DxeCorePerformanceLib/DxeCorePerformanceLib.c
f861d614300148b298c0b5fdff5bf337f2fbab8e
[mirror_edk2.git] / MdeModulePkg / Library / DxeCorePerformanceLib / DxeCorePerformanceLib.c
1 /** @file
2 Performance library instance mainly used by DxeCore.
3
4 This library provides the performance measurement interfaces and initializes performance
5 logging for DXE phase. It first initializes its private global data structure for
6 performance logging and saves the performance GUIDed HOB passed from PEI phase.
7 It initializes DXE phase performance logging by publishing the Performance Protocol,
8 which is consumed by DxePerformanceLib to logging performance data in DXE phase.
9
10 This library is mainly used by DxeCore to start performance logging to ensure that
11 Performance Protocol is installed at the very beginning of DXE phase.
12
13 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
14 All rights reserved. This program and the accompanying materials
15 are licensed and made available under the terms and conditions of the BSD License
16 which accompanies this distribution. The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
18
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21
22 **/
23
24
25 #include "DxeCorePerformanceLibInternal.h"
26
27
28 //
29 // The data structure to hold global performance data.
30 //
31 GAUGE_DATA_HEADER *mGaugeData;
32
33 //
34 // The current maximum number of logging entries. If current number of
35 // entries exceeds this value, it will re-allocate a larger array and
36 // migration the old data to the larger array.
37 //
38 UINT32 mMaxGaugeRecords;
39
40 //
41 // The handle to install Performance Protocol instance.
42 //
43 EFI_HANDLE mHandle = NULL;
44
45 //
46 // Interfaces for performance protocol.
47 //
48 PERFORMANCE_PROTOCOL mPerformanceInterface = {
49 StartGauge,
50 EndGauge,
51 GetGauge
52 };
53
54 /**
55 Searches in the gauge array with keyword Handle, Token and Module.
56
57 This internal function searches for the gauge entry in the gauge array.
58 If there is an entry that exactly matches the given key word triple
59 and its end time stamp is zero, then the index of that gauge entry is returned;
60 otherwise, the the number of gauge entries in the array is returned.
61
62 @param Handle Pointer to environment specific context used
63 to identify the component being measured.
64 @param Token Pointer to a Null-terminated ASCII string
65 that identifies the component being measured.
66 @param Module Pointer to a Null-terminated ASCII string
67 that identifies the module being measured.
68
69 @retval The index of gauge entry in the array.
70
71 **/
72 UINT32
73 InternalSearchForGaugeEntry (
74 IN CONST VOID *Handle, OPTIONAL
75 IN CONST CHAR8 *Token, OPTIONAL
76 IN CONST CHAR8 *Module OPTIONAL
77 )
78 {
79 UINT32 Index;
80 UINT32 NumberOfEntries;
81 GAUGE_DATA_ENTRY *GaugeEntryArray;
82
83 if (Token == NULL) {
84 Token = "";
85 }
86 if (Module == NULL) {
87 Module = "";
88 }
89
90 NumberOfEntries = mGaugeData->NumberOfEntries;
91 GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
92
93 for (Index = 0; Index < NumberOfEntries; Index++) {
94 if ((GaugeEntryArray[Index].Handle == (EFI_PHYSICAL_ADDRESS) (UINTN) Handle) &&
95 AsciiStrnCmp (GaugeEntryArray[Index].Token, Token, PEI_PERFORMANCE_STRING_LENGTH) == 0 &&
96 AsciiStrnCmp (GaugeEntryArray[Index].Module, Module, PEI_PERFORMANCE_STRING_LENGTH) == 0 &&
97 GaugeEntryArray[Index].EndTimeStamp == 0
98 ) {
99 break;
100 }
101 }
102
103 return Index;
104 }
105
106 /**
107 Adds a record at the end of the performance measurement log
108 that records the start time of a performance measurement.
109
110 Adds a record to the end of the performance measurement log
111 that contains the Handle, Token, and Module.
112 The end time of the new record must be set to zero.
113 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
114 If TimeStamp is zero, the start time in the record is filled in with the value
115 read from the current time stamp.
116
117 @param Handle Pointer to environment specific context used
118 to identify the component being measured.
119 @param Token Pointer to a Null-terminated ASCII string
120 that identifies the component being measured.
121 @param Module Pointer to a Null-terminated ASCII string
122 that identifies the module being measured.
123 @param TimeStamp 64-bit time stamp.
124
125 @retval EFI_SUCCESS The data was read correctly from the device.
126 @retval EFI_OUT_OF_RESOURCES There are not enough resources to record the measurement.
127
128 **/
129 EFI_STATUS
130 EFIAPI
131 StartGauge (
132 IN CONST VOID *Handle, OPTIONAL
133 IN CONST CHAR8 *Token, OPTIONAL
134 IN CONST CHAR8 *Module, OPTIONAL
135 IN UINT64 TimeStamp
136 )
137 {
138 GAUGE_DATA_ENTRY *GaugeEntryArray;
139 UINTN GaugeDataSize;
140 UINTN OldGaugeDataSize;
141 GAUGE_DATA_HEADER *OldGaugeData;
142 UINT32 Index;
143
144 Index = mGaugeData->NumberOfEntries;
145 if (Index >= mMaxGaugeRecords) {
146 //
147 // Try to enlarge the scale of gauge array.
148 //
149 OldGaugeData = mGaugeData;
150 OldGaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords;
151
152 mMaxGaugeRecords *= 2;
153 GaugeDataSize = sizeof (GAUGE_DATA_HEADER) + sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords;
154
155 mGaugeData = AllocateZeroPool (GaugeDataSize);
156 if (mGaugeData == NULL) {
157 return EFI_OUT_OF_RESOURCES;
158 }
159 //
160 // Initialize new data array and migrate old data one.
161 //
162 mGaugeData = CopyMem (mGaugeData, OldGaugeData, OldGaugeDataSize);
163
164 FreePool (OldGaugeData);
165 }
166
167 GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
168 GaugeEntryArray[Index].Handle = (EFI_PHYSICAL_ADDRESS) (UINTN) Handle;
169
170 if (Token != NULL) {
171 AsciiStrnCpy (GaugeEntryArray[Index].Token, Token, DXE_PERFORMANCE_STRING_LENGTH);
172 }
173 if (Module != NULL) {
174 AsciiStrnCpy (GaugeEntryArray[Index].Module, Module, DXE_PERFORMANCE_STRING_LENGTH);
175 }
176
177 if (TimeStamp == 0) {
178 TimeStamp = GetPerformanceCounter ();
179 }
180 GaugeEntryArray[Index].StartTimeStamp = TimeStamp;
181
182 mGaugeData->NumberOfEntries++;
183
184 return EFI_SUCCESS;
185 }
186
187 /**
188 Searches the performance measurement log from the beginning of the log
189 for the first matching record that contains a zero end time and fills in a valid end time.
190
191 Searches the performance measurement log from the beginning of the log
192 for the first record that matches Handle, Token, and Module and has an end time value of zero.
193 If the record can not be found then return EFI_NOT_FOUND.
194 If the record is found and TimeStamp is not zero,
195 then the end time in the record is filled in with the value specified by TimeStamp.
196 If the record is found and TimeStamp is zero, then the end time in the matching record
197 is filled in with the current time stamp value.
198
199 @param Handle Pointer to environment specific context used
200 to identify the component being measured.
201 @param Token Pointer to a Null-terminated ASCII string
202 that identifies the component being measured.
203 @param Module Pointer to a Null-terminated ASCII string
204 that identifies the module being measured.
205 @param TimeStamp 64-bit time stamp.
206
207 @retval EFI_SUCCESS The end of the measurement was recorded.
208 @retval EFI_NOT_FOUND The specified measurement record could not be found.
209
210 **/
211 EFI_STATUS
212 EFIAPI
213 EndGauge (
214 IN CONST VOID *Handle, OPTIONAL
215 IN CONST CHAR8 *Token, OPTIONAL
216 IN CONST CHAR8 *Module, OPTIONAL
217 IN UINT64 TimeStamp
218 )
219 {
220 GAUGE_DATA_ENTRY *GaugeEntryArray;
221 UINT32 Index;
222
223 if (TimeStamp == 0) {
224 TimeStamp = GetPerformanceCounter ();
225 }
226
227 Index = InternalSearchForGaugeEntry (Handle, Token, Module);
228 if (Index >= mGaugeData->NumberOfEntries) {
229 return EFI_NOT_FOUND;
230 }
231 GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
232 GaugeEntryArray[Index].EndTimeStamp = TimeStamp;
233
234 return EFI_SUCCESS;
235 }
236
237 /**
238 Retrieves a previously logged performance measurement.
239
240 Retrieves the performance log entry from the performance log specified by LogEntryKey.
241 If it stands for a valid entry, then EFI_SUCCESS is returned and
242 GaugeDataEntry stores the pointer to that entry.
243
244 @param LogEntryKey The key for the previous performance measurement log entry.
245 If 0, then the first performance measurement log entry is retrieved.
246 @param GaugeDataEntry The indirect pointer to the gauge data entry specified by LogEntryKey
247 if the retrieval is successful.
248
249 @retval EFI_SUCCESS The GuageDataEntry is successfully found based on LogEntryKey.
250 @retval EFI_NOT_FOUND The LogEntryKey is the last entry (equals to the total entry number).
251 @retval EFI_INVALIDE_PARAMETER The LogEntryKey is not a valid entry (greater than the total entry number).
252 @retval EFI_INVALIDE_PARAMETER GaugeDataEntry is NULL.
253
254 **/
255 EFI_STATUS
256 EFIAPI
257 GetGauge (
258 IN UINTN LogEntryKey,
259 OUT GAUGE_DATA_ENTRY **GaugeDataEntry
260 )
261 {
262 UINTN NumberOfEntries;
263 GAUGE_DATA_ENTRY *LogEntryArray;
264
265 NumberOfEntries = (UINTN) (mGaugeData->NumberOfEntries);
266 if (LogEntryKey > NumberOfEntries) {
267 return EFI_INVALID_PARAMETER;
268 }
269 if (LogEntryKey == NumberOfEntries) {
270 return EFI_NOT_FOUND;
271 }
272
273 LogEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
274
275 if (GaugeDataEntry == NULL) {
276 return EFI_INVALID_PARAMETER;
277 }
278 *GaugeDataEntry = &LogEntryArray[LogEntryKey];
279
280 return EFI_SUCCESS;
281 }
282
283 /**
284 Dumps all the PEI performance log to DXE performance gauge array.
285
286 This internal function dumps all the PEI performance log to the DXE performance gauge array.
287 It retrieves the optional GUID HOB for PEI performance and then saves the performance data
288 to DXE performance data structures.
289
290 **/
291 VOID
292 InternalGetPeiPerformance (
293 VOID
294 )
295 {
296 EFI_HOB_GUID_TYPE *GuidHob;
297 PEI_PERFORMANCE_LOG_HEADER *LogHob;
298 PEI_PERFORMANCE_LOG_ENTRY *LogEntryArray;
299 GAUGE_DATA_ENTRY *GaugeEntryArray;
300 UINT32 Index;
301 UINT32 NumberOfEntries;
302
303 NumberOfEntries = 0;
304 GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
305
306 //
307 // Dump PEI Log Entries to DXE Guage Data structure.
308 //
309 GuidHob = GetFirstGuidHob (&gPeiPerformanceHobGuid);
310 if (GuidHob != NULL) {
311 LogHob = GET_GUID_HOB_DATA (GuidHob);
312 LogEntryArray = (PEI_PERFORMANCE_LOG_ENTRY *) (LogHob + 1);
313 GaugeEntryArray = (GAUGE_DATA_ENTRY *) (mGaugeData + 1);
314
315 NumberOfEntries = LogHob->NumberOfEntries;
316 for (Index = 0; Index < NumberOfEntries; Index++) {
317 GaugeEntryArray[Index].Handle = LogEntryArray[Index].Handle;
318 AsciiStrnCpy (GaugeEntryArray[Index].Token, LogEntryArray[Index].Token, DXE_PERFORMANCE_STRING_LENGTH);
319 AsciiStrnCpy (GaugeEntryArray[Index].Module, LogEntryArray[Index].Module, DXE_PERFORMANCE_STRING_LENGTH);
320 GaugeEntryArray[Index].StartTimeStamp = LogEntryArray[Index].StartTimeStamp;
321 GaugeEntryArray[Index].EndTimeStamp = LogEntryArray[Index].EndTimeStamp;
322 }
323 }
324 mGaugeData->NumberOfEntries = NumberOfEntries;
325 }
326
327 /**
328 The constructor function initializes Performance infrastructure for DXE phase.
329
330 The constructor function publishes Performance protocol, allocates memory to log DXE performance
331 and merges PEI performance data to DXE performance log.
332 It will ASSERT() if one of these operations fails and it will always return EFI_SUCCESS.
333
334 @param ImageHandle The firmware allocated handle for the EFI image.
335 @param SystemTable A pointer to the EFI System Table.
336
337 @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
338
339 **/
340 EFI_STATUS
341 EFIAPI
342 DxeCorePerformanceLibConstructor (
343 IN EFI_HANDLE ImageHandle,
344 IN EFI_SYSTEM_TABLE *SystemTable
345 )
346 {
347 EFI_STATUS Status;
348
349 if (!PerformanceMeasurementEnabled ()) {
350 //
351 // Do not initialize performance infrastructure if not required.
352 //
353 return EFI_SUCCESS;
354 }
355 //
356 // Install the protocol interfaces.
357 //
358 Status = gBS->InstallProtocolInterface (
359 &mHandle,
360 &gPerformanceProtocolGuid,
361 EFI_NATIVE_INTERFACE,
362 &mPerformanceInterface
363 );
364 ASSERT_EFI_ERROR (Status);
365
366 mMaxGaugeRecords = INIT_DXE_GAUGE_DATA_ENTRIES + PcdGet8 (PcdMaxPeiPerformanceLogEntries);
367
368 mGaugeData = AllocateZeroPool (sizeof (GAUGE_DATA_HEADER) + (sizeof (GAUGE_DATA_ENTRY) * mMaxGaugeRecords));
369 ASSERT (mGaugeData != NULL);
370
371 InternalGetPeiPerformance ();
372
373 return Status;
374 }
375
376 /**
377 Adds a record at the end of the performance measurement log
378 that records the start time of a performance measurement.
379
380 Adds a record to the end of the performance measurement log
381 that contains the Handle, Token, and Module.
382 The end time of the new record must be set to zero.
383 If TimeStamp is not zero, then TimeStamp is used to fill in the start time in the record.
384 If TimeStamp is zero, the start time in the record is filled in with the value
385 read from the current time stamp.
386
387 @param Handle Pointer to environment specific context used
388 to identify the component being measured.
389 @param Token Pointer to a Null-terminated ASCII string
390 that identifies the component being measured.
391 @param Module Pointer to a Null-terminated ASCII string
392 that identifies the module being measured.
393 @param TimeStamp 64-bit time stamp.
394
395 @retval RETURN_SUCCESS The start of the measurement was recorded.
396 @retval RETURN_OUT_OF_RESOURCES There are not enough resources to record the measurement.
397
398 **/
399 RETURN_STATUS
400 EFIAPI
401 StartPerformanceMeasurement (
402 IN CONST VOID *Handle, OPTIONAL
403 IN CONST CHAR8 *Token, OPTIONAL
404 IN CONST CHAR8 *Module, OPTIONAL
405 IN UINT64 TimeStamp
406 )
407 {
408 EFI_STATUS Status;
409
410 Status = StartGauge (Handle, Token, Module, TimeStamp);
411 return (RETURN_STATUS) Status;
412 }
413
414 /**
415 Searches the performance measurement log from the beginning of the log
416 for the first matching record that contains a zero end time and fills in a valid end time.
417
418 Searches the performance measurement log from the beginning of the log
419 for the first record that matches Handle, Token, and Module and has an end time value of zero.
420 If the record can not be found then return RETURN_NOT_FOUND.
421 If the record is found and TimeStamp is not zero,
422 then the end time in the record is filled in with the value specified by TimeStamp.
423 If the record is found and TimeStamp is zero, then the end time in the matching record
424 is filled in with the current time stamp value.
425
426 @param Handle Pointer to environment specific context used
427 to identify the component being measured.
428 @param Token Pointer to a Null-terminated ASCII string
429 that identifies the component being measured.
430 @param Module Pointer to a Null-terminated ASCII string
431 that identifies the module being measured.
432 @param TimeStamp 64-bit time stamp.
433
434 @retval RETURN_SUCCESS The end of the measurement was recorded.
435 @retval RETURN_NOT_FOUND The specified measurement record could not be found.
436
437 **/
438 RETURN_STATUS
439 EFIAPI
440 EndPerformanceMeasurement (
441 IN CONST VOID *Handle, OPTIONAL
442 IN CONST CHAR8 *Token, OPTIONAL
443 IN CONST CHAR8 *Module, OPTIONAL
444 IN UINT64 TimeStamp
445 )
446 {
447 EFI_STATUS Status;
448
449 Status = EndGauge (Handle, Token, Module, TimeStamp);
450 return (RETURN_STATUS) Status;
451 }
452
453 /**
454 Attempts to retrieve a performance measurement log entry from the performance measurement log.
455
456 Attempts to retrieve the performance log entry specified by LogEntryKey. If LogEntryKey is
457 zero on entry, then an attempt is made to retrieve the first entry from the performance log,
458 and the key for the second entry in the log is returned. If the performance log is empty,
459 then no entry is retrieved and zero is returned. If LogEntryKey is not zero, then the performance
460 log entry associated with LogEntryKey is retrieved, and the key for the next entry in the log is
461 returned. If LogEntryKey is the key for the last entry in the log, then the last log entry is
462 retrieved and an implementation specific non-zero key value that specifies the end of the performance
463 log is returned. If LogEntryKey is equal this implementation specific non-zero key value, then no entry
464 is retrieved and zero is returned. In the cases where a performance log entry can be returned,
465 the log entry is returned in Handle, Token, Module, StartTimeStamp, and EndTimeStamp.
466 If LogEntryKey is not a valid log entry key for the performance measurement log, then ASSERT().
467 If Handle is NULL, then ASSERT().
468 If Token is NULL, then ASSERT().
469 If Module is NULL, then ASSERT().
470 If StartTimeStamp is NULL, then ASSERT().
471 If EndTimeStamp is NULL, then ASSERT().
472
473 @param LogEntryKey On entry, the key of the performance measurement log entry to retrieve.
474 0, then the first performance measurement log entry is retrieved.
475 On exit, the key of the next performance log entry.
476 @param Handle Pointer to environment specific context used to identify the component
477 being measured.
478 @param Token Pointer to a Null-terminated ASCII string that identifies the component
479 being measured.
480 @param Module Pointer to a Null-terminated ASCII string that identifies the module
481 being measured.
482 @param StartTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
483 was started.
484 @param EndTimeStamp Pointer to the 64-bit time stamp that was recorded when the measurement
485 was ended.
486
487 @return The key for the next performance log entry (in general case).
488
489 **/
490 UINTN
491 EFIAPI
492 GetPerformanceMeasurement (
493 IN UINTN LogEntryKey,
494 OUT CONST VOID **Handle,
495 OUT CONST CHAR8 **Token,
496 OUT CONST CHAR8 **Module,
497 OUT UINT64 *StartTimeStamp,
498 OUT UINT64 *EndTimeStamp
499 )
500 {
501 EFI_STATUS Status;
502 GAUGE_DATA_ENTRY *GaugeData;
503
504 GaugeData = NULL;
505
506 ASSERT (Handle != NULL);
507 ASSERT (Token != NULL);
508 ASSERT (Module != NULL);
509 ASSERT (StartTimeStamp != NULL);
510 ASSERT (EndTimeStamp != NULL);
511
512 Status = GetGauge (LogEntryKey++, &GaugeData);
513
514 //
515 // Make sure that LogEntryKey is a valid log entry key,
516 //
517 ASSERT (Status != EFI_INVALID_PARAMETER);
518
519 if (EFI_ERROR (Status)) {
520 //
521 // The LogEntryKey is the last entry (equals to the total entry number).
522 //
523 return 0;
524 }
525
526 ASSERT (GaugeData != NULL);
527
528 *Handle = (VOID *) (UINTN) GaugeData->Handle;
529 *Token = GaugeData->Token;
530 *Module = GaugeData->Module;
531 *StartTimeStamp = GaugeData->StartTimeStamp;
532 *EndTimeStamp = GaugeData->EndTimeStamp;
533
534 return LogEntryKey;
535 }
536
537 /**
538 Returns TRUE if the performance measurement macros are enabled.
539
540 This function returns TRUE if the PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
541 PcdPerformanceLibraryPropertyMask is set. Otherwise FALSE is returned.
542
543 @retval TRUE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
544 PcdPerformanceLibraryPropertyMask is set.
545 @retval FALSE The PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED bit of
546 PcdPerformanceLibraryPropertyMask is clear.
547
548 **/
549 BOOLEAN
550 EFIAPI
551 PerformanceMeasurementEnabled (
552 VOID
553 )
554 {
555 return (BOOLEAN) ((PcdGet8(PcdPerformanceLibraryPropertyMask) & PERFORMANCE_LIBRARY_PROPERTY_MEASUREMENT_ENABLED) != 0);
556 }