1 /** @file
2   Trace reporting for the Dp utility.
3 
4   Copyright (c) 2009 - 2013, Intel Corporation. All rights reserved.
5   (C) Copyright 2015 Hewlett Packard Enterprise Development LP<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 **/
14 
15 #include <Library/BaseLib.h>
16 #include <Library/BaseMemoryLib.h>
17 #include <Library/MemoryAllocationLib.h>
18 #include <Library/DebugLib.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/TimerLib.h>
21 #include <Library/PeCoffGetEntryPointLib.h>
22 #include <Library/PerformanceLib.h>
23 #include <Library/PrintLib.h>
24 #include <Library/HiiLib.h>
25 #include <Library/PcdLib.h>
26 
27 #include <Guid/Performance.h>
28 
29 #include "Dp.h"
30 #include "Literals.h"
31 #include "DpInternal.h"
32 
33 /**
34   Collect verbose statistics about the logged performance measurements.
35 
36   General Summary information for all Trace measurements is gathered and
37   stored within the SummaryData structure.  This information is both
38   used internally by subsequent reporting functions, and displayed
39   at the end of verbose reports.
40 
41   @pre  The SummaryData and CumData structures must be initialized
42         prior to calling this function.
43 
44   @post The SummaryData and CumData structures contain statistics for the
45         current performance logs.
46 
47   @param[in, out] CustomCumulativeData  A pointer to the cumtom cumulative data.
48 
49 **/
50 VOID
GatherStatistics(IN OUT PERF_CUM_DATA * CustomCumulativeData OPTIONAL)51 GatherStatistics(
52   IN OUT PERF_CUM_DATA              *CustomCumulativeData OPTIONAL
53   )
54 {
55   MEASUREMENT_RECORD        Measurement;
56   UINT64                    Duration;
57   UINTN                     LogEntryKey;
58   INTN                      TIndex;
59 
60   LogEntryKey = 0;
61   while ((LogEntryKey = GetPerformanceMeasurementEx (
62                         LogEntryKey,
63                         &Measurement.Handle,
64                         &Measurement.Token,
65                         &Measurement.Module,
66                         &Measurement.StartTimeStamp,
67                         &Measurement.EndTimeStamp,
68                         &Measurement.Identifier)) != 0)
69   {
70     ++SummaryData.NumTrace;           // Count the number of TRACE Measurement records
71     if (Measurement.EndTimeStamp == 0) {
72       ++SummaryData.NumIncomplete;    // Count the incomplete records
73       continue;
74     }
75 
76     if (Measurement.Handle != NULL) {
77       ++SummaryData.NumHandles;       // Count the number of measurements with non-NULL handles
78     }
79 
80     if (IsPhase( &Measurement)) {
81       ++SummaryData.NumSummary;       // Count the number of major phases
82     }
83     else {  // !IsPhase(...
84       if(Measurement.Handle == NULL) {
85         ++SummaryData.NumGlobal;
86       }
87     }
88 
89     if (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) == 0) {
90       ++SummaryData.NumPEIMs;         // Count PEIM measurements
91     }
92 
93     Duration = GetDuration (&Measurement);
94     TIndex = GetCumulativeItem (&Measurement);
95     if (TIndex >= 0) {
96       CumData[TIndex].Duration += Duration;
97       CumData[TIndex].Count++;
98       if ( Duration < CumData[TIndex].MinDur ) {
99         CumData[TIndex].MinDur = Duration;
100       }
101       if ( Duration > CumData[TIndex].MaxDur ) {
102         CumData[TIndex].MaxDur = Duration;
103       }
104     }
105 
106     //
107     // Collect the data for custom cumulative data.
108     //
109     if ((CustomCumulativeData != NULL) && (AsciiStrCmp (Measurement.Token, CustomCumulativeData->Name) == 0)) {
110       CustomCumulativeData->Duration += Duration;
111       CustomCumulativeData->Count++;
112       if (Duration < CustomCumulativeData->MinDur) {
113         CustomCumulativeData->MinDur = Duration;
114       }
115       if (Duration > CustomCumulativeData->MaxDur) {
116         CustomCumulativeData->MaxDur = Duration;
117       }
118     }
119   }
120 }
121 
122 /**
123   Gather and print ALL Trace Records.
124 
125   Displays all "interesting" Trace measurements in order.<BR>
126   The number of records displayed is controlled by:
127      - records with a duration less than mInterestThreshold microseconds are not displayed.
128      - No more than Limit records are displayed.  A Limit of zero will not limit the output.
129      - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
130        displayed.
131 
132   @pre    The mInterestThreshold global variable is set to the shortest duration to be printed.
133            The mGaugeString and mUnicodeToken global arrays are used for temporary string storage.
134            They must not be in use by a calling function.
135 
136   @param[in]    Limit       The number of records to print.  Zero is ALL.
137   @param[in]    ExcludeFlag TRUE to exclude individual Cumulative items from display.
138 
139 **/
140 VOID
DumpAllTrace(IN UINTN Limit,IN BOOLEAN ExcludeFlag)141 DumpAllTrace(
142   IN UINTN             Limit,
143   IN BOOLEAN           ExcludeFlag
144   )
145 {
146   MEASUREMENT_RECORD        Measurement;
147   UINT64                    ElapsedTime;
148   UINT64                    Duration;
149   CHAR16                    *IncFlag;
150   UINTN                     LogEntryKey;
151   UINTN                     Count;
152   UINTN                     Index;
153   UINTN                     TIndex;
154 
155   EFI_HANDLE                *HandleBuffer;
156   UINTN                     Size;
157   EFI_HANDLE                TempHandle;
158   EFI_STATUS                Status;
159   EFI_STRING                StringPtrUnknown;
160 
161   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
162   IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_ALL), NULL);
163   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
164               (IncFlag == NULL) ? StringPtrUnknown : IncFlag);
165   FreePool (StringPtrUnknown);
166 
167   // Get Handle information
168   //
169   Size = 0;
170   HandleBuffer = &TempHandle;
171   Status  = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, &TempHandle);
172   if (Status == EFI_BUFFER_TOO_SMALL) {
173     HandleBuffer = AllocatePool (Size);
174     ASSERT (HandleBuffer != NULL);
175     if (HandleBuffer == NULL) {
176       return;
177     }
178     Status  = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleBuffer);
179   }
180   if (EFI_ERROR (Status)) {
181     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), gDpHiiHandle, Status);
182   }
183   else {
184     // We have successfully populated the HandleBuffer
185     // Display ALL Measurement Records
186     //    Up to Limit lines displayed
187     //    Display only records with Elapsed times >= mInterestThreshold
188     //    Display driver names in Module field for records with Handles.
189     //
190     if (mShowId) {
191       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR2), gDpHiiHandle);
192       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_DASHES2), gDpHiiHandle);
193     } else {
194       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR), gDpHiiHandle);
195       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
196     }
197 
198     LogEntryKey = 0;
199     Count = 0;
200     Index = 0;
201     while ( WITHIN_LIMIT(Count, Limit) &&
202             ((LogEntryKey = GetPerformanceMeasurementEx (
203                             LogEntryKey,
204                             &Measurement.Handle,
205                             &Measurement.Token,
206                             &Measurement.Module,
207                             &Measurement.StartTimeStamp,
208                             &Measurement.EndTimeStamp,
209                             &Measurement.Identifier)) != 0)
210           )
211     {
212       ++Index;    // Count every record.  First record is 1.
213       ElapsedTime = 0;
214       SHELL_FREE_NON_NULL (IncFlag);
215       if (Measurement.EndTimeStamp != 0) {
216         Duration = GetDuration (&Measurement);
217         ElapsedTime = DurationInMicroSeconds ( Duration );
218         IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_COMPLETE), NULL);
219       }
220       else {
221         IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_INCOMPLETE), NULL);  // Mark incomplete records
222       }
223       if (((Measurement.EndTimeStamp != 0) && (ElapsedTime < mInterestThreshold)) ||
224           ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
225          ) {      // Ignore "uninteresting" or excluded records
226         continue;
227       }
228       ++Count;    // Count the number of records printed
229 
230       // If Handle is non-zero, see if we can determine a name for the driver
231       AsciiStrToUnicodeStr (Measurement.Module, mGaugeString); // Use Module by default
232       AsciiStrToUnicodeStr (Measurement.Token, mUnicodeToken);
233       if (Measurement.Handle != NULL) {
234         // See if the Handle is in the HandleBuffer
235         for (TIndex = 0; TIndex < (Size / sizeof(HandleBuffer[0])); TIndex++) {
236           if (Measurement.Handle == HandleBuffer[TIndex]) {
237             DpGetNameFromHandle (HandleBuffer[TIndex]);
238             break;
239           }
240         }
241       }
242 
243       if (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) == 0) {
244         UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", Measurement.Handle);
245       }
246 
247       // Ensure that the argument strings are not too long.
248       mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
249       mUnicodeToken[13] = 0;
250 
251       if (mShowId) {
252         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS2), gDpHiiHandle,
253           Index,      // 1 based, Which measurement record is being printed
254           IncFlag,
255           Measurement.Handle,
256           mGaugeString,
257           mUnicodeToken,
258           ElapsedTime,
259           Measurement.Identifier
260         );
261       } else {
262         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS), gDpHiiHandle,
263           Index,      // 1 based, Which measurement record is being printed
264           IncFlag,
265           Measurement.Handle,
266           mGaugeString,
267           mUnicodeToken,
268           ElapsedTime
269         );
270       }
271     }
272   }
273   if (HandleBuffer != &TempHandle) {
274     FreePool (HandleBuffer);
275   }
276   SHELL_FREE_NON_NULL (IncFlag);
277 }
278 
279 /**
280   Gather and print Raw Trace Records.
281 
282   All Trace measurements with a duration greater than or equal to
283   mInterestThreshold are printed without interpretation.
284 
285   The number of records displayed is controlled by:
286      - records with a duration less than mInterestThreshold microseconds are not displayed.
287      - No more than Limit records are displayed.  A Limit of zero will not limit the output.
288      - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
289        displayed.
290 
291   @pre    The mInterestThreshold global variable is set to the shortest duration to be printed.
292 
293   @param[in]    Limit       The number of records to print.  Zero is ALL.
294   @param[in]    ExcludeFlag TRUE to exclude individual Cumulative items from display.
295 
296 **/
297 VOID
DumpRawTrace(IN UINTN Limit,IN BOOLEAN ExcludeFlag)298 DumpRawTrace(
299   IN UINTN          Limit,
300   IN BOOLEAN        ExcludeFlag
301   )
302 {
303   MEASUREMENT_RECORD        Measurement;
304   UINT64                    ElapsedTime;
305   UINT64                    Duration;
306   UINTN                     LogEntryKey;
307   UINTN                     Count;
308   UINTN                     Index;
309 
310   EFI_STRING    StringPtr;
311   EFI_STRING    StringPtrUnknown;
312 
313   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
314   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_RAWTRACE), NULL);
315   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
316               (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
317   FreePool (StringPtr);
318   FreePool (StringPtrUnknown);
319 
320   if (mShowId) {
321     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR2), gDpHiiHandle);
322     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES2), gDpHiiHandle);
323   } else {
324     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR), gDpHiiHandle);
325     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES), gDpHiiHandle);
326   }
327 
328   LogEntryKey = 0;
329   Count = 0;
330   Index = 0;
331   while ( WITHIN_LIMIT(Count, Limit) &&
332           ((LogEntryKey = GetPerformanceMeasurementEx (
333                           LogEntryKey,
334                           &Measurement.Handle,
335                           &Measurement.Token,
336                           &Measurement.Module,
337                           &Measurement.StartTimeStamp,
338                           &Measurement.EndTimeStamp,
339                           &Measurement.Identifier)) != 0)
340         )
341   {
342     ++Index;    // Count every record.  First record is 1.
343     ElapsedTime = 0;
344     if (Measurement.EndTimeStamp != 0) {
345       Duration = GetDuration (&Measurement);
346       ElapsedTime = DurationInMicroSeconds ( Duration );
347     }
348     if ((ElapsedTime < mInterestThreshold)                 ||
349         ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
350         ) { // Ignore "uninteresting" or Excluded records
351       continue;
352     }
353     ++Count;    // Count the number of records printed
354 
355     if (mShowId) {
356       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS2), gDpHiiHandle,
357         Index,      // 1 based, Which measurement record is being printed
358         Measurement.Handle,
359         Measurement.StartTimeStamp,
360         Measurement.EndTimeStamp,
361         Measurement.Token,
362         Measurement.Module,
363         Measurement.Identifier
364       );
365     } else {
366       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS), gDpHiiHandle,
367         Index,      // 1 based, Which measurement record is being printed
368         Measurement.Handle,
369         Measurement.StartTimeStamp,
370         Measurement.EndTimeStamp,
371         Measurement.Token,
372         Measurement.Module
373       );
374     }
375   }
376 }
377 
378 /**
379   Gather and print Major Phase metrics.
380 
381   @param[in]    Ticker      The timer value for the END of Shell phase
382 
383 **/
384 VOID
ProcessPhases(IN UINT64 Ticker)385 ProcessPhases(
386   IN UINT64            Ticker
387   )
388 {
389   MEASUREMENT_RECORD        Measurement;
390   UINT64                    BdsTimeoutValue;
391   UINT64                    SecTime;
392   UINT64                    PeiTime;
393   UINT64                    DxeTime;
394   UINT64                    BdsTime;
395   UINT64                    ShellTime;
396   UINT64                    ElapsedTime;
397   UINT64                    Duration;
398   UINT64                    Total;
399   EFI_STRING                StringPtr;
400   UINTN                     LogEntryKey;
401   EFI_STRING                StringPtrUnknown;
402 
403   BdsTimeoutValue = 0;
404   SecTime         = 0;
405   PeiTime         = 0;
406   DxeTime         = 0;
407   BdsTime         = 0;
408   ShellTime       = 0;
409   //
410   // Get Execution Phase Statistics
411   //
412   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
413   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PHASES), NULL);
414   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
415               (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
416   FreePool (StringPtr);
417   FreePool (StringPtrUnknown);
418 
419   LogEntryKey = 0;
420   while ((LogEntryKey = GetPerformanceMeasurementEx (
421                           LogEntryKey,
422                           &Measurement.Handle,
423                           &Measurement.Token,
424                           &Measurement.Module,
425                           &Measurement.StartTimeStamp,
426                           &Measurement.EndTimeStamp,
427                           &Measurement.Identifier)) != 0)
428   {
429     if (AsciiStrnCmp (Measurement.Token, ALit_SHELL, PERF_TOKEN_LENGTH) == 0) {
430       Measurement.EndTimeStamp = Ticker;
431     }
432     if (Measurement.EndTimeStamp == 0) { // Skip "incomplete" records
433       continue;
434     }
435     Duration = GetDuration (&Measurement);
436     if (   Measurement.Handle != NULL
437         && (AsciiStrnCmp (Measurement.Token, ALit_BdsTO, PERF_TOKEN_LENGTH) == 0)
438        )
439     {
440       BdsTimeoutValue = Duration;
441     } else if (AsciiStrnCmp (Measurement.Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0) {
442       SecTime     = Duration;
443     } else if (AsciiStrnCmp (Measurement.Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0) {
444       PeiTime     = Duration;
445     } else if (AsciiStrnCmp (Measurement.Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0) {
446       DxeTime      = Duration;
447     } else if (AsciiStrnCmp (Measurement.Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0) {
448       BdsTime      = Duration;
449     } else if (AsciiStrnCmp (Measurement.Token, ALit_SHELL, PERF_TOKEN_LENGTH) == 0) {
450       ShellTime    = Duration;
451     }
452   }
453 
454   Total = 0;
455 
456   // print SEC phase duration time
457   //
458   if (SecTime > 0) {
459     ElapsedTime = DurationInMicroSeconds ( SecTime );     // Calculate elapsed time in microseconds
460     Total += DivU64x32 (ElapsedTime, 1000);   // Accumulate time in milliseconds
461     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SEC_PHASE), gDpHiiHandle, ElapsedTime);
462   }
463 
464   // print PEI phase duration time
465   //
466   if (PeiTime > 0) {
467     ElapsedTime = DivU64x32 (
468                     PeiTime,
469                     (UINT32)TimerInfo.Frequency
470                     );
471     Total += ElapsedTime;
472     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_PEI, ElapsedTime);
473   }
474 
475   // print DXE phase duration time
476   //
477   if (DxeTime > 0) {
478     ElapsedTime = DivU64x32 (
479                     DxeTime,
480                     (UINT32)TimerInfo.Frequency
481                     );
482     Total += ElapsedTime;
483     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_DXE, ElapsedTime);
484   }
485 
486   // print BDS phase duration time
487   //
488   if (BdsTime > 0) {
489     ElapsedTime = DivU64x32 (
490                     BdsTime,
491                     (UINT32)TimerInfo.Frequency
492                     );
493     Total += ElapsedTime;
494     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_BDS, ElapsedTime);
495   }
496 
497   if (BdsTimeoutValue > 0) {
498     ElapsedTime = DivU64x32 (
499                     BdsTimeoutValue,
500                     (UINT32)TimerInfo.Frequency
501                     );
502     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_BDSTO), gDpHiiHandle, ALit_BdsTO, ElapsedTime);
503   }
504 
505   // print SHELL phase duration time
506   //
507   if (ShellTime > 0) {
508     ElapsedTime = DivU64x32 (
509                     ShellTime,
510                     (UINT32)TimerInfo.Frequency
511                     );
512     Total += ElapsedTime;
513     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_SHELL, ElapsedTime);
514   }
515 
516   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOTAL_DURATION), gDpHiiHandle, Total);
517 }
518 
519 /**
520   Gather and print Handle data.
521 
522   @param[in]    ExcludeFlag   TRUE to exclude individual Cumulative items from display.
523 
524   @return       Status from a call to gBS->LocateHandle().
525 **/
526 EFI_STATUS
ProcessHandles(IN BOOLEAN ExcludeFlag)527 ProcessHandles(
528   IN BOOLEAN      ExcludeFlag
529   )
530 {
531   MEASUREMENT_RECORD        Measurement;
532   UINT64                    ElapsedTime;
533   UINT64                    Duration;
534   EFI_HANDLE                *HandleBuffer;
535   EFI_STRING                StringPtr;
536   UINTN                     Index;
537   UINTN                     LogEntryKey;
538   UINTN                     Count;
539   UINTN                     Size;
540   EFI_HANDLE                TempHandle;
541   EFI_STATUS                Status;
542   EFI_STRING                StringPtrUnknown;
543 
544   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
545   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_DRIVERS), NULL);
546   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
547               (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
548   FreePool (StringPtr);
549   FreePool (StringPtrUnknown);
550 
551   Size = 0;
552   HandleBuffer = &TempHandle;
553   Status  = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, &TempHandle);
554   if (Status == EFI_BUFFER_TOO_SMALL) {
555     HandleBuffer = AllocatePool (Size);
556     ASSERT (HandleBuffer != NULL);
557     if (HandleBuffer == NULL) {
558       return Status;
559     }
560     Status  = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleBuffer);
561   }
562   if (EFI_ERROR (Status)) {
563     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), gDpHiiHandle, Status);
564   }
565   else {
566 #if DP_DEBUG == 2
567     Print (L"There are %,d Handles defined.\n", (Size / sizeof(HandleBuffer[0])));
568 #endif
569 
570     if (mShowId) {
571       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION2), gDpHiiHandle);
572     } else {
573       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION), gDpHiiHandle);
574     }
575     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
576 
577     LogEntryKey = 0;
578     Count   = 0;
579     while ((LogEntryKey = GetPerformanceMeasurementEx (
580                             LogEntryKey,
581                             &Measurement.Handle,
582                             &Measurement.Token,
583                             &Measurement.Module,
584                             &Measurement.StartTimeStamp,
585                             &Measurement.EndTimeStamp,
586                             &Measurement.Identifier)) != 0)
587     {
588       Count++;
589       Duration = GetDuration (&Measurement);
590       ElapsedTime = DurationInMicroSeconds ( Duration );
591       if ((ElapsedTime < mInterestThreshold)                 ||
592           (Measurement.EndTimeStamp == 0)                    ||
593           (Measurement.Handle == NULL)                       ||
594           ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
595          ) { // Ignore "uninteresting" or excluded records
596         continue;
597       }
598       mGaugeString[0] = 0;    // Empty driver name by default
599       AsciiStrToUnicodeStr (Measurement.Token, mUnicodeToken);
600       // See if the Handle is in the HandleBuffer
601       for (Index = 0; Index < (Size / sizeof(HandleBuffer[0])); Index++) {
602         if (Measurement.Handle == HandleBuffer[Index]) {
603           DpGetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString
604           break;
605         }
606       }
607       // Ensure that the argument strings are not too long.
608       mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
609       mUnicodeToken[11] = 0;
610       if (mGaugeString[0] != 0) {
611         // Display the record if it has a valid handle.
612         if (mShowId) {
613           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS2), gDpHiiHandle,
614             Count,      // 1 based, Which measurement record is being printed
615             Index + 1,  // 1 based, Which handle is being printed
616             mGaugeString,
617             mUnicodeToken,
618             ElapsedTime,
619             Measurement.Identifier
620           );
621         } else {
622           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS), gDpHiiHandle,
623             Count,      // 1 based, Which measurement record is being printed
624             Index + 1,  // 1 based, Which handle is being printed
625             mGaugeString,
626             mUnicodeToken,
627             ElapsedTime
628           );
629         }
630       }
631     }
632   }
633   if (HandleBuffer != &TempHandle) {
634     FreePool (HandleBuffer);
635   }
636   return Status;
637 }
638 
639 /**
640   Gather and print PEIM data.
641 
642   Only prints complete PEIM records
643 
644 **/
645 VOID
ProcessPeims(VOID)646 ProcessPeims(
647   VOID
648 )
649 {
650   MEASUREMENT_RECORD        Measurement;
651   UINT64                    Duration;
652   UINT64                    ElapsedTime;
653   EFI_STRING                StringPtr;
654   UINTN                     LogEntryKey;
655   UINTN                     TIndex;
656   EFI_STRING                StringPtrUnknown;
657 
658   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
659   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PEIMS), NULL);
660   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
661               (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
662   FreePool (StringPtr);
663   FreePool (StringPtrUnknown);
664 
665   if (mShowId) {
666     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION2), gDpHiiHandle);
667   } else {
668     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION), gDpHiiHandle);
669   }
670   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
671   TIndex  = 0;
672   LogEntryKey = 0;
673   while ((LogEntryKey = GetPerformanceMeasurementEx (
674                           LogEntryKey,
675                           &Measurement.Handle,
676                           &Measurement.Token,
677                           &Measurement.Module,
678                           &Measurement.StartTimeStamp,
679                           &Measurement.EndTimeStamp,
680                           &Measurement.Identifier)) != 0)
681   {
682     TIndex++;
683     if ((Measurement.EndTimeStamp == 0) ||
684         (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) != 0)
685        ) {
686       continue;
687     }
688 
689     Duration = GetDuration (&Measurement);
690     ElapsedTime = DurationInMicroSeconds ( Duration );  // Calculate elapsed time in microseconds
691     if (ElapsedTime >= mInterestThreshold) {
692       // PEIM FILE Handle is the start address of its FFS file that contains its file guid.
693       if (mShowId) {
694         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS2), gDpHiiHandle,
695               TIndex,   // 1 based, Which measurement record is being printed
696               Measurement.Handle,  // base address
697               Measurement.Handle,  // file guid
698               ElapsedTime,
699               Measurement.Identifier
700         );
701       } else {
702         ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS), gDpHiiHandle,
703               TIndex,   // 1 based, Which measurement record is being printed
704               Measurement.Handle,  // base address
705               Measurement.Handle,  // file guid
706               ElapsedTime
707         );
708       }
709     }
710   }
711 }
712 
713 /**
714   Gather and print global data.
715 
716   Strips out incomplete or "Execution Phase" records
717   Only prints records where Handle is NULL
718   Increment TIndex for every record, even skipped ones, so that we have an
719   indication of every measurement record taken.
720 
721 **/
722 VOID
ProcessGlobal(VOID)723 ProcessGlobal(
724   VOID
725 )
726 {
727   MEASUREMENT_RECORD        Measurement;
728   UINT64                    Duration;
729   UINT64                    ElapsedTime;
730   EFI_STRING                StringPtr;
731   UINTN                     LogEntryKey;
732   UINTN                     Index;        // Index, or number, of the measurement record being processed
733   EFI_STRING                StringPtrUnknown;
734 
735   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
736   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_GENERAL), NULL);
737   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
738               (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
739   FreePool (StringPtr);
740   FreePool (StringPtrUnknown);
741 
742   if (mShowId) {
743     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION2), gDpHiiHandle);
744   } else {
745     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION), gDpHiiHandle);
746   }
747   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
748 
749   Index = 1;
750   LogEntryKey = 0;
751 
752   while ((LogEntryKey = GetPerformanceMeasurementEx (
753                           LogEntryKey,
754                           &Measurement.Handle,
755                           &Measurement.Token,
756                           &Measurement.Module,
757                           &Measurement.StartTimeStamp,
758                           &Measurement.EndTimeStamp,
759                           &Measurement.Identifier)) != 0)
760   {
761     AsciiStrToUnicodeStr (Measurement.Module, mGaugeString);
762     AsciiStrToUnicodeStr (Measurement.Token, mUnicodeToken);
763     mGaugeString[25] = 0;
764     mUnicodeToken[31] = 0;
765     if ( ! ( IsPhase( &Measurement)  ||
766         (Measurement.Handle != NULL)      ||
767         (Measurement.EndTimeStamp == 0)
768         ))
769     {
770       Duration = GetDuration (&Measurement);
771       ElapsedTime = DurationInMicroSeconds ( Duration );
772       if (ElapsedTime >= mInterestThreshold) {
773         if (mShowId) {
774           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS2), gDpHiiHandle,
775             Index,
776             mGaugeString,
777             mUnicodeToken,
778             ElapsedTime,
779             Measurement.Identifier
780             );
781         } else {
782            ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS), gDpHiiHandle,
783             Index,
784             mGaugeString,
785             mUnicodeToken,
786             ElapsedTime
787             );
788         }
789       }
790     }
791     Index++;
792   }
793 }
794 
795 /**
796   Gather and print cumulative data.
797 
798   Traverse the measurement records and:<BR>
799   For each record with a Token listed in the CumData array:<BR>
800      - Update the instance count and the total, minimum, and maximum durations.
801   Finally, print the gathered cumulative statistics.
802 
803   @param[in]    CustomCumulativeData  A pointer to the cumtom cumulative data.
804 
805 **/
806 VOID
ProcessCumulative(IN PERF_CUM_DATA * CustomCumulativeData OPTIONAL)807 ProcessCumulative(
808   IN PERF_CUM_DATA                  *CustomCumulativeData OPTIONAL
809   )
810 {
811   UINT64                    AvgDur;         // the computed average duration
812   UINT64                    Dur;
813   UINT64                    MinDur;
814   UINT64                    MaxDur;
815   EFI_STRING                StringPtr;
816   UINTN                     TIndex;
817   EFI_STRING                StringPtrUnknown;
818 
819   StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
820   StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_CUMULATIVE), NULL);
821   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
822               (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
823   FreePool (StringPtr);
824   FreePool (StringPtrUnknown);
825 
826   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_1), gDpHiiHandle);
827   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_2), gDpHiiHandle);
828   ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
829 
830   for ( TIndex = 0; TIndex < NumCum; ++TIndex) {
831     if (CumData[TIndex].Count != 0) {
832       AvgDur = DivU64x32 (CumData[TIndex].Duration, CumData[TIndex].Count);
833       AvgDur = DurationInMicroSeconds(AvgDur);
834       Dur    = DurationInMicroSeconds(CumData[TIndex].Duration);
835       MaxDur = DurationInMicroSeconds(CumData[TIndex].MaxDur);
836       MinDur = DurationInMicroSeconds(CumData[TIndex].MinDur);
837 
838       ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), gDpHiiHandle,
839                   CumData[TIndex].Name,
840                   CumData[TIndex].Count,
841                   Dur,
842                   AvgDur,
843                   MinDur,
844                   MaxDur
845                  );
846     }
847   }
848 
849   //
850   // Print the custom cumulative data.
851   //
852   if (CustomCumulativeData != NULL) {
853     if (CustomCumulativeData->Count != 0) {
854       AvgDur = DivU64x32 (CustomCumulativeData->Duration, CustomCumulativeData->Count);
855       AvgDur = DurationInMicroSeconds (AvgDur);
856       Dur    = DurationInMicroSeconds (CustomCumulativeData->Duration);
857       MaxDur = DurationInMicroSeconds (CustomCumulativeData->MaxDur);
858       MinDur = DurationInMicroSeconds (CustomCumulativeData->MinDur);
859     } else {
860       AvgDur = 0;
861       Dur    = 0;
862       MaxDur = 0;
863       MinDur = 0;
864     }
865     ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), gDpHiiHandle,
866                 CustomCumulativeData->Name,
867                 CustomCumulativeData->Count,
868                 Dur,
869                 AvgDur,
870                 MinDur,
871                 MaxDur
872                 );
873   }
874 }
875