1/** @file
2  Trace reporting for the Dp utility.
3
4  Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.
5  (C) Copyright 2015-2016 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**/
50VOID
51GatherStatistics(
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  @retval EFI_SUCCESS           The operation was successful.
140  @retval EFI_ABORTED           The user aborts the operation.
141  @return Others                from a call to gBS->LocateHandleBuffer().
142**/
143EFI_STATUS
144DumpAllTrace(
145  IN UINTN             Limit,
146  IN BOOLEAN           ExcludeFlag
147  )
148{
149  MEASUREMENT_RECORD        Measurement;
150  UINT64                    ElapsedTime;
151  UINT64                    Duration;
152  CHAR16                    *IncFlag;
153  UINTN                     LogEntryKey;
154  UINTN                     Count;
155  UINTN                     Index;
156  UINTN                     TIndex;
157
158  EFI_HANDLE                *HandleBuffer;
159  UINTN                     HandleCount;
160  EFI_STATUS                Status;
161  EFI_STRING                StringPtrUnknown;
162
163  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
164  IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_ALL), NULL);
165  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
166              (IncFlag == NULL) ? StringPtrUnknown : IncFlag);
167  FreePool (StringPtrUnknown);
168
169  // Get Handle information
170  //
171  Status  = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
172  if (EFI_ERROR (Status)) {
173    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), gDpHiiHandle, Status);
174  }
175  else {
176    // We have successfully populated the HandleBuffer
177    // Display ALL Measurement Records
178    //    Up to Limit lines displayed
179    //    Display only records with Elapsed times >= mInterestThreshold
180    //    Display driver names in Module field for records with Handles.
181    //
182    if (mShowId) {
183      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR2), gDpHiiHandle);
184      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_DASHES2), gDpHiiHandle);
185    } else {
186      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_HEADR), gDpHiiHandle);
187      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
188    }
189
190    LogEntryKey = 0;
191    Count = 0;
192    Index = 0;
193    while ( WITHIN_LIMIT(Count, Limit) &&
194            ((LogEntryKey = GetPerformanceMeasurementEx (
195                            LogEntryKey,
196                            &Measurement.Handle,
197                            &Measurement.Token,
198                            &Measurement.Module,
199                            &Measurement.StartTimeStamp,
200                            &Measurement.EndTimeStamp,
201                            &Measurement.Identifier)) != 0)
202          )
203    {
204      ++Index;    // Count every record.  First record is 1.
205      ElapsedTime = 0;
206      SHELL_FREE_NON_NULL (IncFlag);
207      if (Measurement.EndTimeStamp != 0) {
208        Duration = GetDuration (&Measurement);
209        ElapsedTime = DurationInMicroSeconds ( Duration );
210        IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_COMPLETE), NULL);
211      }
212      else {
213        IncFlag = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_INCOMPLETE), NULL);  // Mark incomplete records
214      }
215      if (((Measurement.EndTimeStamp != 0) && (ElapsedTime < mInterestThreshold)) ||
216          ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
217         ) {      // Ignore "uninteresting" or excluded records
218        continue;
219      }
220      ++Count;    // Count the number of records printed
221
222      // If Handle is non-zero, see if we can determine a name for the driver
223      AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString)); // Use Module by default
224      AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
225      if (Measurement.Handle != NULL) {
226        // See if the Handle is in the HandleBuffer
227        for (TIndex = 0; TIndex < HandleCount; TIndex++) {
228          if (Measurement.Handle == HandleBuffer[TIndex]) {
229            DpGetNameFromHandle (HandleBuffer[TIndex]);
230            break;
231          }
232        }
233      }
234
235      if (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) == 0) {
236        UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", Measurement.Handle);
237      }
238
239      // Ensure that the argument strings are not too long.
240      mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
241      mUnicodeToken[13] = 0;
242
243      if (mShowId) {
244        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS2), gDpHiiHandle,
245          Index,      // 1 based, Which measurement record is being printed
246          IncFlag,
247          Measurement.Handle,
248          mGaugeString,
249          mUnicodeToken,
250          ElapsedTime,
251          Measurement.Identifier
252        );
253      } else {
254        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_ALL_VARS), gDpHiiHandle,
255          Index,      // 1 based, Which measurement record is being printed
256          IncFlag,
257          Measurement.Handle,
258          mGaugeString,
259          mUnicodeToken,
260          ElapsedTime
261        );
262      }
263      if (ShellGetExecutionBreakFlag ()) {
264        Status = EFI_ABORTED;
265        break;
266      }
267    }
268  }
269  if (HandleBuffer != NULL) {
270    FreePool (HandleBuffer);
271  }
272  SHELL_FREE_NON_NULL (IncFlag);
273
274  return Status;
275}
276
277/**
278  Gather and print Raw Trace Records.
279
280  All Trace measurements with a duration greater than or equal to
281  mInterestThreshold are printed without interpretation.
282
283  The number of records displayed is controlled by:
284     - records with a duration less than mInterestThreshold microseconds are not displayed.
285     - No more than Limit records are displayed.  A Limit of zero will not limit the output.
286     - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not
287       displayed.
288
289  @pre    The mInterestThreshold global variable is set to the shortest duration to be printed.
290
291  @param[in]    Limit       The number of records to print.  Zero is ALL.
292  @param[in]    ExcludeFlag TRUE to exclude individual Cumulative items from display.
293
294  @retval EFI_SUCCESS           The operation was successful.
295  @retval EFI_ABORTED           The user aborts the operation.
296**/
297EFI_STATUS
298DumpRawTrace(
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  EFI_STATUS    Status;
313
314  Status = EFI_SUCCESS;
315
316  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
317  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_RAWTRACE), NULL);
318  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
319              (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
320  FreePool (StringPtr);
321  FreePool (StringPtrUnknown);
322
323  if (mShowId) {
324    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR2), gDpHiiHandle);
325    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES2), gDpHiiHandle);
326  } else {
327    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_HEADR), gDpHiiHandle);
328    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_DASHES), gDpHiiHandle);
329  }
330
331  LogEntryKey = 0;
332  Count = 0;
333  Index = 0;
334  while ( WITHIN_LIMIT(Count, Limit) &&
335          ((LogEntryKey = GetPerformanceMeasurementEx (
336                          LogEntryKey,
337                          &Measurement.Handle,
338                          &Measurement.Token,
339                          &Measurement.Module,
340                          &Measurement.StartTimeStamp,
341                          &Measurement.EndTimeStamp,
342                          &Measurement.Identifier)) != 0)
343        )
344  {
345    ++Index;    // Count every record.  First record is 1.
346    ElapsedTime = 0;
347    if (Measurement.EndTimeStamp != 0) {
348      Duration = GetDuration (&Measurement);
349      ElapsedTime = DurationInMicroSeconds ( Duration );
350    }
351    if ((ElapsedTime < mInterestThreshold)                 ||
352        ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
353        ) { // Ignore "uninteresting" or Excluded records
354      continue;
355    }
356    ++Count;    // Count the number of records printed
357
358    if (mShowId) {
359      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS2), gDpHiiHandle,
360        Index,      // 1 based, Which measurement record is being printed
361        Measurement.Handle,
362        Measurement.StartTimeStamp,
363        Measurement.EndTimeStamp,
364        Measurement.Token,
365        Measurement.Module,
366        Measurement.Identifier
367      );
368    } else {
369      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_RAW_VARS), gDpHiiHandle,
370        Index,      // 1 based, Which measurement record is being printed
371        Measurement.Handle,
372        Measurement.StartTimeStamp,
373        Measurement.EndTimeStamp,
374        Measurement.Token,
375        Measurement.Module
376      );
377    }
378    if (ShellGetExecutionBreakFlag ()) {
379      Status = EFI_ABORTED;
380      break;
381    }
382  }
383  return Status;
384}
385
386/**
387  Gather and print Major Phase metrics.
388
389  @param[in]    Ticker      The timer value for the END of Shell phase
390
391**/
392VOID
393ProcessPhases(
394  IN UINT64            Ticker
395  )
396{
397  MEASUREMENT_RECORD        Measurement;
398  UINT64                    BdsTimeoutValue;
399  UINT64                    SecTime;
400  UINT64                    PeiTime;
401  UINT64                    DxeTime;
402  UINT64                    BdsTime;
403  UINT64                    ShellTime;
404  UINT64                    ElapsedTime;
405  UINT64                    Duration;
406  UINT64                    Total;
407  EFI_STRING                StringPtr;
408  UINTN                     LogEntryKey;
409  EFI_STRING                StringPtrUnknown;
410
411  BdsTimeoutValue = 0;
412  SecTime         = 0;
413  PeiTime         = 0;
414  DxeTime         = 0;
415  BdsTime         = 0;
416  ShellTime       = 0;
417  //
418  // Get Execution Phase Statistics
419  //
420  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
421  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PHASES), NULL);
422  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
423              (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
424  FreePool (StringPtr);
425  FreePool (StringPtrUnknown);
426
427  LogEntryKey = 0;
428  while ((LogEntryKey = GetPerformanceMeasurementEx (
429                          LogEntryKey,
430                          &Measurement.Handle,
431                          &Measurement.Token,
432                          &Measurement.Module,
433                          &Measurement.StartTimeStamp,
434                          &Measurement.EndTimeStamp,
435                          &Measurement.Identifier)) != 0)
436  {
437    if (AsciiStrnCmp (Measurement.Token, ALit_SHELL, PERF_TOKEN_LENGTH) == 0) {
438      Measurement.EndTimeStamp = Ticker;
439    }
440    if (Measurement.EndTimeStamp == 0) { // Skip "incomplete" records
441      continue;
442    }
443    Duration = GetDuration (&Measurement);
444    if (   Measurement.Handle != NULL
445        && (AsciiStrnCmp (Measurement.Token, ALit_BdsTO, PERF_TOKEN_LENGTH) == 0)
446       )
447    {
448      BdsTimeoutValue = Duration;
449    } else if (AsciiStrnCmp (Measurement.Token, ALit_SEC, PERF_TOKEN_LENGTH) == 0) {
450      SecTime     = Duration;
451    } else if (AsciiStrnCmp (Measurement.Token, ALit_PEI, PERF_TOKEN_LENGTH) == 0) {
452      PeiTime     = Duration;
453    } else if (AsciiStrnCmp (Measurement.Token, ALit_DXE, PERF_TOKEN_LENGTH) == 0) {
454      DxeTime      = Duration;
455    } else if (AsciiStrnCmp (Measurement.Token, ALit_BDS, PERF_TOKEN_LENGTH) == 0) {
456      BdsTime      = Duration;
457    } else if (AsciiStrnCmp (Measurement.Token, ALit_SHELL, PERF_TOKEN_LENGTH) == 0) {
458      ShellTime    = Duration;
459    }
460  }
461
462  Total = 0;
463
464  // print SEC phase duration time
465  //
466  if (SecTime > 0) {
467    ElapsedTime = DurationInMicroSeconds ( SecTime );     // Calculate elapsed time in microseconds
468    Total += DivU64x32 (ElapsedTime, 1000);   // Accumulate time in milliseconds
469    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SEC_PHASE), gDpHiiHandle, ElapsedTime);
470  }
471
472  // print PEI phase duration time
473  //
474  if (PeiTime > 0) {
475    ElapsedTime = DivU64x32 (
476                    PeiTime,
477                    (UINT32)TimerInfo.Frequency
478                    );
479    Total += ElapsedTime;
480    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_PEI, ElapsedTime);
481  }
482
483  // print DXE phase duration time
484  //
485  if (DxeTime > 0) {
486    ElapsedTime = DivU64x32 (
487                    DxeTime,
488                    (UINT32)TimerInfo.Frequency
489                    );
490    Total += ElapsedTime;
491    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_DXE, ElapsedTime);
492  }
493
494  // print BDS phase duration time
495  //
496  if (BdsTime > 0) {
497    ElapsedTime = DivU64x32 (
498                    BdsTime,
499                    (UINT32)TimerInfo.Frequency
500                    );
501    Total += ElapsedTime;
502    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_BDS, ElapsedTime);
503  }
504
505  if (BdsTimeoutValue > 0) {
506    ElapsedTime = DivU64x32 (
507                    BdsTimeoutValue,
508                    (UINT32)TimerInfo.Frequency
509                    );
510    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_BDSTO), gDpHiiHandle, ALit_BdsTO, ElapsedTime);
511  }
512
513  // print SHELL phase duration time
514  //
515  if (ShellTime > 0) {
516    ElapsedTime = DivU64x32 (
517                    ShellTime,
518                    (UINT32)TimerInfo.Frequency
519                    );
520    Total += ElapsedTime;
521    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PHASE_DURATION), gDpHiiHandle, ALit_SHELL, ElapsedTime);
522  }
523
524  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOTAL_DURATION), gDpHiiHandle, Total);
525}
526
527/**
528  Gather and print Handle data.
529
530  @param[in]    ExcludeFlag   TRUE to exclude individual Cumulative items from display.
531
532  @retval EFI_SUCCESS             The operation was successful.
533  @retval EFI_ABORTED             The user aborts the operation.
534  @return Others                  from a call to gBS->LocateHandleBuffer().
535**/
536EFI_STATUS
537ProcessHandles(
538  IN BOOLEAN      ExcludeFlag
539  )
540{
541  MEASUREMENT_RECORD        Measurement;
542  UINT64                    ElapsedTime;
543  UINT64                    Duration;
544  EFI_HANDLE                *HandleBuffer;
545  EFI_STRING                StringPtr;
546  UINTN                     Index;
547  UINTN                     LogEntryKey;
548  UINTN                     Count;
549  UINTN                     HandleCount;
550  EFI_STATUS                Status;
551  EFI_STRING                StringPtrUnknown;
552
553  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
554  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_DRIVERS), NULL);
555  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
556              (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
557  FreePool (StringPtr);
558  FreePool (StringPtrUnknown);
559
560  Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
561  if (EFI_ERROR (Status)) {
562    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), gDpHiiHandle, Status);
563  }
564  else {
565#if DP_DEBUG == 2
566    Print (L"There are %,d Handles defined.\n", (Size / sizeof(HandleBuffer[0])));
567#endif
568
569    if (mShowId) {
570      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION2), gDpHiiHandle);
571    } else {
572      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_SECTION), gDpHiiHandle);
573    }
574    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
575
576    LogEntryKey = 0;
577    Count   = 0;
578    while ((LogEntryKey = GetPerformanceMeasurementEx (
579                            LogEntryKey,
580                            &Measurement.Handle,
581                            &Measurement.Token,
582                            &Measurement.Module,
583                            &Measurement.StartTimeStamp,
584                            &Measurement.EndTimeStamp,
585                            &Measurement.Identifier)) != 0)
586    {
587      Count++;
588      Duration = GetDuration (&Measurement);
589      ElapsedTime = DurationInMicroSeconds ( Duration );
590      if ((ElapsedTime < mInterestThreshold)                 ||
591          (Measurement.EndTimeStamp == 0)                    ||
592          (Measurement.Handle == NULL)                       ||
593          ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0))
594         ) { // Ignore "uninteresting" or excluded records
595        continue;
596      }
597      mGaugeString[0] = 0;    // Empty driver name by default
598      AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
599      // See if the Handle is in the HandleBuffer
600      for (Index = 0; Index < HandleCount; Index++) {
601        if (Measurement.Handle == HandleBuffer[Index]) {
602          DpGetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString
603          break;
604        }
605      }
606      // Ensure that the argument strings are not too long.
607      mGaugeString[DP_GAUGE_STRING_LENGTH] = 0;
608      mUnicodeToken[11] = 0;
609      if (mGaugeString[0] != 0) {
610        // Display the record if it has a valid handle.
611        if (mShowId) {
612          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS2), gDpHiiHandle,
613            Count,      // 1 based, Which measurement record is being printed
614            Index + 1,  // 1 based, Which handle is being printed
615            mGaugeString,
616            mUnicodeToken,
617            ElapsedTime,
618            Measurement.Identifier
619          );
620        } else {
621          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLE_VARS), gDpHiiHandle,
622            Count,      // 1 based, Which measurement record is being printed
623            Index + 1,  // 1 based, Which handle is being printed
624            mGaugeString,
625            mUnicodeToken,
626            ElapsedTime
627          );
628        }
629      }
630      if (ShellGetExecutionBreakFlag ()) {
631        Status = EFI_ABORTED;
632        break;
633      }
634    }
635  }
636  if (HandleBuffer != NULL) {
637    FreePool (HandleBuffer);
638  }
639  return Status;
640}
641
642/**
643  Gather and print PEIM data.
644
645  Only prints complete PEIM records
646
647  @retval EFI_SUCCESS           The operation was successful.
648  @retval EFI_ABORTED           The user aborts the operation.
649**/
650EFI_STATUS
651ProcessPeims(
652  VOID
653)
654{
655  MEASUREMENT_RECORD        Measurement;
656  UINT64                    Duration;
657  UINT64                    ElapsedTime;
658  EFI_STRING                StringPtr;
659  UINTN                     LogEntryKey;
660  UINTN                     TIndex;
661  EFI_STRING                StringPtrUnknown;
662  EFI_STATUS                Status;
663
664  Status = EFI_SUCCESS;
665
666  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
667  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_PEIMS), NULL);
668  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
669              (StringPtr == NULL) ? StringPtrUnknown : StringPtr);
670  FreePool (StringPtr);
671  FreePool (StringPtrUnknown);
672
673  if (mShowId) {
674    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION2), gDpHiiHandle);
675  } else {
676    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_SECTION), gDpHiiHandle);
677  }
678  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
679  TIndex  = 0;
680  LogEntryKey = 0;
681  while ((LogEntryKey = GetPerformanceMeasurementEx (
682                          LogEntryKey,
683                          &Measurement.Handle,
684                          &Measurement.Token,
685                          &Measurement.Module,
686                          &Measurement.StartTimeStamp,
687                          &Measurement.EndTimeStamp,
688                          &Measurement.Identifier)) != 0)
689  {
690    TIndex++;
691    if ((Measurement.EndTimeStamp == 0) ||
692        (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) != 0)
693       ) {
694      continue;
695    }
696
697    Duration = GetDuration (&Measurement);
698    ElapsedTime = DurationInMicroSeconds ( Duration );  // Calculate elapsed time in microseconds
699    if (ElapsedTime >= mInterestThreshold) {
700      // PEIM FILE Handle is the start address of its FFS file that contains its file guid.
701      if (mShowId) {
702        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS2), gDpHiiHandle,
703              TIndex,   // 1 based, Which measurement record is being printed
704              Measurement.Handle,  // base address
705              Measurement.Handle,  // file guid
706              ElapsedTime,
707              Measurement.Identifier
708        );
709      } else {
710        ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_PEIM_VARS), gDpHiiHandle,
711              TIndex,   // 1 based, Which measurement record is being printed
712              Measurement.Handle,  // base address
713              Measurement.Handle,  // file guid
714              ElapsedTime
715        );
716      }
717    }
718    if (ShellGetExecutionBreakFlag ()) {
719      Status = EFI_ABORTED;
720      break;
721    }
722  }
723  return Status;
724}
725
726/**
727  Gather and print global data.
728
729  Strips out incomplete or "Execution Phase" records
730  Only prints records where Handle is NULL
731  Increment TIndex for every record, even skipped ones, so that we have an
732  indication of every measurement record taken.
733
734  @retval EFI_SUCCESS           The operation was successful.
735  @retval EFI_ABORTED           The user aborts the operation.
736**/
737EFI_STATUS
738ProcessGlobal(
739  VOID
740)
741{
742  MEASUREMENT_RECORD        Measurement;
743  UINT64                    Duration;
744  UINT64                    ElapsedTime;
745  EFI_STRING                StringPtr;
746  UINTN                     LogEntryKey;
747  UINTN                     Index;        // Index, or number, of the measurement record being processed
748  EFI_STRING                StringPtrUnknown;
749  EFI_STATUS                Status;
750
751  Status = EFI_SUCCESS;
752
753  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
754  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_GENERAL), NULL);
755  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
756              (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
757  FreePool (StringPtr);
758  FreePool (StringPtrUnknown);
759
760  if (mShowId) {
761    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION2), gDpHiiHandle);
762  } else {
763    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_SECTION), gDpHiiHandle);
764  }
765  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
766
767  Index = 1;
768  LogEntryKey = 0;
769
770  while ((LogEntryKey = GetPerformanceMeasurementEx (
771                          LogEntryKey,
772                          &Measurement.Handle,
773                          &Measurement.Token,
774                          &Measurement.Module,
775                          &Measurement.StartTimeStamp,
776                          &Measurement.EndTimeStamp,
777                          &Measurement.Identifier)) != 0)
778  {
779    AsciiStrToUnicodeStrS (Measurement.Module, mGaugeString, ARRAY_SIZE (mGaugeString));
780    AsciiStrToUnicodeStrS (Measurement.Token, mUnicodeToken, ARRAY_SIZE (mUnicodeToken));
781    mGaugeString[25] = 0;
782    mUnicodeToken[31] = 0;
783    if ( ! ( IsPhase( &Measurement)  ||
784        (Measurement.Handle != NULL)      ||
785        (Measurement.EndTimeStamp == 0)
786        ))
787    {
788      Duration = GetDuration (&Measurement);
789      ElapsedTime = DurationInMicroSeconds ( Duration );
790      if (ElapsedTime >= mInterestThreshold) {
791        if (mShowId) {
792          ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS2), gDpHiiHandle,
793            Index,
794            mGaugeString,
795            mUnicodeToken,
796            ElapsedTime,
797            Measurement.Identifier
798            );
799        } else {
800           ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GLOBAL_VARS), gDpHiiHandle,
801            Index,
802            mGaugeString,
803            mUnicodeToken,
804            ElapsedTime
805            );
806        }
807      }
808    }
809    if (ShellGetExecutionBreakFlag ()) {
810      Status = EFI_ABORTED;
811      break;
812    }
813    Index++;
814  }
815  return Status;
816}
817
818/**
819  Gather and print cumulative data.
820
821  Traverse the measurement records and:<BR>
822  For each record with a Token listed in the CumData array:<BR>
823     - Update the instance count and the total, minimum, and maximum durations.
824  Finally, print the gathered cumulative statistics.
825
826  @param[in]    CustomCumulativeData  A pointer to the cumtom cumulative data.
827
828**/
829VOID
830ProcessCumulative(
831  IN PERF_CUM_DATA                  *CustomCumulativeData OPTIONAL
832  )
833{
834  UINT64                    AvgDur;         // the computed average duration
835  UINT64                    Dur;
836  UINT64                    MinDur;
837  UINT64                    MaxDur;
838  EFI_STRING                StringPtr;
839  UINTN                     TIndex;
840  EFI_STRING                StringPtrUnknown;
841
842  StringPtrUnknown = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
843  StringPtr = HiiGetString (gDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_CUMULATIVE), NULL);
844  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_SECTION_HEADER), gDpHiiHandle,
845              (StringPtr == NULL) ? StringPtrUnknown: StringPtr);
846  FreePool (StringPtr);
847  FreePool (StringPtrUnknown);
848
849  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_1), gDpHiiHandle);
850  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_SECT_2), gDpHiiHandle);
851  ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_DASHES), gDpHiiHandle);
852
853  for ( TIndex = 0; TIndex < NumCum; ++TIndex) {
854    if (CumData[TIndex].Count != 0) {
855      AvgDur = DivU64x32 (CumData[TIndex].Duration, CumData[TIndex].Count);
856      AvgDur = DurationInMicroSeconds(AvgDur);
857      Dur    = DurationInMicroSeconds(CumData[TIndex].Duration);
858      MaxDur = DurationInMicroSeconds(CumData[TIndex].MaxDur);
859      MinDur = DurationInMicroSeconds(CumData[TIndex].MinDur);
860
861      ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), gDpHiiHandle,
862                  CumData[TIndex].Name,
863                  CumData[TIndex].Count,
864                  Dur,
865                  AvgDur,
866                  MinDur,
867                  MaxDur
868                 );
869    }
870  }
871
872  //
873  // Print the custom cumulative data.
874  //
875  if (CustomCumulativeData != NULL) {
876    if (CustomCumulativeData->Count != 0) {
877      AvgDur = DivU64x32 (CustomCumulativeData->Duration, CustomCumulativeData->Count);
878      AvgDur = DurationInMicroSeconds (AvgDur);
879      Dur    = DurationInMicroSeconds (CustomCumulativeData->Duration);
880      MaxDur = DurationInMicroSeconds (CustomCumulativeData->MaxDur);
881      MinDur = DurationInMicroSeconds (CustomCumulativeData->MinDur);
882    } else {
883      AvgDur = 0;
884      Dur    = 0;
885      MaxDur = 0;
886      MinDur = 0;
887    }
888    ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CUMULATIVE_STATS), gDpHiiHandle,
889                CustomCumulativeData->Name,
890                CustomCumulativeData->Count,
891                Dur,
892                AvgDur,
893                MinDur,
894                MaxDur
895                );
896  }
897}
898