EFI_PERF_DATA_LIST * CreateDataNode ( IN EFI_HANDLE Handle, IN UINT16 *Token, IN UINT16 *Host ) /*++ Routine Description: Create a EFI_PERF_DATA_LIST data node. Arguments: Handle - Handle of gauge data Token - Token of gauge data Host - Host of gauge data Returns: Pointer to a data node created. --*/ { EFI_PERF_DATA_LIST *Node; // // Al\ a new image structure // Node = EfiLibAllocateZeroPool (sizeof (EFI_PERF_DATA_LIST)); if (Node != NULL) { Node->Signature = EFI_PERFORMANCE_DATA_SIGNATURE; Node->GaugeData.Handle = Handle; if (Token != NULL) { EfiStrCpy ((Node->GaugeData).Token, Token); } if (Host != NULL) { EfiStrCpy ((Node->GaugeData).Host, Host); } if (Handle != NULL) { GetNameFromHandle (Handle, Node->GaugeData.PdbFileName); } } return Node; }
/** Writes performance data of booting into the allocated memory. OS can process these records. @param Event The triggered event. @param Context Context for this event. **/ VOID EFIAPI WriteBootToOsPerformanceData ( IN EFI_EVENT Event, IN VOID *Context ) { EFI_STATUS Status; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_SIZE]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; UINTN VarSize; // // Record the performance data for End of BDS // PERF_END(NULL, "BDS", NULL, 0); // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { VarSize = sizeof (EFI_PHYSICAL_ADDRESS); Status = gRT->GetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, NULL, &VarSize, &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { // // Fail to get the variable, return. // return; } } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); return ; }
/** Gather and print Handle data. @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. @return Status from a call to gBS->LocateHandle(). **/ EFI_STATUS ProcessHandles( IN BOOLEAN ExcludeFlag ) { MEASUREMENT_RECORD Measurement; UINT64 ElapsedTime; UINT64 Duration; EFI_HANDLE *HandleBuffer; EFI_STRING StringPtr; UINTN Index; UINTN LogEntryKey; UINTN Count; UINTN Size; EFI_HANDLE TempHandle; EFI_STATUS Status; EFI_STRING StringPtrUnknown; StringPtrUnknown = HiiGetString (gHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); StringPtr = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_SECTION_DRIVERS), NULL); PrintToken( STRING_TOKEN (STR_DP_SECTION_HEADER), (StringPtr == NULL) ? StringPtrUnknown : StringPtr); FreePool (StringPtr); FreePool (StringPtrUnknown); Size = 0; HandleBuffer = &TempHandle; Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, &TempHandle); if (Status == EFI_BUFFER_TOO_SMALL) { HandleBuffer = AllocatePool (Size); ASSERT (HandleBuffer != NULL); if (HandleBuffer == NULL) { return Status; } Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleBuffer); } if (EFI_ERROR (Status)) { PrintToken (STRING_TOKEN (STR_DP_HANDLES_ERROR), Status); } else { #if DP_DEBUG == 2 Print (L"There are %,d Handles defined.\n", (Size / sizeof(HandleBuffer[0]))); #endif if (mShowId) { PrintToken (STRING_TOKEN (STR_DP_HANDLE_SECTION2) ); } else { PrintToken (STRING_TOKEN (STR_DP_HANDLE_SECTION) ); } PrintToken (STRING_TOKEN (STR_DP_DASHES) ); LogEntryKey = 0; Count = 0; while ((LogEntryKey = GetPerformanceMeasurementEx ( LogEntryKey, &Measurement.Handle, &Measurement.Token, &Measurement.Module, &Measurement.StartTimeStamp, &Measurement.EndTimeStamp, &Measurement.Identifier)) != 0) { Count++; Duration = GetDuration (&Measurement); ElapsedTime = DurationInMicroSeconds ( Duration ); if ((ElapsedTime < mInterestThreshold) || (Measurement.EndTimeStamp == 0) || (Measurement.Handle == NULL) || ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0)) ) { // Ignore "uninteresting" or excluded records continue; } mGaugeString[0] = 0; // Empty driver name by default AsciiStrToUnicodeStr (Measurement.Token, mUnicodeToken); // See if the Handle is in the HandleBuffer for (Index = 0; Index < (Size / sizeof(HandleBuffer[0])); Index++) { if (Measurement.Handle == HandleBuffer[Index]) { GetNameFromHandle (HandleBuffer[Index]); // Name is put into mGaugeString break; } } // Ensure that the argument strings are not too long. mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; mUnicodeToken[11] = 0; if (mGaugeString[0] != 0) { // Display the record if it has a valid handle. if (mShowId) { PrintToken ( STRING_TOKEN (STR_DP_HANDLE_VARS2), Count, // 1 based, Which measurement record is being printed Index + 1, // 1 based, Which handle is being printed mGaugeString, mUnicodeToken, ElapsedTime, Measurement.Identifier ); } else { PrintToken ( STRING_TOKEN (STR_DP_HANDLE_VARS), Count, // 1 based, Which measurement record is being printed Index + 1, // 1 based, Which handle is being printed mGaugeString, mUnicodeToken, ElapsedTime ); } } } } if (HandleBuffer != &TempHandle) { FreePool (HandleBuffer); } return Status; }
/** Allocates a block of memory and writes performance data of booting into it. OS can processing these record. **/ VOID WriteBootToOsPerformanceData ( VOID ) { EFI_STATUS Status; UINT32 AcpiLowMemoryLength; UINT32 LimitCount; EFI_HANDLE *Handles; UINTN NoHandles; CHAR8 GaugeString[PERF_TOKEN_LENGTH]; UINT8 *Ptr; UINT32 Index; UINT64 Ticker; UINT64 Freq; UINT32 Duration; UINTN LogEntryKey; CONST VOID *Handle; CONST CHAR8 *Token; CONST CHAR8 *Module; UINT64 StartTicker; UINT64 EndTicker; UINT64 StartValue; UINT64 EndValue; BOOLEAN CountUp; UINTN EntryIndex; UINTN NumPerfEntries; // // List of flags indicating PerfEntry contains DXE handle // BOOLEAN *PerfEntriesAsDxeHandle; // // Retrieve time stamp count as early as possible // Ticker = GetPerformanceCounter (); Freq = GetPerformanceCounterProperties (&StartValue, &EndValue); Freq = DivU64x32 (Freq, 1000); mPerfHeader.CpuFreq = Freq; // // Record BDS raw performance data // if (EndValue >= StartValue) { mPerfHeader.BDSRaw = Ticker - StartValue; CountUp = TRUE; } else { mPerfHeader.BDSRaw = StartValue - Ticker; CountUp = FALSE; } // // Put Detailed performance data into memory // Handles = NULL; Status = gBS->LocateHandleBuffer ( AllHandles, NULL, NULL, &NoHandles, &Handles ); if (EFI_ERROR (Status)) { return ; } AcpiLowMemoryLength = 0x4000; if (mAcpiLowMemoryBase == 0x0FFFFFFFF) { // // Allocate a block of memory that contain performance data to OS // Status = gBS->AllocatePages ( AllocateMaxAddress, EfiReservedMemoryType, EFI_SIZE_TO_PAGES (AcpiLowMemoryLength), &mAcpiLowMemoryBase ); if (EFI_ERROR (Status)) { FreePool (Handles); return ; } } Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER)); LimitCount = (AcpiLowMemoryLength - sizeof (PERF_HEADER)) / sizeof (PERF_DATA); NumPerfEntries = 0; LogEntryKey = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { NumPerfEntries++; } PerfEntriesAsDxeHandle = AllocateZeroPool (NumPerfEntries * sizeof (BOOLEAN)); ASSERT (PerfEntriesAsDxeHandle != NULL); // // Get DXE drivers performance // for (Index = 0; Index < NoHandles; Index++) { Ticker = 0; LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (Handle == Handles[Index] && !PerfEntriesAsDxeHandle[EntryIndex]) { PerfEntriesAsDxeHandle[EntryIndex] = TRUE; } EntryIndex++; if ((Handle == Handles[Index]) && (EndTicker != 0)) { if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker += CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); } } Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); if (Duration > 0) { GetNameFromHandle (Handles[Index], GaugeString); AsciiStrCpy (mPerfData.Token, GaugeString); mPerfData.Duration = Duration; CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } } // // Get inserted performance data // LogEntryKey = 0; EntryIndex = 0; while ((LogEntryKey = GetPerformanceMeasurement ( LogEntryKey, &Handle, &Token, &Module, &StartTicker, &EndTicker)) != 0) { if (!PerfEntriesAsDxeHandle[EntryIndex] && EndTicker != 0) { ZeroMem (&mPerfData, sizeof (PERF_DATA)); AsciiStrnCpy (mPerfData.Token, Token, PERF_TOKEN_LENGTH); if (StartTicker == 1) { StartTicker = StartValue; } if (EndTicker == 1) { EndTicker = StartValue; } Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker); mPerfData.Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq); CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA)); Ptr += sizeof (PERF_DATA); mPerfHeader.Count++; if (mPerfHeader.Count == LimitCount) { goto Done; } } EntryIndex++; } Done: FreePool (Handles); FreePool (PerfEntriesAsDxeHandle); mPerfHeader.Signiture = PERFORMANCE_SIGNATURE; // // Put performance data to Reserved memory // CopyMem ( (UINTN *) (UINTN) mAcpiLowMemoryBase, &mPerfHeader, sizeof (PERF_HEADER) ); gRT->SetVariable ( L"PerfDataMemAddr", &gPerformanceProtocolGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, sizeof (EFI_PHYSICAL_ADDRESS), &mAcpiLowMemoryBase ); return ; }
/** Gather and print ALL Trace Records. Displays all "interesting" Trace measurements in order.<BR> The number of records displayed is controlled by: - records with a duration less than mInterestThreshold microseconds are not displayed. - No more than Limit records are displayed. A Limit of zero will not limit the output. - If the ExcludeFlag is TRUE, records matching entries in the CumData array are not displayed. @pre The mInterestThreshold global variable is set to the shortest duration to be printed. The mGaugeString and mUnicodeToken global arrays are used for temporary string storage. They must not be in use by a calling function. @param[in] Limit The number of records to print. Zero is ALL. @param[in] ExcludeFlag TRUE to exclude individual Cumulative items from display. **/ VOID DumpAllTrace( IN UINTN Limit, IN BOOLEAN ExcludeFlag ) { MEASUREMENT_RECORD Measurement; UINT64 ElapsedTime; UINT64 Duration; const CHAR16 *IncFlag; UINTN LogEntryKey; UINTN Count; UINTN Index; UINTN TIndex; EFI_HANDLE *HandleBuffer; UINTN Size; EFI_HANDLE TempHandle; EFI_STATUS Status; EFI_STRING StringPtrUnknown; StringPtrUnknown = HiiGetString (gHiiHandle, STRING_TOKEN (STR_ALIT_UNKNOWN), NULL); IncFlag = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_SECTION_ALL), NULL); PrintToken( STRING_TOKEN (STR_DP_SECTION_HEADER), (IncFlag == NULL) ? StringPtrUnknown : IncFlag); FreePool (StringPtrUnknown); // Get Handle information // Size = 0; HandleBuffer = &TempHandle; Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, &TempHandle); if (Status == EFI_BUFFER_TOO_SMALL) { HandleBuffer = AllocatePool (Size); ASSERT (HandleBuffer != NULL); if (HandleBuffer == NULL) { return; } Status = gBS->LocateHandle (AllHandles, NULL, NULL, &Size, HandleBuffer); } if (EFI_ERROR (Status)) { PrintToken (STRING_TOKEN (STR_DP_HANDLES_ERROR), Status); } else { // We have successfully populated the HandleBuffer // Display ALL Measurement Records // Up to Limit lines displayed // Display only records with Elapsed times >= mInterestThreshold // Display driver names in Module field for records with Handles. // if (mShowId) { PrintToken (STRING_TOKEN (STR_DP_ALL_HEADR2) ); PrintToken (STRING_TOKEN (STR_DP_ALL_DASHES2) ); } else { PrintToken (STRING_TOKEN (STR_DP_ALL_HEADR) ); PrintToken (STRING_TOKEN (STR_DP_DASHES) ); } LogEntryKey = 0; Count = 0; Index = 0; while ( WITHIN_LIMIT(Count, Limit) && ((LogEntryKey = GetPerformanceMeasurementEx ( LogEntryKey, &Measurement.Handle, &Measurement.Token, &Measurement.Module, &Measurement.StartTimeStamp, &Measurement.EndTimeStamp, &Measurement.Identifier)) != 0) ) { ++Index; // Count every record. First record is 1. ElapsedTime = 0; SafeFreePool ((VOID *) IncFlag); if (Measurement.EndTimeStamp != 0) { Duration = GetDuration (&Measurement); ElapsedTime = DurationInMicroSeconds ( Duration ); IncFlag = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_COMPLETE), NULL); } else { IncFlag = HiiGetString (gHiiHandle, STRING_TOKEN (STR_DP_INCOMPLETE), NULL); // Mark incomplete records } if (((Measurement.EndTimeStamp != 0) && (ElapsedTime < mInterestThreshold)) || ((ExcludeFlag) && (GetCumulativeItem(&Measurement) >= 0)) ) { // Ignore "uninteresting" or excluded records continue; } ++Count; // Count the number of records printed // If Handle is non-zero, see if we can determine a name for the driver AsciiStrToUnicodeStr (Measurement.Module, mGaugeString); // Use Module by default AsciiStrToUnicodeStr (Measurement.Token, mUnicodeToken); if (Measurement.Handle != NULL) { // See if the Handle is in the HandleBuffer for (TIndex = 0; TIndex < (Size / sizeof(HandleBuffer[0])); TIndex++) { if (Measurement.Handle == HandleBuffer[TIndex]) { GetNameFromHandle (HandleBuffer[TIndex]); break; } } } if (AsciiStrnCmp (Measurement.Token, ALit_PEIM, PERF_TOKEN_LENGTH) == 0) { UnicodeSPrint (mGaugeString, sizeof (mGaugeString), L"%g", Measurement.Handle); } // Ensure that the argument strings are not too long. mGaugeString[DP_GAUGE_STRING_LENGTH] = 0; mUnicodeToken[13] = 0; if (mShowId) { PrintToken( STRING_TOKEN (STR_DP_ALL_VARS2), Index, // 1 based, Which measurement record is being printed IncFlag, Measurement.Handle, mGaugeString, mUnicodeToken, ElapsedTime, Measurement.Identifier ); } else { PrintToken( STRING_TOKEN (STR_DP_ALL_VARS), Index, // 1 based, Which measurement record is being printed IncFlag, Measurement.Handle, mGaugeString, mUnicodeToken, ElapsedTime ); } } } if (HandleBuffer != &TempHandle) { FreePool (HandleBuffer); } SafeFreePool ((VOID *) IncFlag); }