alder_lake_bios/Insyde/InsydeSetupPkg/Drivers/H2ODisplayEngineLocalMetroDxe/MetroPerfMeasure.c

265 lines
8.5 KiB
C

/** @file
Performance measure related functions
;******************************************************************************
;* Copyright (c) 2016, Insyde Software Corp. All Rights Reserved.
;*
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
;* transmit, broadcast, present, recite, release, license or otherwise exploit
;* any part of this publication in any form, by any means, without the prior
;* written permission of Insyde Software Corporation.
;*
;******************************************************************************
*/
#include "MetroPerfMeasure.h"
typedef struct _METRO_PERFORMANCE_PRIVATE_DATA {
UINT64 StartTick[PERF_INFO_NUM];
UINT64 TotalDiffTick[PERF_INFO_NUM];
UINT32 Count[PERF_INFO_NUM];
CHAR16 *UnitStr;
UINT32 UnitDivisor;
METRO_PERFORMANCE_MEASURE PerfMeasure;
} METRO_PERFORMANCE_PRIVATE_DATA;
METRO_PERFORMANCE_PRIVATE_DATA *mPerfPrivateData = NULL;
typedef struct _METRO_PERFORMANCE_MEASURE_UNIT_INFO {
PERFORMANCE_MEASURE_UINT Unit;
UINT32 Divisor;
CHAR16 *String;
} METRO_PERFORMANCE_MEASURE_UNIT_INFO;
METRO_PERFORMANCE_MEASURE_UNIT_INFO mUnitInfo[] = {{MeasureInMilliSec, 1000000000, L"MilliSec"},
{MeasureInMicroSec, 1000000 , L"MicroSec"},
{MeasureInNanoSec , 1000 , L"NanoSec" }
};
/**
Converts elapsed ticks of performance counter to time in picoseconds.
This function converts the elapsed ticks of running performance counter to time value in unit of picoseconds.
@param[in] Ticks The number of elapsed ticks of running performance counter.
@return The elapsed time in picoseconds.
**/
STATIC
UINT64
InternalGetTimeInPicoSecond (
IN UINT64 Ticks
)
{
STATIC UINT64 Frequency = 0;
UINT64 PicoSeconds;
UINT64 Remainder;
INTN Shift;
if (Frequency == 0) {
Frequency = GetPerformanceCounterProperties (NULL, NULL);
}
//
// Ticks
// Time = --------- x 1,000,000,000
// Frequency
//
PicoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
//
// Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
// Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
// i.e. highest bit set in Remainder should <= 33.
//
Shift = MAX (0, HighBitSet64 (Remainder) - 33);
Remainder = RShiftU64 (Remainder, (UINTN) Shift);
Frequency = RShiftU64 (Frequency, (UINTN) Shift);
PicoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
return PicoSeconds;
}
/**
Start performance measure for record index.
@param[in] RecordIndex Record index
@param[in] ValidFlag Flag to determine if start performance measure
**/
VOID
EFIAPI
PerfMeasureStart (
IN UINTN RecordIndex,
IN BOOLEAN ValidFlag
)
{
ASSERT (RecordIndex < PERF_INFO_NUM);
if (RecordIndex >= PERF_INFO_NUM || !ValidFlag) {
return;
}
mPerfPrivateData->StartTick[RecordIndex] = GetPerformanceCounter();
}
/**
End performance measure for record index.
@param[in] RecordIndex Record index
@param[in] ValidFlag Flag to determine if end performance measure
@param[in] StartString Pointer to start string for debug
@param[in] EndString Pointer to end string for debug
@return The differenc time or ticks based on parformance measure private data.
**/
UINT64
EFIAPI
PerfMeasureEnd (
IN UINTN RecordIndex,
IN BOOLEAN ValidFlag,
IN CHAR16 *StartString,
IN CHAR16 *EndString
)
{
UINT64 EndTick;
UINT64 DiffTick;
UINT64 DiffTime;
METRO_PERFORMANCE_MEASURE *PerfMeasure;
ASSERT (RecordIndex < PERF_INFO_NUM);
if (RecordIndex >= PERF_INFO_NUM || !ValidFlag) {
return 0;
}
EndTick = GetPerformanceCounter();
DiffTick = EndTick - mPerfPrivateData->StartTick[RecordIndex];
mPerfPrivateData->TotalDiffTick[RecordIndex] += DiffTick;
mPerfPrivateData->Count[RecordIndex]++;
PerfMeasure = &mPerfPrivateData->PerfMeasure;
if (PerfMeasure->PrintTickDifference) {
if (PerfMeasure->IsPrintEnable) {
DEBUG ((EFI_D_ERROR, "%s, Ticks = %08ld %s", StartString, DiffTick, EndString));
}
return DiffTick;
} else {
DiffTime = DivU64x32 (InternalGetTimeInPicoSecond (DiffTick), mPerfPrivateData->UnitDivisor);
if (PerfMeasure->IsPrintEnable) {
DEBUG ((EFI_D_ERROR, "%s, %s = %08ld %s", StartString, mPerfPrivateData->UnitStr, DiffTime, EndString));
}
return DiffTime;
}
}
/**
Get total difference for record index.
@param[in] RecordIndex Record index
@param[in] ValidFlag Flag to determine if end performance measure
@param[in] ClearRecord Flag to determine if clear record
@param[in] StartString Pointer to start string for debug
@param[in] EndString Pointer to end string for debug
@return The total differenc time or ticks based on parformance measure private data.
**/
UINT64
EFIAPI
PerfMeasureTotal (
IN UINTN RecordIndex,
IN BOOLEAN ValidFlag,
IN BOOLEAN ClearRecord,
IN CHAR16 *StartString,
IN CHAR16 *EndString
)
{
UINT64 Difference;
METRO_PERFORMANCE_MEASURE *PerfMeasure;
ASSERT (RecordIndex < PERF_INFO_NUM);
if (RecordIndex >= PERF_INFO_NUM || !ValidFlag) {
return 0;
}
PerfMeasure = &mPerfPrivateData->PerfMeasure;
if (PerfMeasure->PrintTickDifference) {
Difference = mPerfPrivateData->TotalDiffTick[RecordIndex];
if (PerfMeasure->IsPrintEnable) {
DEBUG ((EFI_D_ERROR, "%s, Ticks = %08ld %s", StartString, Difference, EndString));
}
} else {
Difference = DivU64x32 (InternalGetTimeInPicoSecond (mPerfPrivateData->TotalDiffTick[RecordIndex]), mPerfPrivateData->UnitDivisor);
if (PerfMeasure->IsPrintEnable) {
if (mPerfPrivateData->Count[RecordIndex] == 0) {
DEBUG ((EFI_D_ERROR, "%s, %s = %08ld %s", StartString, mPerfPrivateData->UnitStr, Difference, EndString));
} else {
DEBUG ((EFI_D_ERROR, "%s, %s = %08ld (Count = %d, Avg = %d)\n", StartString, mPerfPrivateData->UnitStr, Difference, mPerfPrivateData->Count[RecordIndex], DivU64x32 (Difference, mPerfPrivateData->Count[RecordIndex])));
}
}
}
if (ClearRecord) {
mPerfPrivateData->TotalDiffTick[RecordIndex] = 0;
mPerfPrivateData->Count[RecordIndex] = 0;
}
return Difference;
}
/**
Change measure unit.
@param[in] MeasureUnit Measure unit
@retval EFI_SUCCESS Change measure unit successfully
@retval EFI_UNSUPPORTED Input unit is not found
**/
EFI_STATUS
EFIAPI
PerfMeasureChangeUnit (
IN PERFORMANCE_MEASURE_UINT MeasureUnit
)
{
UINTN Index;
for (Index = 0; Index < sizeof (mUnitInfo) / sizeof (METRO_PERFORMANCE_MEASURE_UNIT_INFO); Index++) {
if (mUnitInfo[Index].Unit == MeasureUnit) {
mPerfPrivateData->UnitStr = mUnitInfo[Index].String;
mPerfPrivateData->UnitDivisor = mUnitInfo[Index].Divisor;
return EFI_SUCCESS;
}
}
return EFI_UNSUPPORTED;
}
/**
Get performance measure instance
@return The pointer of performance measure instance or NULL if allocate memory failed.
**/
METRO_PERFORMANCE_MEASURE *
EFIAPI
GetPerfMeasure (
VOID
)
{
METRO_PERFORMANCE_MEASURE *PerfMeasure;
if (mPerfPrivateData != NULL) {
return &mPerfPrivateData->PerfMeasure;
}
mPerfPrivateData = AllocateZeroPool (sizeof (METRO_PERFORMANCE_PRIVATE_DATA));
if (mPerfPrivateData == NULL) {
return NULL;
}
PerfMeasure = &mPerfPrivateData->PerfMeasure;
PerfMeasure->IsPrintEnable = FALSE;
PerfMeasure->PrintTickDifference = FALSE;
PerfMeasure->Start = PerfMeasureStart;
PerfMeasure->End = PerfMeasureEnd;
PerfMeasure->Total = PerfMeasureTotal;
PerfMeasure->ChangeUnit = PerfMeasureChangeUnit;
PerfMeasureChangeUnit (MeasureInMicroSec);
return PerfMeasure;
}