]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/DynamicCommand/DpDynamicCommand/Dp.c
1799ab176a16904e354a773eed8fae66555147fd
[mirror_edk2.git] / ShellPkg / DynamicCommand / DpDynamicCommand / Dp.c
1 /** @file
2 Shell command for Displaying Performance Metrics.
3
4 The Dp command reads performance data and presents it in several
5 different formats depending upon the needs of the user. Both
6 Trace and Measured Profiling information is processed and presented.
7
8 Dp uses the "PerformanceLib" to read the measurement records.
9 The "TimerLib" provides information about the timer, such as frequency,
10 beginning, and ending counter values.
11 Measurement records contain identifying information (Handle, Token, Module)
12 and start and end time values.
13 Dp uses this information to group records in different ways. It also uses
14 timer information to calculate elapsed time for each measurement.
15
16 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.
17 (C) Copyright 2015-2016 Hewlett Packard Enterprise Development LP<BR>
18 SPDX-License-Identifier: BSD-2-Clause-Patent
19 **/
20
21 #include "Dp.h"
22 #include "Literals.h"
23 #include "DpInternal.h"
24
25 #pragma pack(1)
26
27 typedef struct {
28 EFI_ACPI_DESCRIPTION_HEADER Header;
29 UINT32 Entry;
30 } RSDT_TABLE;
31
32 typedef struct {
33 EFI_ACPI_DESCRIPTION_HEADER Header;
34 UINT64 Entry;
35 } XSDT_TABLE;
36
37 #pragma pack()
38
39 EFI_HII_HANDLE mDpHiiHandle;
40
41 typedef struct {
42 EFI_HANDLE Handle;
43 EFI_GUID ModuleGuid;
44 } HANDLE_GUID_MAP;
45
46 HANDLE_GUID_MAP *mCacheHandleGuidTable;
47 UINTN mCachePairCount = 0;
48
49 //
50 /// Module-Global Variables
51 ///@{
52 CHAR16 mGaugeString[DP_GAUGE_STRING_LENGTH + 1];
53 CHAR16 mUnicodeToken[DXE_PERFORMANCE_STRING_SIZE];
54 UINT64 mInterestThreshold;
55 BOOLEAN mShowId = FALSE;
56 UINT8 *mBootPerformanceTable;
57 UINTN mBootPerformanceTableSize;
58 BOOLEAN mPeiPhase = FALSE;
59 BOOLEAN mDxePhase = FALSE;
60
61 PERF_SUMMARY_DATA SummaryData = { 0 }; ///< Create the SummaryData structure and init. to ZERO.
62 MEASUREMENT_RECORD *mMeasurementList = NULL;
63 UINTN mMeasurementNum = 0;
64
65 /// Items for which to gather cumulative statistics.
66 PERF_CUM_DATA CumData[] = {
67 PERF_INIT_CUM_DATA (LOAD_IMAGE_TOK),
68 PERF_INIT_CUM_DATA (START_IMAGE_TOK),
69 PERF_INIT_CUM_DATA (DRIVERBINDING_START_TOK),
70 PERF_INIT_CUM_DATA (DRIVERBINDING_SUPPORT_TOK),
71 PERF_INIT_CUM_DATA (DRIVERBINDING_STOP_TOK)
72 };
73
74 /// Number of items for which we are gathering cumulative statistics.
75 UINT32 const NumCum = sizeof (CumData) / sizeof (PERF_CUM_DATA);
76
77 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
78 { L"-v", TypeFlag }, // -v Verbose Mode
79 { L"-A", TypeFlag }, // -A All, Cooked
80 { L"-R", TypeFlag }, // -R RAW All
81 { L"-s", TypeFlag }, // -s Summary
82 { L"-x", TypeFlag }, // -x eXclude Cumulative Items
83 { L"-i", TypeFlag }, // -i Display Identifier
84 { L"-c", TypeValue }, // -c Display cumulative data.
85 { L"-n", TypeValue }, // -n # Number of records to display for A and R
86 { L"-t", TypeValue }, // -t # Threshold of interest
87 { NULL, TypeMax }
88 };
89
90 ///@}
91
92 /**
93 Display the trailing Verbose information.
94 **/
95 VOID
96 DumpStatistics (
97 void
98 )
99 {
100 EFI_STRING StringPtr;
101 EFI_STRING StringPtrUnknown;
102
103 StringPtr = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_DP_SECTION_STATISTICS), NULL);
104 StringPtrUnknown = HiiGetString (mDpHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL);
105 ShellPrintHiiEx (
106 -1,
107 -1,
108 NULL,
109 STRING_TOKEN (STR_DP_SECTION_HEADER),
110 mDpHiiHandle,
111 (StringPtr == NULL) ? StringPtrUnknown : StringPtr
112 );
113 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMTRACE), mDpHiiHandle, SummaryData.NumTrace);
114 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMINCOMPLETE), mDpHiiHandle, SummaryData.NumIncomplete);
115 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPHASES), mDpHiiHandle, SummaryData.NumSummary);
116 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMHANDLES), mDpHiiHandle, SummaryData.NumHandles, SummaryData.NumTrace - SummaryData.NumHandles);
117 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMPEIMS), mDpHiiHandle, SummaryData.NumPEIMs);
118 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_STATS_NUMGLOBALS), mDpHiiHandle, SummaryData.NumGlobal);
119 SHELL_FREE_NON_NULL (StringPtr);
120 SHELL_FREE_NON_NULL (StringPtrUnknown);
121 }
122
123 /**
124 Get Boot performance table form Acpi table.
125
126 **/
127 EFI_STATUS
128 GetBootPerformanceTable (
129 )
130 {
131 FIRMWARE_PERFORMANCE_TABLE *FirmwarePerformanceTable;
132
133 FirmwarePerformanceTable = (FIRMWARE_PERFORMANCE_TABLE *)EfiLocateFirstAcpiTable (
134 EFI_ACPI_5_0_FIRMWARE_PERFORMANCE_DATA_TABLE_SIGNATURE
135 );
136 if (FirmwarePerformanceTable == NULL) {
137 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_GET_ACPI_FPDT_FAIL), mDpHiiHandle);
138 return EFI_NOT_FOUND;
139 }
140
141 mBootPerformanceTable = (UINT8 *)(UINTN)FirmwarePerformanceTable->BootPointerRecord.BootPerformanceTablePointer;
142 mBootPerformanceTableSize = ((BOOT_PERFORMANCE_TABLE *)mBootPerformanceTable)->Header.Length;
143
144 return EFI_SUCCESS;
145 }
146
147 /**
148 Get Handle form Module Guid.
149
150 @param ModuleGuid Module Guid.
151 @param Handle The handle to be returned.
152
153 **/
154 VOID
155 GetHandleFormModuleGuid (
156 IN EFI_GUID *ModuleGuid,
157 IN OUT EFI_HANDLE *Handle
158 )
159 {
160 UINTN Index;
161
162 if (IsZeroGuid (ModuleGuid)) {
163 *Handle = NULL;
164 }
165
166 //
167 // Try to get the Handle from the cached array.
168 //
169 for (Index = 0; Index < mCachePairCount; Index++) {
170 if (CompareGuid (ModuleGuid, &mCacheHandleGuidTable[Index].ModuleGuid)) {
171 *Handle = mCacheHandleGuidTable[Index].Handle;
172 break;
173 }
174 }
175
176 if (Index >= mCachePairCount) {
177 *Handle = NULL;
178 }
179 }
180
181 /**
182 Cache the GUID and handle mapping pairs. In order to save time for searching.
183
184 **/
185 EFI_STATUS
186 BuildCachedGuidHandleTable (
187 VOID
188 )
189 {
190 EFI_STATUS Status;
191 EFI_HANDLE *HandleBuffer;
192 UINTN HandleCount;
193 UINTN Index;
194 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
195 EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
196 EFI_GUID *TempGuid;
197 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FvFilePath;
198
199 Status = gBS->LocateHandleBuffer (AllHandles, NULL, NULL, &HandleCount, &HandleBuffer);
200 if (EFI_ERROR (Status)) {
201 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_HANDLES_ERROR), mDpHiiHandle, Status);
202 return Status;
203 }
204
205 mCacheHandleGuidTable = AllocateZeroPool (HandleCount * sizeof (HANDLE_GUID_MAP));
206 if (mCacheHandleGuidTable == NULL) {
207 return EFI_OUT_OF_RESOURCES;
208 }
209
210 for (Index = 0; Index < HandleCount; Index++) {
211 //
212 // Try Handle as ImageHandle.
213 //
214 Status = gBS->HandleProtocol (
215 HandleBuffer[Index],
216 &gEfiLoadedImageProtocolGuid,
217 (VOID **)&LoadedImage
218 );
219 if (EFI_ERROR (Status)) {
220 //
221 // Try Handle as Controller Handle
222 //
223 Status = gBS->OpenProtocol (
224 HandleBuffer[Index],
225 &gEfiDriverBindingProtocolGuid,
226 (VOID **)&DriverBinding,
227 NULL,
228 NULL,
229 EFI_OPEN_PROTOCOL_GET_PROTOCOL
230 );
231 if (!EFI_ERROR (Status)) {
232 //
233 // Get Image protocol from ImageHandle
234 //
235 Status = gBS->HandleProtocol (
236 DriverBinding->ImageHandle,
237 &gEfiLoadedImageProtocolGuid,
238 (VOID **)&LoadedImage
239 );
240 }
241 }
242
243 if (!EFI_ERROR (Status) && (LoadedImage != NULL)) {
244 //
245 // Get Module Guid from DevicePath.
246 //
247 if ((LoadedImage->FilePath != NULL) &&
248 (LoadedImage->FilePath->Type == MEDIA_DEVICE_PATH) &&
249 (LoadedImage->FilePath->SubType == MEDIA_PIWG_FW_FILE_DP)
250 )
251 {
252 FvFilePath = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)LoadedImage->FilePath;
253 TempGuid = &FvFilePath->FvFileName;
254
255 mCacheHandleGuidTable[mCachePairCount].Handle = HandleBuffer[Index];
256 CopyGuid (&mCacheHandleGuidTable[mCachePairCount].ModuleGuid, TempGuid);
257 mCachePairCount++;
258 }
259 }
260 }
261
262 if (HandleBuffer != NULL) {
263 FreePool (HandleBuffer);
264 HandleBuffer = NULL;
265 }
266
267 return EFI_SUCCESS;
268 }
269
270 /**
271 Get Measurement form Fpdt records.
272
273 @param RecordHeader Pointer to the start record.
274 @param IsStart Is start record or End record.
275 @param Measurement Pointer to the measurement which need to be filled.
276
277 **/
278 VOID
279 GetMeasurementInfo (
280 IN EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader,
281 IN BOOLEAN IsStart,
282 IN OUT MEASUREMENT_RECORD *Measurement
283 )
284 {
285 VOID *ModuleGuid;
286 EFI_HANDLE StartHandle;
287
288 switch (RecordHeader->Type) {
289 case FPDT_GUID_EVENT_TYPE:
290 ModuleGuid = &(((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Guid);
291 Measurement->Identifier = ((UINT32)((FPDT_GUID_EVENT_RECORD *)RecordHeader)->ProgressID);
292 if (IsStart) {
293 Measurement->StartTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
294 } else {
295 Measurement->EndTimeStamp = ((FPDT_GUID_EVENT_RECORD *)RecordHeader)->Timestamp;
296 }
297
298 switch (Measurement->Identifier) {
299 case MODULE_START_ID:
300 case MODULE_END_ID:
301 if (mPeiPhase) {
302 Measurement->Token = ALit_PEIM;
303 Measurement->Module = ALit_PEIM;
304 } else if (mDxePhase) {
305 Measurement->Token = ALit_START_IMAGE;
306 Measurement->Module = ALit_START_IMAGE;
307 }
308
309 break;
310 default:
311 ASSERT (FALSE);
312 }
313
314 if ((Measurement->Token != NULL) && (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0)) {
315 Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
316 } else {
317 GetHandleFormModuleGuid (ModuleGuid, &StartHandle);
318 Measurement->Handle = StartHandle;
319 //
320 // When no perf entry to record the PEI and DXE phase,
321 // For start image, we need detect the PEIM and non PEIM here.
322 //
323 if (Measurement->Token == NULL) {
324 if ((StartHandle == NULL) && !IsZeroGuid (ModuleGuid)) {
325 Measurement->Token = ALit_PEIM;
326 Measurement->Module = ALit_PEIM;
327 Measurement->Handle = ModuleGuid;
328 } else {
329 Measurement->Token = ALit_START_IMAGE;
330 Measurement->Module = ALit_START_IMAGE;
331 }
332 }
333 }
334
335 break;
336
337 case FPDT_DYNAMIC_STRING_EVENT_TYPE:
338 ModuleGuid = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
339 Measurement->Identifier = ((UINT32)((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
340 if (IsStart) {
341 Measurement->StartTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
342 } else {
343 Measurement->EndTimeStamp = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
344 }
345
346 switch (Measurement->Identifier) {
347 case MODULE_START_ID:
348 case MODULE_END_ID:
349 if (mPeiPhase) {
350 Measurement->Token = ALit_PEIM;
351 } else if (mDxePhase) {
352 Measurement->Token = ALit_START_IMAGE;
353 }
354
355 break;
356
357 case MODULE_LOADIMAGE_START_ID:
358 case MODULE_LOADIMAGE_END_ID:
359 Measurement->Token = ALit_LOAD_IMAGE;
360 break;
361
362 case MODULE_DB_START_ID:
363 case MODULE_DB_END_ID:
364 Measurement->Token = ALit_DB_START;
365 break;
366
367 case MODULE_DB_SUPPORT_START_ID:
368 case MODULE_DB_SUPPORT_END_ID:
369 Measurement->Token = ALit_DB_SUPPORT;
370 break;
371
372 case MODULE_DB_STOP_START_ID:
373 case MODULE_DB_STOP_END_ID:
374 Measurement->Token = ALit_DB_STOP;
375 break;
376
377 default:
378 Measurement->Token = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
379 break;
380 }
381
382 Measurement->Module = ((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->String;
383
384 if ((Measurement->Token != NULL) && (AsciiStrCmp (Measurement->Token, ALit_PEIM) == 0)) {
385 Measurement->Handle = &(((FPDT_DYNAMIC_STRING_EVENT_RECORD *)RecordHeader)->Guid);
386 } else {
387 GetHandleFormModuleGuid (ModuleGuid, &StartHandle);
388 Measurement->Handle = StartHandle;
389 //
390 // When no perf entry to record the PEI and DXE phase,
391 // For start image, we need detect the PEIM and non PEIM here.
392 //
393 if ((Measurement->Token == NULL) && ((Measurement->Identifier == MODULE_START_ID) || (Measurement->Identifier == MODULE_END_ID))) {
394 if ((StartHandle == NULL) && !IsZeroGuid (ModuleGuid)) {
395 Measurement->Token = ALit_PEIM;
396 Measurement->Handle = ModuleGuid;
397 } else {
398 Measurement->Token = ALit_START_IMAGE;
399 }
400 }
401 }
402
403 break;
404
405 case FPDT_GUID_QWORD_EVENT_TYPE:
406 ModuleGuid = &(((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Guid);
407 Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->ProgressID);
408 if (IsStart) {
409 Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
410 } else {
411 Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_EVENT_RECORD *)RecordHeader)->Timestamp;
412 }
413
414 switch (Measurement->Identifier) {
415 case MODULE_DB_START_ID:
416 Measurement->Token = ALit_DB_START;
417 Measurement->Module = ALit_DB_START;
418 break;
419
420 case MODULE_DB_SUPPORT_START_ID:
421 case MODULE_DB_SUPPORT_END_ID:
422 Measurement->Token = ALit_DB_SUPPORT;
423 Measurement->Module = ALit_DB_SUPPORT;
424 break;
425
426 case MODULE_DB_STOP_START_ID:
427 case MODULE_DB_STOP_END_ID:
428 Measurement->Token = ALit_DB_STOP;
429 Measurement->Module = ALit_DB_STOP;
430 break;
431
432 case MODULE_LOADIMAGE_START_ID:
433 case MODULE_LOADIMAGE_END_ID:
434 Measurement->Token = ALit_LOAD_IMAGE;
435 Measurement->Module = ALit_LOAD_IMAGE;
436 break;
437
438 default:
439 ASSERT (FALSE);
440 }
441
442 GetHandleFormModuleGuid (ModuleGuid, &StartHandle);
443 Measurement->Handle = StartHandle;
444 break;
445
446 case FPDT_GUID_QWORD_STRING_EVENT_TYPE:
447 ModuleGuid = &(((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Guid);
448 Measurement->Identifier = ((UINT32)((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
449 if (IsStart) {
450 Measurement->StartTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
451 } else {
452 Measurement->EndTimeStamp = ((FPDT_GUID_QWORD_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
453 }
454
455 //
456 // Currently only "DB:Start:" end record with FPDT_GUID_QWORD_STRING_EVENT_TYPE.
457 //
458 switch (Measurement->Identifier) {
459 case MODULE_DB_END_ID:
460 Measurement->Token = ALit_DB_START;
461 Measurement->Module = ALit_DB_START;
462 break;
463 default:
464 ASSERT (FALSE);
465 }
466
467 GetHandleFormModuleGuid (ModuleGuid, &StartHandle);
468 Measurement->Handle = StartHandle;
469 break;
470
471 case FPDT_DUAL_GUID_STRING_EVENT_TYPE:
472 ModuleGuid = &(((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Guid1);
473 Measurement->Identifier = ((UINT32)((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->ProgressID);
474 if (IsStart) {
475 Measurement->StartTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
476 } else {
477 Measurement->EndTimeStamp = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->Timestamp;
478 }
479
480 Measurement->Token = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String;
481 Measurement->Module = ((FPDT_DUAL_GUID_STRING_EVENT_RECORD *)RecordHeader)->String;
482 GetHandleFormModuleGuid (ModuleGuid, &StartHandle);
483 Measurement->Handle = StartHandle;
484 break;
485
486 default:
487 break;
488 }
489 }
490
491 /**
492 Search the start measurement in the mMeasurementList for the end measurement.
493
494 @param EndMeasureMent Measurement for end record.
495
496 **/
497 VOID
498 SearchMeasurement (
499 IN MEASUREMENT_RECORD *EndMeasureMent
500 )
501 {
502 INTN Index;
503
504 for (Index = mMeasurementNum - 1; Index >= 0; Index--) {
505 if (AsciiStrCmp (EndMeasureMent->Token, ALit_PEIM) == 0) {
506 if ((mMeasurementList[Index].EndTimeStamp == 0) && (EndMeasureMent->Handle != NULL) && (mMeasurementList[Index].Handle != NULL) &&
507 CompareGuid (mMeasurementList[Index].Handle, EndMeasureMent->Handle) &&
508 (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
509 (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0))
510 {
511 mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
512 break;
513 }
514 } else if (EndMeasureMent->Identifier == PERF_CROSSMODULE_END_ID) {
515 if ((mMeasurementList[Index].EndTimeStamp == 0) &&
516 (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
517 (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0) &&
518 (mMeasurementList[Index].Identifier == PERF_CROSSMODULE_START_ID))
519 {
520 mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
521 break;
522 }
523 } else {
524 if ((mMeasurementList[Index].EndTimeStamp == 0) && (mMeasurementList[Index].Handle == EndMeasureMent->Handle) &&
525 (AsciiStrCmp (mMeasurementList[Index].Token, EndMeasureMent->Token) == 0) &&
526 (AsciiStrCmp (mMeasurementList[Index].Module, EndMeasureMent->Module) == 0))
527 {
528 mMeasurementList[Index].EndTimeStamp = EndMeasureMent->EndTimeStamp;
529 break;
530 }
531 }
532 }
533 }
534
535 /**
536 Generate the measure record array.
537
538 **/
539 EFI_STATUS
540 BuildMeasurementList (
541 )
542 {
543 EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *RecordHeader;
544 UINT8 *PerformanceTablePtr;
545 UINT16 StartProgressId;
546 UINTN TableLength;
547 UINT8 *StartRecordEvent;
548 MEASUREMENT_RECORD MeasureMent;
549
550 mMeasurementList = AllocateZeroPool (mBootPerformanceTableSize);
551 if (mMeasurementList == NULL) {
552 return EFI_OUT_OF_RESOURCES;
553 }
554
555 TableLength = sizeof (BOOT_PERFORMANCE_TABLE);
556 PerformanceTablePtr = (mBootPerformanceTable + TableLength);
557
558 while (TableLength < mBootPerformanceTableSize) {
559 RecordHeader = (EFI_ACPI_5_0_FPDT_PERFORMANCE_RECORD_HEADER *)PerformanceTablePtr;
560 StartRecordEvent = (UINT8 *)RecordHeader;
561 StartProgressId = ((FPDT_GUID_EVENT_RECORD *)StartRecordEvent)->ProgressID;
562
563 //
564 // If the record with ProgressId 0, the record doesn't appear in pairs. The timestamp in the record is the EndTimeStamp, its StartTimeStamp is 0.
565 // If the record is the start record, fill the info to the measurement in the mMeasurementList.
566 // If the record is the end record, find the related start measurement in the mMeasurementList and fill the EndTimeStamp.
567 //
568 if (StartProgressId == 0) {
569 GetMeasurementInfo (RecordHeader, FALSE, &(mMeasurementList[mMeasurementNum]));
570 mMeasurementNum++;
571 } else if ((((StartProgressId >= PERF_EVENTSIGNAL_START_ID) && ((StartProgressId & 0x000F) == 0)) ||
572 ((StartProgressId < PERF_EVENTSIGNAL_START_ID) && ((StartProgressId & 0x0001) != 0))))
573 {
574 //
575 // Since PEIM and StartImage has same Type and ID when PCD PcdEdkiiFpdtStringRecordEnableOnly = FALSE
576 // So we need to identify these two kinds of record through different phase.
577 //
578 if (StartProgressId == PERF_CROSSMODULE_START_ID ) {
579 if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_PEI) == 0) {
580 mPeiPhase = TRUE;
581 } else if (AsciiStrCmp (((FPDT_DYNAMIC_STRING_EVENT_RECORD *)StartRecordEvent)->String, ALit_DXE) == 0) {
582 mDxePhase = TRUE;
583 mPeiPhase = FALSE;
584 }
585 }
586
587 // Get measurement info form the start record to the mMeasurementList.
588 GetMeasurementInfo (RecordHeader, TRUE, &(mMeasurementList[mMeasurementNum]));
589 mMeasurementNum++;
590 } else {
591 ZeroMem (&MeasureMent, sizeof (MEASUREMENT_RECORD));
592 GetMeasurementInfo (RecordHeader, FALSE, &MeasureMent);
593 SearchMeasurement (&MeasureMent);
594 }
595
596 TableLength += RecordHeader->Length;
597 PerformanceTablePtr += RecordHeader->Length;
598 }
599
600 return EFI_SUCCESS;
601 }
602
603 /**
604 Initialize the cumulative data.
605
606 **/
607 VOID
608 InitCumulativeData (
609 VOID
610 )
611 {
612 UINTN Index;
613
614 for (Index = 0; Index < NumCum; ++Index) {
615 CumData[Index].Count = 0;
616 CumData[Index].MinDur = PERF_MAXDUR;
617 CumData[Index].MaxDur = 0;
618 CumData[Index].Duration = 0;
619 }
620 }
621
622 /**
623 Initialize the Summary data.
624
625 **/
626 VOID
627 InitSummaryData (
628 VOID
629 )
630 {
631 SummaryData.NumTrace = 0;
632 SummaryData.NumIncomplete = 0;
633 SummaryData.NumSummary = 0;
634 SummaryData.NumHandles = 0;
635 SummaryData.NumPEIMs = 0;
636 SummaryData.NumGlobal = 0;
637 }
638
639 /**
640 Dump performance data.
641
642 @param[in] ImageHandle The image handle.
643 @param[in] SystemTable The system table.
644
645 @retval SHELL_SUCCESS Command completed successfully.
646 @retval SHELL_INVALID_PARAMETER Command usage error.
647 @retval SHELL_ABORTED The user aborts the operation.
648 @retval value Unknown error.
649 **/
650 SHELL_STATUS
651 RunDp (
652 IN EFI_HANDLE ImageHandle,
653 IN EFI_SYSTEM_TABLE *SystemTable
654 )
655 {
656 LIST_ENTRY *ParamPackage;
657 CONST CHAR16 *CmdLineArg;
658 EFI_STATUS Status;
659
660 PERFORMANCE_PROPERTY *PerformanceProperty;
661 UINTN Number2Display;
662
663 EFI_STRING StringPtr;
664 BOOLEAN SummaryMode;
665 BOOLEAN VerboseMode;
666 BOOLEAN AllMode;
667 BOOLEAN RawMode;
668 BOOLEAN ExcludeMode;
669 BOOLEAN CumulativeMode;
670 CONST CHAR16 *CustomCumulativeToken;
671 PERF_CUM_DATA *CustomCumulativeData;
672 UINTN NameSize;
673 SHELL_STATUS ShellStatus;
674 TIMER_INFO TimerInfo;
675 UINT64 Intermediate;
676
677 StringPtr = NULL;
678 SummaryMode = FALSE;
679 VerboseMode = FALSE;
680 AllMode = FALSE;
681 RawMode = FALSE;
682 ExcludeMode = FALSE;
683 CumulativeMode = FALSE;
684 CustomCumulativeData = NULL;
685 ShellStatus = SHELL_SUCCESS;
686
687 //
688 // initialize the shell lib (we must be in non-auto-init...)
689 //
690 Status = ShellInitialize ();
691 ASSERT_EFI_ERROR (Status);
692
693 //
694 // Process Command Line arguments
695 //
696 Status = ShellCommandLineParse (ParamList, &ParamPackage, NULL, TRUE);
697 if (EFI_ERROR (Status)) {
698 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_ARG), mDpHiiHandle);
699 return SHELL_INVALID_PARAMETER;
700 } else if (ShellCommandLineGetCount (ParamPackage) > 1) {
701 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_MANY), mDpHiiHandle);
702 return SHELL_INVALID_PARAMETER;
703 }
704
705 //
706 // Boolean options
707 //
708 VerboseMode = ShellCommandLineGetFlag (ParamPackage, L"-v");
709 SummaryMode = (BOOLEAN)(ShellCommandLineGetFlag (ParamPackage, L"-S") || ShellCommandLineGetFlag (ParamPackage, L"-s"));
710 AllMode = ShellCommandLineGetFlag (ParamPackage, L"-A");
711 RawMode = ShellCommandLineGetFlag (ParamPackage, L"-R");
712 ExcludeMode = ShellCommandLineGetFlag (ParamPackage, L"-x");
713 mShowId = ShellCommandLineGetFlag (ParamPackage, L"-i");
714 CumulativeMode = ShellCommandLineGetFlag (ParamPackage, L"-c");
715
716 if (AllMode && RawMode) {
717 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_CONFLICT_ARG), mDpHiiHandle, L"-A", L"-R");
718 return SHELL_INVALID_PARAMETER;
719 }
720
721 // Options with Values
722 if (ShellCommandLineGetFlag (ParamPackage, L"-n")) {
723 CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-n");
724 if (CmdLineArg == NULL) {
725 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
726 return SHELL_INVALID_PARAMETER;
727 } else {
728 if (!(RawMode || AllMode)) {
729 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_NO_RAW_ALL), mDpHiiHandle);
730 return SHELL_INVALID_PARAMETER;
731 }
732
733 Status = ShellConvertStringToUint64 (CmdLineArg, &Intermediate, FALSE, TRUE);
734 if (EFI_ERROR (Status)) {
735 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-n");
736 return SHELL_INVALID_PARAMETER;
737 } else {
738 Number2Display = (UINTN)Intermediate;
739 if ((Number2Display == 0) || (Number2Display > MAXIMUM_DISPLAYCOUNT)) {
740 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_RANGE), mDpHiiHandle, L"-n", 0, MAXIMUM_DISPLAYCOUNT);
741 return SHELL_INVALID_PARAMETER;
742 }
743 }
744 }
745 } else {
746 Number2Display = DEFAULT_DISPLAYCOUNT;
747 }
748
749 if (ShellCommandLineGetFlag (ParamPackage, L"-t")) {
750 CmdLineArg = ShellCommandLineGetValue (ParamPackage, L"-t");
751 if (CmdLineArg == NULL) {
752 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
753 return SHELL_INVALID_PARAMETER;
754 } else {
755 Status = ShellConvertStringToUint64 (CmdLineArg, &Intermediate, FALSE, TRUE);
756 if (EFI_ERROR (Status)) {
757 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_INVALID_NUM_ARG), mDpHiiHandle, L"-t");
758 return SHELL_INVALID_PARAMETER;
759 } else {
760 mInterestThreshold = Intermediate;
761 }
762 }
763 } else {
764 mInterestThreshold = DEFAULT_THRESHOLD; // 1ms := 1,000 us
765 }
766
767 if (ShellCommandLineGetFlag (ParamPackage, L"-c")) {
768 CustomCumulativeToken = ShellCommandLineGetValue (ParamPackage, L"-c");
769 if (CustomCumulativeToken == NULL) {
770 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_TOO_FEW), mDpHiiHandle);
771 return SHELL_INVALID_PARAMETER;
772 } else {
773 CustomCumulativeData = AllocateZeroPool (sizeof (PERF_CUM_DATA));
774 if (CustomCumulativeData == NULL) {
775 ShellStatus = SHELL_OUT_OF_RESOURCES;
776 goto Done;
777 }
778
779 CustomCumulativeData->MinDur = PERF_MAXDUR;
780 CustomCumulativeData->MaxDur = 0;
781 CustomCumulativeData->Count = 0;
782 CustomCumulativeData->Duration = 0;
783 NameSize = StrLen (CustomCumulativeToken) + 1;
784 CustomCumulativeData->Name = AllocateZeroPool (NameSize);
785 if (CustomCumulativeData->Name == NULL) {
786 ShellStatus = SHELL_OUT_OF_RESOURCES;
787 goto Done;
788 }
789
790 UnicodeStrToAsciiStrS (CustomCumulativeToken, CustomCumulativeData->Name, NameSize);
791 }
792 }
793
794 //
795 // DP dump performance data by parsing FPDT table in ACPI table.
796 // Folloing 3 steps are to get the measurement form the FPDT table.
797 //
798
799 //
800 // 1. Get FPDT from ACPI table.
801 //
802 Status = GetBootPerformanceTable ();
803 if (EFI_ERROR (Status)) {
804 ShellStatus = Status;
805 goto Done;
806 }
807
808 //
809 // 2. Cache the ModuleGuid and hanlde mapping table.
810 //
811 Status = BuildCachedGuidHandleTable ();
812 if (EFI_ERROR (Status)) {
813 ShellStatus = Status;
814 goto Done;
815 }
816
817 //
818 // 3. Build the measurement array form the FPDT records.
819 //
820 Status = BuildMeasurementList ();
821 if (EFI_ERROR (Status)) {
822 ShellStatus = SHELL_OUT_OF_RESOURCES;
823 goto Done;
824 }
825
826 //
827 // Initialize the pre-defined cumulative data.
828 //
829 InitCumulativeData ();
830
831 //
832 // Initialize the Summary data.
833 //
834 InitSummaryData ();
835
836 //
837 // Timer specific processing
838 //
839 // Get the Performance counter characteristics:
840 // Freq = Frequency in Hz
841 // StartCount = Value loaded into the counter when it starts counting
842 // EndCount = Value counter counts to before it needs to be reset
843 //
844 Status = EfiGetSystemConfigurationTable (&gPerformanceProtocolGuid, (VOID **)&PerformanceProperty);
845 if (EFI_ERROR (Status) || (PerformanceProperty == NULL)) {
846 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_PERF_PROPERTY_NOT_FOUND), mDpHiiHandle);
847 goto Done;
848 }
849
850 TimerInfo.Frequency = (UINT32)DivU64x32 (PerformanceProperty->Frequency, 1000);
851 TimerInfo.StartCount = 0;
852 TimerInfo.EndCount = 0xFFFF;
853 TimerInfo.CountUp = TRUE;
854
855 //
856 // Print header
857 //
858 // print DP's build version
859 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_BUILD_REVISION), mDpHiiHandle, DP_MAJOR_VERSION, DP_MINOR_VERSION);
860
861 // print performance timer characteristics
862 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_KHZ), mDpHiiHandle, TimerInfo.Frequency);
863
864 if (VerboseMode && !RawMode) {
865 StringPtr = HiiGetString (
866 mDpHiiHandle,
867 (EFI_STRING_ID)(TimerInfo.CountUp ? STRING_TOKEN (STR_DP_UP) : STRING_TOKEN (STR_DP_DOWN)),
868 NULL
869 );
870 ASSERT (StringPtr != NULL);
871 // Print Timer count range and direction
872 ShellPrintHiiEx (
873 -1,
874 -1,
875 NULL,
876 STRING_TOKEN (STR_DP_TIMER_PROPERTIES),
877 mDpHiiHandle,
878 StringPtr,
879 TimerInfo.StartCount,
880 TimerInfo.EndCount
881 );
882 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_DP_VERBOSE_THRESHOLD), mDpHiiHandle, mInterestThreshold);
883 }
884
885 /****************************************************************************
886 **** Print Sections based on command line options
887 ****
888 **** Option modes have the following priority:
889 **** v Verbose -- Valid in combination with any other options
890 **** t Threshold -- Modifies All, Raw, and Cooked output
891 **** Default is 0 for All and Raw mode
892 **** Default is DEFAULT_THRESHOLD for "Cooked" mode
893 **** n Number2Display Used by All and Raw mode. Otherwise ignored.
894 **** A All -- R and S options are ignored
895 **** R Raw -- S option is ignored
896 **** s Summary -- Modifies "Cooked" output only
897 **** Cooked (Default)
898 ****************************************************************************/
899 GatherStatistics (CustomCumulativeData);
900 if (CumulativeMode) {
901 ProcessCumulative (CustomCumulativeData);
902 } else if (AllMode) {
903 Status = DumpAllTrace (Number2Display, ExcludeMode);
904 if (Status == EFI_ABORTED) {
905 ShellStatus = SHELL_ABORTED;
906 goto Done;
907 }
908 } else if (RawMode) {
909 Status = DumpRawTrace (Number2Display, ExcludeMode);
910 if (Status == EFI_ABORTED) {
911 ShellStatus = SHELL_ABORTED;
912 goto Done;
913 }
914 } else {
915 // ------------- Begin Cooked Mode Processing
916 ProcessPhases ();
917 if ( !SummaryMode) {
918 Status = ProcessHandles (ExcludeMode);
919 if (Status == EFI_ABORTED) {
920 ShellStatus = SHELL_ABORTED;
921 goto Done;
922 }
923
924 Status = ProcessPeims ();
925 if (Status == EFI_ABORTED) {
926 ShellStatus = SHELL_ABORTED;
927 goto Done;
928 }
929
930 Status = ProcessGlobal ();
931 if (Status == EFI_ABORTED) {
932 ShellStatus = SHELL_ABORTED;
933 goto Done;
934 }
935
936 ProcessCumulative (NULL);
937 }
938 } // ------------- End of Cooked Mode Processing
939
940 if ( VerboseMode || SummaryMode) {
941 DumpStatistics ();
942 }
943
944 Done:
945 if (ParamPackage != NULL) {
946 ShellCommandLineFreeVarList (ParamPackage);
947 }
948
949 SHELL_FREE_NON_NULL (StringPtr);
950 if (CustomCumulativeData != NULL) {
951 SHELL_FREE_NON_NULL (CustomCumulativeData->Name);
952 }
953
954 SHELL_FREE_NON_NULL (CustomCumulativeData);
955
956 SHELL_FREE_NON_NULL (mMeasurementList);
957
958 SHELL_FREE_NON_NULL (mCacheHandleGuidTable);
959
960 mMeasurementNum = 0;
961 mCachePairCount = 0;
962 return ShellStatus;
963 }
964
965 /**
966 Retrieve HII package list from ImageHandle and publish to HII database.
967
968 @param ImageHandle The image handle of the process.
969
970 @return HII handle.
971 **/
972 EFI_HII_HANDLE
973 InitializeHiiPackage (
974 EFI_HANDLE ImageHandle
975 )
976 {
977 EFI_STATUS Status;
978 EFI_HII_PACKAGE_LIST_HEADER *PackageList;
979 EFI_HII_HANDLE HiiHandle;
980
981 //
982 // Retrieve HII package list from ImageHandle
983 //
984 Status = gBS->OpenProtocol (
985 ImageHandle,
986 &gEfiHiiPackageListProtocolGuid,
987 (VOID **)&PackageList,
988 ImageHandle,
989 NULL,
990 EFI_OPEN_PROTOCOL_GET_PROTOCOL
991 );
992 ASSERT_EFI_ERROR (Status);
993 if (EFI_ERROR (Status)) {
994 return NULL;
995 }
996
997 //
998 // Publish HII package list to HII Database.
999 //
1000 Status = gHiiDatabase->NewPackageList (
1001 gHiiDatabase,
1002 PackageList,
1003 NULL,
1004 &HiiHandle
1005 );
1006 ASSERT_EFI_ERROR (Status);
1007 if (EFI_ERROR (Status)) {
1008 return NULL;
1009 }
1010
1011 return HiiHandle;
1012 }