* TimerTickDiffLib for MdePkg?
@ 2017-08-16 11:45 Laszlo Ersek
2017-08-16 15:41 ` Kinney, Michael D
0 siblings, 1 reply; 6+ messages in thread
From: Laszlo Ersek @ 2017-08-16 11:45 UTC (permalink / raw)
To: Michael Kinney, Gao, Liming; +Cc: edk2-devel-01
Hi,
edk2 code frequently needs to calculate a time difference (in nano-,
micro-, or milliseconds) between two timer tick values retrieved with
TimerLib's GetPerformanceCounter() call. For performance measurements,
PERF_START() and friends can be used, but in many contexts the time
difference is needed for lower-level reasons.
Such users can be enumerated by grepping for
GetPerformanceCounterProperties() call sites that pass in non-NULL
parameters -- this is needed for interpreting wrap-arounds in tick
values (direction and boundaries). I'm seeing a whole lot of such call
sites. (And some call sites don't handle both directions of counting.)
I've written a very small library for centralizing this. While I'm not
suggesting that existent code be rebased (although I'm also not advising
against it), I think this library would be convenient for new code.
I don't think TimerLib should be extended with the new (suggested) APIs.
There's a huge number of TimerLib instances (21 in my count), and
replicating the implementation of the new APIs -- which are totally
platform independent -- would defeat the whole exercise (which is to
prevent code duplication).
The library is currently for OvmfPkg only (in my local tree). I'm
pasting the patch below. If there is interest, I could rework it for
MdePkg.
Thanks
Laszlo
> commit f1963c7b1705c7e46ce369802d8c15f943a114d6
> Author: Laszlo Ersek <lersek@redhat.com>
> Date: Tue Aug 8 22:46:47 2017 +0200
>
> OvmfPkg: add TimerTickDiffLib
>
> Contributed-under: TianoCore Contribution Agreement 1.1
> Signed-off-by: Laszlo Ersek <lersek@redhat.com>
>
> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec
> index 6a4c15c7917a..53a0a34d326d 100644
> --- a/OvmfPkg/OvmfPkg.dec
> +++ b/OvmfPkg/OvmfPkg.dec
> @@ -60,6 +60,10 @@ [LibraryClasses]
> #
> HexDumpLib|Include/Library/HexDumpLib.h
>
> + ## @libraryclass Timer tick difference functions, to be used with TimerLib.
> + #
> + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h
> +
> [Guids]
> gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}}
> gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}}
> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc
> index 5b0461ff46b1..17f1db43f57d 100644
> --- a/OvmfPkg/OvmfPkgIa32.dsc
> +++ b/OvmfPkg/OvmfPkgIa32.dsc
> @@ -97,6 +97,7 @@ [SkuIds]
> #
> ################################################################################
> [LibraryClasses]
> + TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf
> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf
> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc b/OvmfPkg/OvmfPkgIa32X64.dsc
> index 0ce3cbd3ebd0..924e17824760 100644
> --- a/OvmfPkg/OvmfPkgIa32X64.dsc
> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc
> @@ -102,6 +102,7 @@ [SkuIds]
> #
> ################################################################################
> [LibraryClasses]
> + TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf
> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf
> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc
> index e7bdf8711b0f..d22384a26768 100644
> --- a/OvmfPkg/OvmfPkgX64.dsc
> +++ b/OvmfPkg/OvmfPkgX64.dsc
> @@ -102,6 +102,7 @@ [SkuIds]
> #
> ################################################################################
> [LibraryClasses]
> + TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf
> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf
> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf
> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf
> diff --git a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf
> new file mode 100644
> index 000000000000..4d464565eb2f
> --- /dev/null
> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf
> @@ -0,0 +1,31 @@
> +## @file
> +# Timer tick difference functions, to be used with TimerLib.
> +#
> +# Copyright (C) 2017, Red Hat, Inc.
> +#
> +# This program and the accompanying materials are licensed and made available
> +# under the terms and conditions of the BSD License which accompanies this
> +# distribution. The full text of the license may be found at
> +# http://opensource.org/licenses/bsd-license.php
> +#
> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +##
> +
> +[Defines]
> + INF_VERSION = 1.26
> + BASE_NAME = TimerTickDiffLib
> + FILE_GUID = F1998AED-934F-4C96-AEFB-29C39FA62434
> + MODULE_TYPE = BASE
> + VERSION_STRING = 1.0
> + LIBRARY_CLASS = TimerTickDiffLib
> +
> +[Sources]
> + TimerTickDiffLib.c
> +
> +[Packages]
> + MdePkg/MdePkg.dec
> +
> +[LibraryClasses]
> + BaseLib
> + TimerLib
> diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h b/OvmfPkg/Include/Library/TimerTickDiffLib.h
> new file mode 100644
> index 000000000000..40052e11b6ed
> --- /dev/null
> +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h
> @@ -0,0 +1,109 @@
> +/** @file
> + Timer tick difference functions, to be used with TimerLib.
> +
> + Copyright (C) 2017, Red Hat, Inc.
> +
> + This program and the accompanying materials are licensed and made available
> + under the terms and conditions of the BSD License which accompanies this
> + distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +**/
> +
> +#ifndef __TIMER_TICK_DIFF_LIB_H__
> +#define __TIMER_TICK_DIFF_LIB_H__
> +
> +#include <Base.h>
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of ticks elapsed between them, such that the difference can be
> + passed to TimerLib's GetTimeInNanoSecond().
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of ticks corresponding to the conceptual difference
> + (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetTickDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + );
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of nanoseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of nanoseconds corresponding to the conceptual difference
> + (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetNanoSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + );
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of microseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of microseconds corresponding to the conceptual
> + difference (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetMicroSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + );
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of milliseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of milliseconds corresponding to the conceptual
> + difference (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetMilliSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + );
> +
> +#endif
> diff --git a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c
> new file mode 100644
> index 000000000000..03ecae8200aa
> --- /dev/null
> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c
> @@ -0,0 +1,178 @@
> +/** @file
> + Timer tick difference functions, to be used with TimerLib.
> +
> + Copyright (C) 2017, Red Hat, Inc.
> +
> + This program and the accompanying materials are licensed and made available
> + under the terms and conditions of the BSD License which accompanies this
> + distribution. The full text of the license may be found at
> + http://opensource.org/licenses/bsd-license.php
> +
> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, WITHOUT
> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
> +**/
> +
> +#include <Library/BaseLib.h>
> +#include <Library/TimerLib.h>
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of ticks elapsed between them, such that the difference can be
> + passed to TimerLib's GetTimeInNanoSecond().
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of ticks corresponding to the conceptual difference
> + (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetTickDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + )
> +{
> + UINT64 StartValue;
> + UINT64 EndValue;
> + UINT64 TickDifference;
> +
> + GetPerformanceCounterProperties (&StartValue, &EndValue);
> +
> + if (StartValue < EndValue) {
> + //
> + // The performance counter counts up.
> + //
> + if (PerfCounterStart < PerfCounterStop) {
> + //
> + // The counter didn't wrap around.
> + //
> + TickDifference = PerfCounterStop - PerfCounterStart;
> + } else {
> + //
> + // The counter wrapped around.
> + //
> + TickDifference = (EndValue - PerfCounterStart) +
> + (PerfCounterStop - StartValue);
> + }
> + } else {
> + //
> + // The performance counter counts down.
> + //
> + if (PerfCounterStart < PerfCounterStop) {
> + //
> + // The counter wrapped around.
> + //
> + TickDifference = (PerfCounterStart - EndValue) +
> + (StartValue - PerfCounterStop);
> + } else {
> + //
> + // The counter didn't wrap around.
> + //
> + TickDifference = PerfCounterStart - PerfCounterStop;
> + }
> + }
> +
> + return TickDifference;
> +}
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of nanoseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of nanoseconds corresponding to the conceptual difference
> + (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetNanoSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + )
> +{
> + UINT64 TickDifference;
> + UINT64 NanoSecondDifference;
> +
> + TickDifference = GetTickDifference (PerfCounterStart, PerfCounterStop);
> + NanoSecondDifference = GetTimeInNanoSecond (TickDifference);
> + return NanoSecondDifference;
> +}
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of microseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of microseconds corresponding to the conceptual
> + difference (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetMicroSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + )
> +{
> + UINT64 NanoSecondDifference;
> + UINT64 MicroSecondDifference;
> +
> + NanoSecondDifference = GetNanoSecondDifference (
> + PerfCounterStart,
> + PerfCounterStop
> + );
> + MicroSecondDifference = DivU64x32 (NanoSecondDifference, 1000);
> + return MicroSecondDifference;
> +}
> +
> +/**
> + From two values retrieved with TimerLib's GetPerformanceCounter(), calculate
> + the number of milliseconds elapsed between them.
> +
> + The function cannot handle multiple wrap-arounds of the performance counter.
> +
> + @param[in] PerfCounterStart The value returned by GetPerformanceCounter(),
> + called earlier in wall clock time.
> +
> + @param[in] PerfCounterStop The value returned by GetPerformanceCounter(),
> + called later in wall clock time.
> +
> + @retval The number of milliseconds corresponding to the conceptual
> + difference (PerfCounterStop-PerfCounterStart).
> +**/
> +UINT64
> +EFIAPI
> +GetMilliSecondDifference (
> + IN UINT64 PerfCounterStart,
> + IN UINT64 PerfCounterStop
> + )
> +{
> + UINT64 NanoSecondDifference;
> + UINT64 MilliSecondDifference;
> +
> + NanoSecondDifference = GetNanoSecondDifference (
> + PerfCounterStart,
> + PerfCounterStop
> + );
> + MilliSecondDifference = DivU64x32 (NanoSecondDifference, 1000 * 1000);
> + return MilliSecondDifference;
> +}
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: TimerTickDiffLib for MdePkg? 2017-08-16 11:45 TimerTickDiffLib for MdePkg? Laszlo Ersek @ 2017-08-16 15:41 ` Kinney, Michael D 2017-08-16 16:08 ` Laszlo Ersek 0 siblings, 1 reply; 6+ messages in thread From: Kinney, Michael D @ 2017-08-16 15:41 UTC (permalink / raw) To: Laszlo Ersek, Gao, Liming, Kinney, Michael D; +Cc: edk2-devel-01 Laszlo, The TimerLib already has the following API. /** Converts elapsed ticks of performance counter to time in nanoseconds. This function converts the elapsed ticks of running performance counter to time value in unit of nanoseconds. @param Ticks The number of elapsed ticks of running performance counter. @return The elapsed time in nanoseconds. **/ UINT64 EFIAPI GetTimeInNanoSecond ( IN UINT64 Ticks ); I think a couple macros on top of this API could provide the microsecond and millisecond units. Mike > -----Original Message----- > From: Laszlo Ersek [mailto:lersek@redhat.com] > Sent: Wednesday, August 16, 2017 4:46 AM > To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming > <liming.gao@intel.com> > Cc: edk2-devel-01 <edk2-devel@lists.01.org> > Subject: TimerTickDiffLib for MdePkg? > > Hi, > > edk2 code frequently needs to calculate a time difference (in > nano-, > micro-, or milliseconds) between two timer tick values retrieved > with > TimerLib's GetPerformanceCounter() call. For performance > measurements, > PERF_START() and friends can be used, but in many contexts the > time > difference is needed for lower-level reasons. > > Such users can be enumerated by grepping for > GetPerformanceCounterProperties() call sites that pass in non- > NULL > parameters -- this is needed for interpreting wrap-arounds in > tick > values (direction and boundaries). I'm seeing a whole lot of > such call > sites. (And some call sites don't handle both directions of > counting.) > > I've written a very small library for centralizing this. While > I'm not > suggesting that existent code be rebased (although I'm also not > advising > against it), I think this library would be convenient for new > code. > > I don't think TimerLib should be extended with the new > (suggested) APIs. > There's a huge number of TimerLib instances (21 in my count), > and > replicating the implementation of the new APIs -- which are > totally > platform independent -- would defeat the whole exercise (which > is to > prevent code duplication). > > The library is currently for OvmfPkg only (in my local tree). > I'm > pasting the patch below. If there is interest, I could rework it > for > MdePkg. > > Thanks > Laszlo > > > commit f1963c7b1705c7e46ce369802d8c15f943a114d6 > > Author: Laszlo Ersek <lersek@redhat.com> > > Date: Tue Aug 8 22:46:47 2017 +0200 > > > > OvmfPkg: add TimerTickDiffLib > > > > Contributed-under: TianoCore Contribution Agreement 1.1 > > Signed-off-by: Laszlo Ersek <lersek@redhat.com> > > > > diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec > > index 6a4c15c7917a..53a0a34d326d 100644 > > --- a/OvmfPkg/OvmfPkg.dec > > +++ b/OvmfPkg/OvmfPkg.dec > > @@ -60,6 +60,10 @@ [LibraryClasses] > > # > > HexDumpLib|Include/Library/HexDumpLib.h > > > > + ## @libraryclass Timer tick difference functions, to be > used with TimerLib. > > + # > > + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h > > + > > [Guids] > > gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, > 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} > > gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, > 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} > > diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc > > index 5b0461ff46b1..17f1db43f57d 100644 > > --- a/OvmfPkg/OvmfPkgIa32.dsc > > +++ b/OvmfPkg/OvmfPkgIa32.dsc > > @@ -97,6 +97,7 @@ [SkuIds] > > # > > > ################################################################ > ################ > > [LibraryClasses] > > + > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > ib.inf > > HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > > PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > > diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc > b/OvmfPkg/OvmfPkgIa32X64.dsc > > index 0ce3cbd3ebd0..924e17824760 100644 > > --- a/OvmfPkg/OvmfPkgIa32X64.dsc > > +++ b/OvmfPkg/OvmfPkgIa32X64.dsc > > @@ -102,6 +102,7 @@ [SkuIds] > > # > > > ################################################################ > ################ > > [LibraryClasses] > > + > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > ib.inf > > HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > > PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > > diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc > > index e7bdf8711b0f..d22384a26768 100644 > > --- a/OvmfPkg/OvmfPkgX64.dsc > > +++ b/OvmfPkg/OvmfPkgX64.dsc > > @@ -102,6 +102,7 @@ [SkuIds] > > # > > > ################################################################ > ################ > > [LibraryClasses] > > + > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > ib.inf > > HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > > PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > > diff --git > a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > > new file mode 100644 > > index 000000000000..4d464565eb2f > > --- /dev/null > > +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > > @@ -0,0 +1,31 @@ > > +## @file > > +# Timer tick difference functions, to be used with TimerLib. > > +# > > +# Copyright (C) 2017, Red Hat, Inc. > > +# > > +# This program and the accompanying materials are licensed > and made available > > +# under the terms and conditions of the BSD License which > accompanies this > > +# distribution. The full text of the license may be found at > > +# http://opensource.org/licenses/bsd-license.php > > +# > > +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS > IS" BASIS, WITHOUT > > +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > OR IMPLIED. > > +## > > + > > +[Defines] > > + INF_VERSION = 1.26 > > + BASE_NAME = TimerTickDiffLib > > + FILE_GUID = F1998AED-934F-4C96-AEFB- > 29C39FA62434 > > + MODULE_TYPE = BASE > > + VERSION_STRING = 1.0 > > + LIBRARY_CLASS = TimerTickDiffLib > > + > > +[Sources] > > + TimerTickDiffLib.c > > + > > +[Packages] > > + MdePkg/MdePkg.dec > > + > > +[LibraryClasses] > > + BaseLib > > + TimerLib > > diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h > b/OvmfPkg/Include/Library/TimerTickDiffLib.h > > new file mode 100644 > > index 000000000000..40052e11b6ed > > --- /dev/null > > +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h > > @@ -0,0 +1,109 @@ > > +/** @file > > + Timer tick difference functions, to be used with TimerLib. > > + > > + Copyright (C) 2017, Red Hat, Inc. > > + > > + This program and the accompanying materials are licensed > and made available > > + under the terms and conditions of the BSD License which > accompanies this > > + distribution. The full text of the license may be found at > > + http://opensource.org/licenses/bsd-license.php > > + > > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS > IS" BASIS, WITHOUT > > + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > OR IMPLIED. > > +**/ > > + > > +#ifndef __TIMER_TICK_DIFF_LIB_H__ > > +#define __TIMER_TICK_DIFF_LIB_H__ > > + > > +#include <Base.h> > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of ticks elapsed between them, such that the > difference can be > > + passed to TimerLib's GetTimeInNanoSecond(). > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of ticks corresponding to the > conceptual difference > > + (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetTickDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ); > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of nanoseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of nanoseconds corresponding to the > conceptual difference > > + (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetNanoSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ); > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of microseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of microseconds corresponding to the > conceptual > > + difference (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetMicroSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ); > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of milliseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of milliseconds corresponding to the > conceptual > > + difference (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetMilliSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ); > > + > > +#endif > > diff --git > a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > > new file mode 100644 > > index 000000000000..03ecae8200aa > > --- /dev/null > > +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > > @@ -0,0 +1,178 @@ > > +/** @file > > + Timer tick difference functions, to be used with TimerLib. > > + > > + Copyright (C) 2017, Red Hat, Inc. > > + > > + This program and the accompanying materials are licensed > and made available > > + under the terms and conditions of the BSD License which > accompanies this > > + distribution. The full text of the license may be found at > > + http://opensource.org/licenses/bsd-license.php > > + > > + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS > IS" BASIS, WITHOUT > > + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > OR IMPLIED. > > +**/ > > + > > +#include <Library/BaseLib.h> > > +#include <Library/TimerLib.h> > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of ticks elapsed between them, such that the > difference can be > > + passed to TimerLib's GetTimeInNanoSecond(). > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of ticks corresponding to the > conceptual difference > > + (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetTickDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ) > > +{ > > + UINT64 StartValue; > > + UINT64 EndValue; > > + UINT64 TickDifference; > > + > > + GetPerformanceCounterProperties (&StartValue, &EndValue); > > + > > + if (StartValue < EndValue) { > > + // > > + // The performance counter counts up. > > + // > > + if (PerfCounterStart < PerfCounterStop) { > > + // > > + // The counter didn't wrap around. > > + // > > + TickDifference = PerfCounterStop - PerfCounterStart; > > + } else { > > + // > > + // The counter wrapped around. > > + // > > + TickDifference = (EndValue - PerfCounterStart) + > > + (PerfCounterStop - StartValue); > > + } > > + } else { > > + // > > + // The performance counter counts down. > > + // > > + if (PerfCounterStart < PerfCounterStop) { > > + // > > + // The counter wrapped around. > > + // > > + TickDifference = (PerfCounterStart - EndValue) + > > + (StartValue - PerfCounterStop); > > + } else { > > + // > > + // The counter didn't wrap around. > > + // > > + TickDifference = PerfCounterStart - PerfCounterStop; > > + } > > + } > > + > > + return TickDifference; > > +} > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of nanoseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of nanoseconds corresponding to the > conceptual difference > > + (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetNanoSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ) > > +{ > > + UINT64 TickDifference; > > + UINT64 NanoSecondDifference; > > + > > + TickDifference = GetTickDifference (PerfCounterStart, > PerfCounterStop); > > + NanoSecondDifference = GetTimeInNanoSecond > (TickDifference); > > + return NanoSecondDifference; > > +} > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of microseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of microseconds corresponding to the > conceptual > > + difference (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetMicroSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ) > > +{ > > + UINT64 NanoSecondDifference; > > + UINT64 MicroSecondDifference; > > + > > + NanoSecondDifference = GetNanoSecondDifference ( > > + PerfCounterStart, > > + PerfCounterStop > > + ); > > + MicroSecondDifference = DivU64x32 (NanoSecondDifference, > 1000); > > + return MicroSecondDifference; > > +} > > + > > +/** > > + From two values retrieved with TimerLib's > GetPerformanceCounter(), calculate > > + the number of milliseconds elapsed between them. > > + > > + The function cannot handle multiple wrap-arounds of the > performance counter. > > + > > + @param[in] PerfCounterStart The value returned by > GetPerformanceCounter(), > > + called earlier in wall clock > time. > > + > > + @param[in] PerfCounterStop The value returned by > GetPerformanceCounter(), > > + called later in wall clock > time. > > + > > + @retval The number of milliseconds corresponding to the > conceptual > > + difference (PerfCounterStop-PerfCounterStart). > > +**/ > > +UINT64 > > +EFIAPI > > +GetMilliSecondDifference ( > > + IN UINT64 PerfCounterStart, > > + IN UINT64 PerfCounterStop > > + ) > > +{ > > + UINT64 NanoSecondDifference; > > + UINT64 MilliSecondDifference; > > + > > + NanoSecondDifference = GetNanoSecondDifference ( > > + PerfCounterStart, > > + PerfCounterStop > > + ); > > + MilliSecondDifference = DivU64x32 (NanoSecondDifference, > 1000 * 1000); > > + return MilliSecondDifference; > > +} ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: TimerTickDiffLib for MdePkg? 2017-08-16 15:41 ` Kinney, Michael D @ 2017-08-16 16:08 ` Laszlo Ersek 2017-08-16 18:01 ` Kinney, Michael D 0 siblings, 1 reply; 6+ messages in thread From: Laszlo Ersek @ 2017-08-16 16:08 UTC (permalink / raw) To: Kinney, Michael D, Gao, Liming; +Cc: edk2-devel-01 On 08/16/17 17:41, Kinney, Michael D wrote: > Laszlo, > > The TimerLib already has the following API. > > /** > Converts elapsed ticks of performance counter to time in nanoseconds. > > This function converts the elapsed ticks of running performance counter to > time value in unit of nanoseconds. > > @param Ticks The number of elapsed ticks of running performance counter. > > @return The elapsed time in nanoseconds. > > **/ > UINT64 > EFIAPI > GetTimeInNanoSecond ( > IN UINT64 Ticks > ); > > I think a couple macros on top of this API could provide the microsecond > and millisecond units. I'm aware of GetTimeInNanoSecond(), and I agree that some macros on top would be sufficient for providing usec and msec wrappers. However, such wrappers are not the main point of this library. The main difficulty with using GetTimeInNanoSecond() is that the caller has to calculate the "Ticks" parameter. In theory, this is a simple difference, such as: // // fetch the start tick // PerformanceCounterStart = GetPerformanceCounter (); // // do some work, then fetch the stop tick // PerformanceCounterStop = GetPerformanceCounter (); // // calculate tick difference // Ticks = PerformanceCounterStop - PerformanceCounterStart; // // get elapsed time // NanoSeconds = GetTimeInNanoSecond (Ticks); However, the Ticks parameter cannot be calculated as naively as written above, for two reasons: - The performance counter can wrap around while doing the work. - The performance counter can be counting down as time progresses. Therefore the simple subtraction for Ticks has to be replaced every time with an elaborate four-branched check; for every variation of { counts up, counts down } x { wrapped around, did not wrap around } Additionally, in order to determine the counting direction, and the boundaries that have to be considered in case of wrap-around, GetPerformanceCounterProperties() must be called first. Extracting this logic is the main point of the library -- please see the GetTickDifference() function. The rest is just convenience fluff. Thanks Laszlo >> -----Original Message----- >> From: Laszlo Ersek [mailto:lersek@redhat.com] >> Sent: Wednesday, August 16, 2017 4:46 AM >> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming >> <liming.gao@intel.com> >> Cc: edk2-devel-01 <edk2-devel@lists.01.org> >> Subject: TimerTickDiffLib for MdePkg? >> >> Hi, >> >> edk2 code frequently needs to calculate a time difference (in >> nano-, >> micro-, or milliseconds) between two timer tick values retrieved >> with >> TimerLib's GetPerformanceCounter() call. For performance >> measurements, >> PERF_START() and friends can be used, but in many contexts the >> time >> difference is needed for lower-level reasons. >> >> Such users can be enumerated by grepping for >> GetPerformanceCounterProperties() call sites that pass in non- >> NULL >> parameters -- this is needed for interpreting wrap-arounds in >> tick >> values (direction and boundaries). I'm seeing a whole lot of >> such call >> sites. (And some call sites don't handle both directions of >> counting.) >> >> I've written a very small library for centralizing this. While >> I'm not >> suggesting that existent code be rebased (although I'm also not >> advising >> against it), I think this library would be convenient for new >> code. >> >> I don't think TimerLib should be extended with the new >> (suggested) APIs. >> There's a huge number of TimerLib instances (21 in my count), >> and >> replicating the implementation of the new APIs -- which are >> totally >> platform independent -- would defeat the whole exercise (which >> is to >> prevent code duplication). >> >> The library is currently for OvmfPkg only (in my local tree). >> I'm >> pasting the patch below. If there is interest, I could rework it >> for >> MdePkg. >> >> Thanks >> Laszlo >> >>> commit f1963c7b1705c7e46ce369802d8c15f943a114d6 >>> Author: Laszlo Ersek <lersek@redhat.com> >>> Date: Tue Aug 8 22:46:47 2017 +0200 >>> >>> OvmfPkg: add TimerTickDiffLib >>> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Laszlo Ersek <lersek@redhat.com> >>> >>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec >>> index 6a4c15c7917a..53a0a34d326d 100644 >>> --- a/OvmfPkg/OvmfPkg.dec >>> +++ b/OvmfPkg/OvmfPkg.dec >>> @@ -60,6 +60,10 @@ [LibraryClasses] >>> # >>> HexDumpLib|Include/Library/HexDumpLib.h >>> >>> + ## @libraryclass Timer tick difference functions, to be >> used with TimerLib. >>> + # >>> + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h >>> + >>> [Guids] >>> gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, 0xb9f2, >> 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} >>> gEfiXenInfoGuid = {0xd3b46f3b, 0xd441, >> 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} >>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc b/OvmfPkg/OvmfPkgIa32.dsc >>> index 5b0461ff46b1..17f1db43f57d 100644 >>> --- a/OvmfPkg/OvmfPkgIa32.dsc >>> +++ b/OvmfPkg/OvmfPkgIa32.dsc >>> @@ -97,6 +97,7 @@ [SkuIds] >>> # >>> >> ################################################################ >> ################ >>> [LibraryClasses] >>> + >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >> ib.inf >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc >> b/OvmfPkg/OvmfPkgIa32X64.dsc >>> index 0ce3cbd3ebd0..924e17824760 100644 >>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc >>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc >>> @@ -102,6 +102,7 @@ [SkuIds] >>> # >>> >> ################################################################ >> ################ >>> [LibraryClasses] >>> + >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >> ib.inf >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc >>> index e7bdf8711b0f..d22384a26768 100644 >>> --- a/OvmfPkg/OvmfPkgX64.dsc >>> +++ b/OvmfPkg/OvmfPkgX64.dsc >>> @@ -102,6 +102,7 @@ [SkuIds] >>> # >>> >> ################################################################ >> ################ >>> [LibraryClasses] >>> + >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >> ib.inf >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>> diff --git >> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >>> new file mode 100644 >>> index 000000000000..4d464565eb2f >>> --- /dev/null >>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >>> @@ -0,0 +1,31 @@ >>> +## @file >>> +# Timer tick difference functions, to be used with TimerLib. >>> +# >>> +# Copyright (C) 2017, Red Hat, Inc. >>> +# >>> +# This program and the accompanying materials are licensed >> and made available >>> +# under the terms and conditions of the BSD License which >> accompanies this >>> +# distribution. The full text of the license may be found at >>> +# http://opensource.org/licenses/bsd-license.php >>> +# >>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS >> IS" BASIS, WITHOUT >>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >> OR IMPLIED. >>> +## >>> + >>> +[Defines] >>> + INF_VERSION = 1.26 >>> + BASE_NAME = TimerTickDiffLib >>> + FILE_GUID = F1998AED-934F-4C96-AEFB- >> 29C39FA62434 >>> + MODULE_TYPE = BASE >>> + VERSION_STRING = 1.0 >>> + LIBRARY_CLASS = TimerTickDiffLib >>> + >>> +[Sources] >>> + TimerTickDiffLib.c >>> + >>> +[Packages] >>> + MdePkg/MdePkg.dec >>> + >>> +[LibraryClasses] >>> + BaseLib >>> + TimerLib >>> diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h >> b/OvmfPkg/Include/Library/TimerTickDiffLib.h >>> new file mode 100644 >>> index 000000000000..40052e11b6ed >>> --- /dev/null >>> +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h >>> @@ -0,0 +1,109 @@ >>> +/** @file >>> + Timer tick difference functions, to be used with TimerLib. >>> + >>> + Copyright (C) 2017, Red Hat, Inc. >>> + >>> + This program and the accompanying materials are licensed >> and made available >>> + under the terms and conditions of the BSD License which >> accompanies this >>> + distribution. The full text of the license may be found at >>> + http://opensource.org/licenses/bsd-license.php >>> + >>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS >> IS" BASIS, WITHOUT >>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >> OR IMPLIED. >>> +**/ >>> + >>> +#ifndef __TIMER_TICK_DIFF_LIB_H__ >>> +#define __TIMER_TICK_DIFF_LIB_H__ >>> + >>> +#include <Base.h> >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of ticks elapsed between them, such that the >> difference can be >>> + passed to TimerLib's GetTimeInNanoSecond(). >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of ticks corresponding to the >> conceptual difference >>> + (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetTickDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ); >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of nanoseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of nanoseconds corresponding to the >> conceptual difference >>> + (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetNanoSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ); >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of microseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of microseconds corresponding to the >> conceptual >>> + difference (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetMicroSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ); >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of milliseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of milliseconds corresponding to the >> conceptual >>> + difference (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetMilliSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ); >>> + >>> +#endif >>> diff --git >> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >>> new file mode 100644 >>> index 000000000000..03ecae8200aa >>> --- /dev/null >>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >>> @@ -0,0 +1,178 @@ >>> +/** @file >>> + Timer tick difference functions, to be used with TimerLib. >>> + >>> + Copyright (C) 2017, Red Hat, Inc. >>> + >>> + This program and the accompanying materials are licensed >> and made available >>> + under the terms and conditions of the BSD License which >> accompanies this >>> + distribution. The full text of the license may be found at >>> + http://opensource.org/licenses/bsd-license.php >>> + >>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS >> IS" BASIS, WITHOUT >>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >> OR IMPLIED. >>> +**/ >>> + >>> +#include <Library/BaseLib.h> >>> +#include <Library/TimerLib.h> >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of ticks elapsed between them, such that the >> difference can be >>> + passed to TimerLib's GetTimeInNanoSecond(). >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of ticks corresponding to the >> conceptual difference >>> + (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetTickDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ) >>> +{ >>> + UINT64 StartValue; >>> + UINT64 EndValue; >>> + UINT64 TickDifference; >>> + >>> + GetPerformanceCounterProperties (&StartValue, &EndValue); >>> + >>> + if (StartValue < EndValue) { >>> + // >>> + // The performance counter counts up. >>> + // >>> + if (PerfCounterStart < PerfCounterStop) { >>> + // >>> + // The counter didn't wrap around. >>> + // >>> + TickDifference = PerfCounterStop - PerfCounterStart; >>> + } else { >>> + // >>> + // The counter wrapped around. >>> + // >>> + TickDifference = (EndValue - PerfCounterStart) + >>> + (PerfCounterStop - StartValue); >>> + } >>> + } else { >>> + // >>> + // The performance counter counts down. >>> + // >>> + if (PerfCounterStart < PerfCounterStop) { >>> + // >>> + // The counter wrapped around. >>> + // >>> + TickDifference = (PerfCounterStart - EndValue) + >>> + (StartValue - PerfCounterStop); >>> + } else { >>> + // >>> + // The counter didn't wrap around. >>> + // >>> + TickDifference = PerfCounterStart - PerfCounterStop; >>> + } >>> + } >>> + >>> + return TickDifference; >>> +} >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of nanoseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of nanoseconds corresponding to the >> conceptual difference >>> + (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetNanoSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ) >>> +{ >>> + UINT64 TickDifference; >>> + UINT64 NanoSecondDifference; >>> + >>> + TickDifference = GetTickDifference (PerfCounterStart, >> PerfCounterStop); >>> + NanoSecondDifference = GetTimeInNanoSecond >> (TickDifference); >>> + return NanoSecondDifference; >>> +} >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of microseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of microseconds corresponding to the >> conceptual >>> + difference (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetMicroSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ) >>> +{ >>> + UINT64 NanoSecondDifference; >>> + UINT64 MicroSecondDifference; >>> + >>> + NanoSecondDifference = GetNanoSecondDifference ( >>> + PerfCounterStart, >>> + PerfCounterStop >>> + ); >>> + MicroSecondDifference = DivU64x32 (NanoSecondDifference, >> 1000); >>> + return MicroSecondDifference; >>> +} >>> + >>> +/** >>> + From two values retrieved with TimerLib's >> GetPerformanceCounter(), calculate >>> + the number of milliseconds elapsed between them. >>> + >>> + The function cannot handle multiple wrap-arounds of the >> performance counter. >>> + >>> + @param[in] PerfCounterStart The value returned by >> GetPerformanceCounter(), >>> + called earlier in wall clock >> time. >>> + >>> + @param[in] PerfCounterStop The value returned by >> GetPerformanceCounter(), >>> + called later in wall clock >> time. >>> + >>> + @retval The number of milliseconds corresponding to the >> conceptual >>> + difference (PerfCounterStop-PerfCounterStart). >>> +**/ >>> +UINT64 >>> +EFIAPI >>> +GetMilliSecondDifference ( >>> + IN UINT64 PerfCounterStart, >>> + IN UINT64 PerfCounterStop >>> + ) >>> +{ >>> + UINT64 NanoSecondDifference; >>> + UINT64 MilliSecondDifference; >>> + >>> + NanoSecondDifference = GetNanoSecondDifference ( >>> + PerfCounterStart, >>> + PerfCounterStop >>> + ); >>> + MilliSecondDifference = DivU64x32 (NanoSecondDifference, >> 1000 * 1000); >>> + return MilliSecondDifference; >>> +} ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: TimerTickDiffLib for MdePkg? 2017-08-16 16:08 ` Laszlo Ersek @ 2017-08-16 18:01 ` Kinney, Michael D 2017-08-16 18:24 ` Laszlo Ersek 0 siblings, 1 reply; 6+ messages in thread From: Kinney, Michael D @ 2017-08-16 18:01 UTC (permalink / raw) To: Laszlo Ersek, Gao, Liming, Kinney, Michael D; +Cc: edk2-devel-01 Hi Laszlo, I agree with the complexity of handling the combinations. A single implementation of a new lib class that provides helper functions on top of TimerLib class would be valuable. There is another code pattern we may also want to review to see if adding more helper functions would also have value. Modules that have APIs or loops with a timeout need to know when the timeout has been reached with good accuracy and low overhead. A couple of examples are: MdePkg\Library\BaseSynchronizationLib\Synchronization.c: 94 AcquireSpinLock() UefiCpuPkg\Library\MpInitLib\MpLib.c: 1052 CheckTimeout() We can search the repos for calls to GetPerformanceCounterProperties() to find the types of helper functions that might be valuable. There are a couple of approaches on timeouts. One is to wait until the tick difference reaches the timeout. This works if the timeout does not exceed the number of ticks that the TimerLib counter rolls over. The second approach is to accumulate the number of ticks that have elapsed within the loop to support timeouts that are longer that the TimerLibs rollover count. We may also want to consider multiple INF files for this library. Calling GetPerformanceCounterProperties() is extra overhead. If we are executing from RAM and can use global variables, then we can call GetPerformanceCounterProperties() once and cache the results in global variables. We only need to call GetPerformanceCounterProperties() if the code is XIP from NV storage. An example of this technique is in the implementation of InternalGetPerformanceCounterFrequency() in PcAtChipsetPkg\Library\AcpiTimerLib. There is a Base and Dxe version of this TimerLib. The Dxe one only does the work to determine the frequency of the timer once and saves it in a global variable. Best regards, Mike > -----Original Message----- > From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On > Behalf Of Laszlo Ersek > Sent: Wednesday, August 16, 2017 9:09 AM > To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming > <liming.gao@intel.com> > Cc: edk2-devel-01 <edk2-devel@lists.01.org> > Subject: Re: [edk2] TimerTickDiffLib for MdePkg? > > On 08/16/17 17:41, Kinney, Michael D wrote: > > Laszlo, > > > > The TimerLib already has the following API. > > > > /** > > Converts elapsed ticks of performance counter to time in > nanoseconds. > > > > This function converts the elapsed ticks of running > performance counter to > > time value in unit of nanoseconds. > > > > @param Ticks The number of elapsed ticks of running > performance counter. > > > > @return The elapsed time in nanoseconds. > > > > **/ > > UINT64 > > EFIAPI > > GetTimeInNanoSecond ( > > IN UINT64 Ticks > > ); > > > > I think a couple macros on top of this API could provide the > microsecond > > and millisecond units. > > I'm aware of GetTimeInNanoSecond(), and I agree that some macros > on top > would be sufficient for providing usec and msec wrappers. > > However, such wrappers are not the main point of this library. > > The main difficulty with using GetTimeInNanoSecond() is that the > caller > has to calculate the "Ticks" parameter. In theory, this is a > simple > difference, such as: > > // > // fetch the start tick > // > PerformanceCounterStart = GetPerformanceCounter (); > // > // do some work, then fetch the stop tick > // > PerformanceCounterStop = GetPerformanceCounter (); > // > // calculate tick difference > // > Ticks = PerformanceCounterStop - PerformanceCounterStart; > // > // get elapsed time > // > NanoSeconds = GetTimeInNanoSecond (Ticks); > > However, the Ticks parameter cannot be calculated as naively as > written > above, for two reasons: > > - The performance counter can wrap around while doing the work. > - The performance counter can be counting down as time > progresses. > > Therefore the simple subtraction for Ticks has to be replaced > every time > with an elaborate four-branched check; for every variation of > > { counts up, counts down } x { wrapped around, did not wrap > around } > > Additionally, in order to determine the counting direction, and > the > boundaries that have to be considered in case of wrap-around, > GetPerformanceCounterProperties() must be called first. > > Extracting this logic is the main point of the library -- please > see the > GetTickDifference() function. The rest is just convenience > fluff. > > Thanks > Laszlo > > >> -----Original Message----- > >> From: Laszlo Ersek [mailto:lersek@redhat.com] > >> Sent: Wednesday, August 16, 2017 4:46 AM > >> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, > Liming > >> <liming.gao@intel.com> > >> Cc: edk2-devel-01 <edk2-devel@lists.01.org> > >> Subject: TimerTickDiffLib for MdePkg? > >> > >> Hi, > >> > >> edk2 code frequently needs to calculate a time difference (in > >> nano-, > >> micro-, or milliseconds) between two timer tick values > retrieved > >> with > >> TimerLib's GetPerformanceCounter() call. For performance > >> measurements, > >> PERF_START() and friends can be used, but in many contexts > the > >> time > >> difference is needed for lower-level reasons. > >> > >> Such users can be enumerated by grepping for > >> GetPerformanceCounterProperties() call sites that pass in > non- > >> NULL > >> parameters -- this is needed for interpreting wrap-arounds in > >> tick > >> values (direction and boundaries). I'm seeing a whole lot of > >> such call > >> sites. (And some call sites don't handle both directions of > >> counting.) > >> > >> I've written a very small library for centralizing this. > While > >> I'm not > >> suggesting that existent code be rebased (although I'm also > not > >> advising > >> against it), I think this library would be convenient for new > >> code. > >> > >> I don't think TimerLib should be extended with the new > >> (suggested) APIs. > >> There's a huge number of TimerLib instances (21 in my count), > >> and > >> replicating the implementation of the new APIs -- which are > >> totally > >> platform independent -- would defeat the whole exercise > (which > >> is to > >> prevent code duplication). > >> > >> The library is currently for OvmfPkg only (in my local tree). > >> I'm > >> pasting the patch below. If there is interest, I could rework > it > >> for > >> MdePkg. > >> > >> Thanks > >> Laszlo > >> > >>> commit f1963c7b1705c7e46ce369802d8c15f943a114d6 > >>> Author: Laszlo Ersek <lersek@redhat.com> > >>> Date: Tue Aug 8 22:46:47 2017 +0200 > >>> > >>> OvmfPkg: add TimerTickDiffLib > >>> > >>> Contributed-under: TianoCore Contribution Agreement 1.1 > >>> Signed-off-by: Laszlo Ersek <lersek@redhat.com> > >>> > >>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec > >>> index 6a4c15c7917a..53a0a34d326d 100644 > >>> --- a/OvmfPkg/OvmfPkg.dec > >>> +++ b/OvmfPkg/OvmfPkg.dec > >>> @@ -60,6 +60,10 @@ [LibraryClasses] > >>> # > >>> HexDumpLib|Include/Library/HexDumpLib.h > >>> > >>> + ## @libraryclass Timer tick difference functions, to be > >> used with TimerLib. > >>> + # > >>> + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h > >>> + > >>> [Guids] > >>> gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, > 0xb9f2, > >> 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} > >>> gEfiXenInfoGuid = {0xd3b46f3b, > 0xd441, > >> 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} > >>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc > b/OvmfPkg/OvmfPkgIa32.dsc > >>> index 5b0461ff46b1..17f1db43f57d 100644 > >>> --- a/OvmfPkg/OvmfPkgIa32.dsc > >>> +++ b/OvmfPkg/OvmfPkgIa32.dsc > >>> @@ -97,6 +97,7 @@ [SkuIds] > >>> # > >>> > >> > ################################################################ > >> ################ > >>> [LibraryClasses] > >>> + > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >> ib.inf > >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>> > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc > >> b/OvmfPkg/OvmfPkgIa32X64.dsc > >>> index 0ce3cbd3ebd0..924e17824760 100644 > >>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc > >>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc > >>> @@ -102,6 +102,7 @@ [SkuIds] > >>> # > >>> > >> > ################################################################ > >> ################ > >>> [LibraryClasses] > >>> + > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >> ib.inf > >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>> > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc > >>> index e7bdf8711b0f..d22384a26768 100644 > >>> --- a/OvmfPkg/OvmfPkgX64.dsc > >>> +++ b/OvmfPkg/OvmfPkgX64.dsc > >>> @@ -102,6 +102,7 @@ [SkuIds] > >>> # > >>> > >> > ################################################################ > >> ################ > >>> [LibraryClasses] > >>> + > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >> ib.inf > >>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>> > TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>> diff --git > >> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >>> new file mode 100644 > >>> index 000000000000..4d464565eb2f > >>> --- /dev/null > >>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >>> @@ -0,0 +1,31 @@ > >>> +## @file > >>> +# Timer tick difference functions, to be used with > TimerLib. > >>> +# > >>> +# Copyright (C) 2017, Red Hat, Inc. > >>> +# > >>> +# This program and the accompanying materials are licensed > >> and made available > >>> +# under the terms and conditions of the BSD License which > >> accompanies this > >>> +# distribution. The full text of the license may be found > at > >>> +# http://opensource.org/licenses/bsd-license.php > >>> +# > >>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > "AS > >> IS" BASIS, WITHOUT > >>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > >> OR IMPLIED. > >>> +## > >>> + > >>> +[Defines] > >>> + INF_VERSION = 1.26 > >>> + BASE_NAME = TimerTickDiffLib > >>> + FILE_GUID = F1998AED-934F-4C96-AEFB- > >> 29C39FA62434 > >>> + MODULE_TYPE = BASE > >>> + VERSION_STRING = 1.0 > >>> + LIBRARY_CLASS = TimerTickDiffLib > >>> + > >>> +[Sources] > >>> + TimerTickDiffLib.c > >>> + > >>> +[Packages] > >>> + MdePkg/MdePkg.dec > >>> + > >>> +[LibraryClasses] > >>> + BaseLib > >>> + TimerLib > >>> diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h > >> b/OvmfPkg/Include/Library/TimerTickDiffLib.h > >>> new file mode 100644 > >>> index 000000000000..40052e11b6ed > >>> --- /dev/null > >>> +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h > >>> @@ -0,0 +1,109 @@ > >>> +/** @file > >>> + Timer tick difference functions, to be used with > TimerLib. > >>> + > >>> + Copyright (C) 2017, Red Hat, Inc. > >>> + > >>> + This program and the accompanying materials are licensed > >> and made available > >>> + under the terms and conditions of the BSD License which > >> accompanies this > >>> + distribution. The full text of the license may be found > at > >>> + http://opensource.org/licenses/bsd-license.php > >>> + > >>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > "AS > >> IS" BASIS, WITHOUT > >>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > >> OR IMPLIED. > >>> +**/ > >>> + > >>> +#ifndef __TIMER_TICK_DIFF_LIB_H__ > >>> +#define __TIMER_TICK_DIFF_LIB_H__ > >>> + > >>> +#include <Base.h> > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of ticks elapsed between them, such that the > >> difference can be > >>> + passed to TimerLib's GetTimeInNanoSecond(). > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of ticks corresponding to the > >> conceptual difference > >>> + (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetTickDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ); > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of nanoseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of nanoseconds corresponding to the > >> conceptual difference > >>> + (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetNanoSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ); > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of microseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of microseconds corresponding to the > >> conceptual > >>> + difference (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetMicroSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ); > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of milliseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of milliseconds corresponding to the > >> conceptual > >>> + difference (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetMilliSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ); > >>> + > >>> +#endif > >>> diff --git > >> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >>> new file mode 100644 > >>> index 000000000000..03ecae8200aa > >>> --- /dev/null > >>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >>> @@ -0,0 +1,178 @@ > >>> +/** @file > >>> + Timer tick difference functions, to be used with > TimerLib. > >>> + > >>> + Copyright (C) 2017, Red Hat, Inc. > >>> + > >>> + This program and the accompanying materials are licensed > >> and made available > >>> + under the terms and conditions of the BSD License which > >> accompanies this > >>> + distribution. The full text of the license may be found > at > >>> + http://opensource.org/licenses/bsd-license.php > >>> + > >>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > "AS > >> IS" BASIS, WITHOUT > >>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS > >> OR IMPLIED. > >>> +**/ > >>> + > >>> +#include <Library/BaseLib.h> > >>> +#include <Library/TimerLib.h> > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of ticks elapsed between them, such that the > >> difference can be > >>> + passed to TimerLib's GetTimeInNanoSecond(). > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of ticks corresponding to the > >> conceptual difference > >>> + (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetTickDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ) > >>> +{ > >>> + UINT64 StartValue; > >>> + UINT64 EndValue; > >>> + UINT64 TickDifference; > >>> + > >>> + GetPerformanceCounterProperties (&StartValue, &EndValue); > >>> + > >>> + if (StartValue < EndValue) { > >>> + // > >>> + // The performance counter counts up. > >>> + // > >>> + if (PerfCounterStart < PerfCounterStop) { > >>> + // > >>> + // The counter didn't wrap around. > >>> + // > >>> + TickDifference = PerfCounterStop - PerfCounterStart; > >>> + } else { > >>> + // > >>> + // The counter wrapped around. > >>> + // > >>> + TickDifference = (EndValue - PerfCounterStart) + > >>> + (PerfCounterStop - StartValue); > >>> + } > >>> + } else { > >>> + // > >>> + // The performance counter counts down. > >>> + // > >>> + if (PerfCounterStart < PerfCounterStop) { > >>> + // > >>> + // The counter wrapped around. > >>> + // > >>> + TickDifference = (PerfCounterStart - EndValue) + > >>> + (StartValue - PerfCounterStop); > >>> + } else { > >>> + // > >>> + // The counter didn't wrap around. > >>> + // > >>> + TickDifference = PerfCounterStart - PerfCounterStop; > >>> + } > >>> + } > >>> + > >>> + return TickDifference; > >>> +} > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of nanoseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of nanoseconds corresponding to the > >> conceptual difference > >>> + (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetNanoSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ) > >>> +{ > >>> + UINT64 TickDifference; > >>> + UINT64 NanoSecondDifference; > >>> + > >>> + TickDifference = GetTickDifference (PerfCounterStart, > >> PerfCounterStop); > >>> + NanoSecondDifference = GetTimeInNanoSecond > >> (TickDifference); > >>> + return NanoSecondDifference; > >>> +} > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of microseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of microseconds corresponding to the > >> conceptual > >>> + difference (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetMicroSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ) > >>> +{ > >>> + UINT64 NanoSecondDifference; > >>> + UINT64 MicroSecondDifference; > >>> + > >>> + NanoSecondDifference = GetNanoSecondDifference ( > >>> + PerfCounterStart, > >>> + PerfCounterStop > >>> + ); > >>> + MicroSecondDifference = DivU64x32 (NanoSecondDifference, > >> 1000); > >>> + return MicroSecondDifference; > >>> +} > >>> + > >>> +/** > >>> + From two values retrieved with TimerLib's > >> GetPerformanceCounter(), calculate > >>> + the number of milliseconds elapsed between them. > >>> + > >>> + The function cannot handle multiple wrap-arounds of the > >> performance counter. > >>> + > >>> + @param[in] PerfCounterStart The value returned by > >> GetPerformanceCounter(), > >>> + called earlier in wall clock > >> time. > >>> + > >>> + @param[in] PerfCounterStop The value returned by > >> GetPerformanceCounter(), > >>> + called later in wall clock > >> time. > >>> + > >>> + @retval The number of milliseconds corresponding to the > >> conceptual > >>> + difference (PerfCounterStop-PerfCounterStart). > >>> +**/ > >>> +UINT64 > >>> +EFIAPI > >>> +GetMilliSecondDifference ( > >>> + IN UINT64 PerfCounterStart, > >>> + IN UINT64 PerfCounterStop > >>> + ) > >>> +{ > >>> + UINT64 NanoSecondDifference; > >>> + UINT64 MilliSecondDifference; > >>> + > >>> + NanoSecondDifference = GetNanoSecondDifference ( > >>> + PerfCounterStart, > >>> + PerfCounterStop > >>> + ); > >>> + MilliSecondDifference = DivU64x32 (NanoSecondDifference, > >> 1000 * 1000); > >>> + return MilliSecondDifference; > >>> +} > > _______________________________________________ > edk2-devel mailing list > edk2-devel@lists.01.org > https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: TimerTickDiffLib for MdePkg? 2017-08-16 18:01 ` Kinney, Michael D @ 2017-08-16 18:24 ` Laszlo Ersek 2017-08-16 18:33 ` Kinney, Michael D 0 siblings, 1 reply; 6+ messages in thread From: Laszlo Ersek @ 2017-08-16 18:24 UTC (permalink / raw) To: Kinney, Michael D, Gao, Liming; +Cc: edk2-devel-01 Mike, On 08/16/17 20:01, Kinney, Michael D wrote: > Hi Laszlo, > > I agree with the complexity of handling the combinations. > > A single implementation of a new lib class that provides > helper functions on top of TimerLib class would be valuable. > > There is another code pattern we may also want to review to see > if adding more helper functions would also have value. Modules > that have APIs or loops with a timeout need to know when the > timeout has been reached with good accuracy and low overhead. > A couple of examples are: > > MdePkg\Library\BaseSynchronizationLib\Synchronization.c: 94 > AcquireSpinLock() > > UefiCpuPkg\Library\MpInitLib\MpLib.c: 1052 > CheckTimeout() > > We can search the repos for calls to GetPerformanceCounterProperties() > to find the types of helper functions that might be valuable. This sounds very valuable, but a bit larger bite than I expected :) > There are a couple of approaches on timeouts. One is to wait > until the tick difference reaches the timeout. This works if > the timeout does not exceed the number of ticks that the > TimerLib counter rolls over. The second approach is to accumulate > the number of ticks that have elapsed within the loop to support > timeouts that are longer that the TimerLibs rollover count. > > We may also want to consider multiple INF files for this library. > Calling GetPerformanceCounterProperties() is extra overhead. If > we are executing from RAM and can use global variables, then we can > call GetPerformanceCounterProperties() once and cache the results in > global variables. I thought of this. However, I figured the TimerLib instances themselves would make the same distinction (for example, we make a similar distinction in OvmfPkg, with "BaseRomAcpiTimerLib.inf", "BaseAcpiTimerLib.inf", and "DxeAcpiTimerLib.inf"). Once a TimerLib instance -- e.g. for DXE and later -- caches the data needed by GetPerformanceCounterProperties(), any caching layered on top becomes a waste. So my idea was to let the TimerLib instance cache whatever it can, internally to GetPerformanceCounterProperties(). This would be justified anyway, considering the current callers of GetPerformanceCounterProperties(). > We only need to call GetPerformanceCounterProperties() > if the code is XIP from NV storage. An example of this technique is > in the implementation of InternalGetPerformanceCounterFrequency() > in PcAtChipsetPkg\Library\AcpiTimerLib. There is a Base and Dxe > version of this TimerLib. The Dxe one only does the work to > determine the frequency of the timer once and saves it in a global > variable. Right. My argument is, if the StartValue and EndValue output parameters of GetPerformanceCounterProperties() are not constants, but require hardware access and/or some calculation, then a DXE TimerLib instance can cache those values as well, not just the frequency. So calling GetPerformanceCounterProperties() every time would add basically no overhead (while caching the results of GetPerformanceCounterProperties() could easily lead to duplicate caching -- internal and external). Thanks, Laszlo > > Best regards, > > Mike > >> -----Original Message----- >> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On >> Behalf Of Laszlo Ersek >> Sent: Wednesday, August 16, 2017 9:09 AM >> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming >> <liming.gao@intel.com> >> Cc: edk2-devel-01 <edk2-devel@lists.01.org> >> Subject: Re: [edk2] TimerTickDiffLib for MdePkg? >> >> On 08/16/17 17:41, Kinney, Michael D wrote: >>> Laszlo, >>> >>> The TimerLib already has the following API. >>> >>> /** >>> Converts elapsed ticks of performance counter to time in >> nanoseconds. >>> >>> This function converts the elapsed ticks of running >> performance counter to >>> time value in unit of nanoseconds. >>> >>> @param Ticks The number of elapsed ticks of running >> performance counter. >>> >>> @return The elapsed time in nanoseconds. >>> >>> **/ >>> UINT64 >>> EFIAPI >>> GetTimeInNanoSecond ( >>> IN UINT64 Ticks >>> ); >>> >>> I think a couple macros on top of this API could provide the >> microsecond >>> and millisecond units. >> >> I'm aware of GetTimeInNanoSecond(), and I agree that some macros >> on top >> would be sufficient for providing usec and msec wrappers. >> >> However, such wrappers are not the main point of this library. >> >> The main difficulty with using GetTimeInNanoSecond() is that the >> caller >> has to calculate the "Ticks" parameter. In theory, this is a >> simple >> difference, such as: >> >> // >> // fetch the start tick >> // >> PerformanceCounterStart = GetPerformanceCounter (); >> // >> // do some work, then fetch the stop tick >> // >> PerformanceCounterStop = GetPerformanceCounter (); >> // >> // calculate tick difference >> // >> Ticks = PerformanceCounterStop - PerformanceCounterStart; >> // >> // get elapsed time >> // >> NanoSeconds = GetTimeInNanoSecond (Ticks); >> >> However, the Ticks parameter cannot be calculated as naively as >> written >> above, for two reasons: >> >> - The performance counter can wrap around while doing the work. >> - The performance counter can be counting down as time >> progresses. >> >> Therefore the simple subtraction for Ticks has to be replaced >> every time >> with an elaborate four-branched check; for every variation of >> >> { counts up, counts down } x { wrapped around, did not wrap >> around } >> >> Additionally, in order to determine the counting direction, and >> the >> boundaries that have to be considered in case of wrap-around, >> GetPerformanceCounterProperties() must be called first. >> >> Extracting this logic is the main point of the library -- please >> see the >> GetTickDifference() function. The rest is just convenience >> fluff. >> >> Thanks >> Laszlo >> >>>> -----Original Message----- >>>> From: Laszlo Ersek [mailto:lersek@redhat.com] >>>> Sent: Wednesday, August 16, 2017 4:46 AM >>>> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, >> Liming >>>> <liming.gao@intel.com> >>>> Cc: edk2-devel-01 <edk2-devel@lists.01.org> >>>> Subject: TimerTickDiffLib for MdePkg? >>>> >>>> Hi, >>>> >>>> edk2 code frequently needs to calculate a time difference (in >>>> nano-, >>>> micro-, or milliseconds) between two timer tick values >> retrieved >>>> with >>>> TimerLib's GetPerformanceCounter() call. For performance >>>> measurements, >>>> PERF_START() and friends can be used, but in many contexts >> the >>>> time >>>> difference is needed for lower-level reasons. >>>> >>>> Such users can be enumerated by grepping for >>>> GetPerformanceCounterProperties() call sites that pass in >> non- >>>> NULL >>>> parameters -- this is needed for interpreting wrap-arounds in >>>> tick >>>> values (direction and boundaries). I'm seeing a whole lot of >>>> such call >>>> sites. (And some call sites don't handle both directions of >>>> counting.) >>>> >>>> I've written a very small library for centralizing this. >> While >>>> I'm not >>>> suggesting that existent code be rebased (although I'm also >> not >>>> advising >>>> against it), I think this library would be convenient for new >>>> code. >>>> >>>> I don't think TimerLib should be extended with the new >>>> (suggested) APIs. >>>> There's a huge number of TimerLib instances (21 in my count), >>>> and >>>> replicating the implementation of the new APIs -- which are >>>> totally >>>> platform independent -- would defeat the whole exercise >> (which >>>> is to >>>> prevent code duplication). >>>> >>>> The library is currently for OvmfPkg only (in my local tree). >>>> I'm >>>> pasting the patch below. If there is interest, I could rework >> it >>>> for >>>> MdePkg. >>>> >>>> Thanks >>>> Laszlo >>>> >>>>> commit f1963c7b1705c7e46ce369802d8c15f943a114d6 >>>>> Author: Laszlo Ersek <lersek@redhat.com> >>>>> Date: Tue Aug 8 22:46:47 2017 +0200 >>>>> >>>>> OvmfPkg: add TimerTickDiffLib >>>>> >>>>> Contributed-under: TianoCore Contribution Agreement 1.1 >>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com> >>>>> >>>>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec >>>>> index 6a4c15c7917a..53a0a34d326d 100644 >>>>> --- a/OvmfPkg/OvmfPkg.dec >>>>> +++ b/OvmfPkg/OvmfPkg.dec >>>>> @@ -60,6 +60,10 @@ [LibraryClasses] >>>>> # >>>>> HexDumpLib|Include/Library/HexDumpLib.h >>>>> >>>>> + ## @libraryclass Timer tick difference functions, to be >>>> used with TimerLib. >>>>> + # >>>>> + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h >>>>> + >>>>> [Guids] >>>>> gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, >> 0xb9f2, >>>> 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} >>>>> gEfiXenInfoGuid = {0xd3b46f3b, >> 0xd441, >>>> 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} >>>>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc >> b/OvmfPkg/OvmfPkgIa32.dsc >>>>> index 5b0461ff46b1..17f1db43f57d 100644 >>>>> --- a/OvmfPkg/OvmfPkgIa32.dsc >>>>> +++ b/OvmfPkg/OvmfPkgIa32.dsc >>>>> @@ -97,6 +97,7 @@ [SkuIds] >>>>> # >>>>> >>>> >> ################################################################ >>>> ################ >>>>> [LibraryClasses] >>>>> + >>>> >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >>>> ib.inf >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>>>> >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>>>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc >>>> b/OvmfPkg/OvmfPkgIa32X64.dsc >>>>> index 0ce3cbd3ebd0..924e17824760 100644 >>>>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc >>>>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc >>>>> @@ -102,6 +102,7 @@ [SkuIds] >>>>> # >>>>> >>>> >> ################################################################ >>>> ################ >>>>> [LibraryClasses] >>>>> + >>>> >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >>>> ib.inf >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>>>> >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>>>> diff --git a/OvmfPkg/OvmfPkgX64.dsc b/OvmfPkg/OvmfPkgX64.dsc >>>>> index e7bdf8711b0f..d22384a26768 100644 >>>>> --- a/OvmfPkg/OvmfPkgX64.dsc >>>>> +++ b/OvmfPkg/OvmfPkgX64.dsc >>>>> @@ -102,6 +102,7 @@ [SkuIds] >>>>> # >>>>> >>>> >> ################################################################ >>>> ################ >>>>> [LibraryClasses] >>>>> + >>>> >> TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL >>>> ib.inf >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf >>>>> >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf >>>>> diff --git >>>> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >>>> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >>>>> new file mode 100644 >>>>> index 000000000000..4d464565eb2f >>>>> --- /dev/null >>>>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf >>>>> @@ -0,0 +1,31 @@ >>>>> +## @file >>>>> +# Timer tick difference functions, to be used with >> TimerLib. >>>>> +# >>>>> +# Copyright (C) 2017, Red Hat, Inc. >>>>> +# >>>>> +# This program and the accompanying materials are licensed >>>> and made available >>>>> +# under the terms and conditions of the BSD License which >>>> accompanies this >>>>> +# distribution. The full text of the license may be found >> at >>>>> +# http://opensource.org/licenses/bsd-license.php >>>>> +# >>>>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN >> "AS >>>> IS" BASIS, WITHOUT >>>>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >>>> OR IMPLIED. >>>>> +## >>>>> + >>>>> +[Defines] >>>>> + INF_VERSION = 1.26 >>>>> + BASE_NAME = TimerTickDiffLib >>>>> + FILE_GUID = F1998AED-934F-4C96-AEFB- >>>> 29C39FA62434 >>>>> + MODULE_TYPE = BASE >>>>> + VERSION_STRING = 1.0 >>>>> + LIBRARY_CLASS = TimerTickDiffLib >>>>> + >>>>> +[Sources] >>>>> + TimerTickDiffLib.c >>>>> + >>>>> +[Packages] >>>>> + MdePkg/MdePkg.dec >>>>> + >>>>> +[LibraryClasses] >>>>> + BaseLib >>>>> + TimerLib >>>>> diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h >>>> b/OvmfPkg/Include/Library/TimerTickDiffLib.h >>>>> new file mode 100644 >>>>> index 000000000000..40052e11b6ed >>>>> --- /dev/null >>>>> +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h >>>>> @@ -0,0 +1,109 @@ >>>>> +/** @file >>>>> + Timer tick difference functions, to be used with >> TimerLib. >>>>> + >>>>> + Copyright (C) 2017, Red Hat, Inc. >>>>> + >>>>> + This program and the accompanying materials are licensed >>>> and made available >>>>> + under the terms and conditions of the BSD License which >>>> accompanies this >>>>> + distribution. The full text of the license may be found >> at >>>>> + http://opensource.org/licenses/bsd-license.php >>>>> + >>>>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN >> "AS >>>> IS" BASIS, WITHOUT >>>>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >>>> OR IMPLIED. >>>>> +**/ >>>>> + >>>>> +#ifndef __TIMER_TICK_DIFF_LIB_H__ >>>>> +#define __TIMER_TICK_DIFF_LIB_H__ >>>>> + >>>>> +#include <Base.h> >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of ticks elapsed between them, such that the >>>> difference can be >>>>> + passed to TimerLib's GetTimeInNanoSecond(). >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of ticks corresponding to the >>>> conceptual difference >>>>> + (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetTickDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ); >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of nanoseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of nanoseconds corresponding to the >>>> conceptual difference >>>>> + (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetNanoSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ); >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of microseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of microseconds corresponding to the >>>> conceptual >>>>> + difference (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetMicroSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ); >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of milliseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of milliseconds corresponding to the >>>> conceptual >>>>> + difference (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetMilliSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ); >>>>> + >>>>> +#endif >>>>> diff --git >>>> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >>>> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >>>>> new file mode 100644 >>>>> index 000000000000..03ecae8200aa >>>>> --- /dev/null >>>>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c >>>>> @@ -0,0 +1,178 @@ >>>>> +/** @file >>>>> + Timer tick difference functions, to be used with >> TimerLib. >>>>> + >>>>> + Copyright (C) 2017, Red Hat, Inc. >>>>> + >>>>> + This program and the accompanying materials are licensed >>>> and made available >>>>> + under the terms and conditions of the BSD License which >>>> accompanies this >>>>> + distribution. The full text of the license may be found >> at >>>>> + http://opensource.org/licenses/bsd-license.php >>>>> + >>>>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN >> "AS >>>> IS" BASIS, WITHOUT >>>>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS >>>> OR IMPLIED. >>>>> +**/ >>>>> + >>>>> +#include <Library/BaseLib.h> >>>>> +#include <Library/TimerLib.h> >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of ticks elapsed between them, such that the >>>> difference can be >>>>> + passed to TimerLib's GetTimeInNanoSecond(). >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of ticks corresponding to the >>>> conceptual difference >>>>> + (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetTickDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ) >>>>> +{ >>>>> + UINT64 StartValue; >>>>> + UINT64 EndValue; >>>>> + UINT64 TickDifference; >>>>> + >>>>> + GetPerformanceCounterProperties (&StartValue, &EndValue); >>>>> + >>>>> + if (StartValue < EndValue) { >>>>> + // >>>>> + // The performance counter counts up. >>>>> + // >>>>> + if (PerfCounterStart < PerfCounterStop) { >>>>> + // >>>>> + // The counter didn't wrap around. >>>>> + // >>>>> + TickDifference = PerfCounterStop - PerfCounterStart; >>>>> + } else { >>>>> + // >>>>> + // The counter wrapped around. >>>>> + // >>>>> + TickDifference = (EndValue - PerfCounterStart) + >>>>> + (PerfCounterStop - StartValue); >>>>> + } >>>>> + } else { >>>>> + // >>>>> + // The performance counter counts down. >>>>> + // >>>>> + if (PerfCounterStart < PerfCounterStop) { >>>>> + // >>>>> + // The counter wrapped around. >>>>> + // >>>>> + TickDifference = (PerfCounterStart - EndValue) + >>>>> + (StartValue - PerfCounterStop); >>>>> + } else { >>>>> + // >>>>> + // The counter didn't wrap around. >>>>> + // >>>>> + TickDifference = PerfCounterStart - PerfCounterStop; >>>>> + } >>>>> + } >>>>> + >>>>> + return TickDifference; >>>>> +} >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of nanoseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of nanoseconds corresponding to the >>>> conceptual difference >>>>> + (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetNanoSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ) >>>>> +{ >>>>> + UINT64 TickDifference; >>>>> + UINT64 NanoSecondDifference; >>>>> + >>>>> + TickDifference = GetTickDifference (PerfCounterStart, >>>> PerfCounterStop); >>>>> + NanoSecondDifference = GetTimeInNanoSecond >>>> (TickDifference); >>>>> + return NanoSecondDifference; >>>>> +} >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of microseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of microseconds corresponding to the >>>> conceptual >>>>> + difference (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetMicroSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ) >>>>> +{ >>>>> + UINT64 NanoSecondDifference; >>>>> + UINT64 MicroSecondDifference; >>>>> + >>>>> + NanoSecondDifference = GetNanoSecondDifference ( >>>>> + PerfCounterStart, >>>>> + PerfCounterStop >>>>> + ); >>>>> + MicroSecondDifference = DivU64x32 (NanoSecondDifference, >>>> 1000); >>>>> + return MicroSecondDifference; >>>>> +} >>>>> + >>>>> +/** >>>>> + From two values retrieved with TimerLib's >>>> GetPerformanceCounter(), calculate >>>>> + the number of milliseconds elapsed between them. >>>>> + >>>>> + The function cannot handle multiple wrap-arounds of the >>>> performance counter. >>>>> + >>>>> + @param[in] PerfCounterStart The value returned by >>>> GetPerformanceCounter(), >>>>> + called earlier in wall clock >>>> time. >>>>> + >>>>> + @param[in] PerfCounterStop The value returned by >>>> GetPerformanceCounter(), >>>>> + called later in wall clock >>>> time. >>>>> + >>>>> + @retval The number of milliseconds corresponding to the >>>> conceptual >>>>> + difference (PerfCounterStop-PerfCounterStart). >>>>> +**/ >>>>> +UINT64 >>>>> +EFIAPI >>>>> +GetMilliSecondDifference ( >>>>> + IN UINT64 PerfCounterStart, >>>>> + IN UINT64 PerfCounterStop >>>>> + ) >>>>> +{ >>>>> + UINT64 NanoSecondDifference; >>>>> + UINT64 MilliSecondDifference; >>>>> + >>>>> + NanoSecondDifference = GetNanoSecondDifference ( >>>>> + PerfCounterStart, >>>>> + PerfCounterStop >>>>> + ); >>>>> + MilliSecondDifference = DivU64x32 (NanoSecondDifference, >>>> 1000 * 1000); >>>>> + return MilliSecondDifference; >>>>> +} >> >> _______________________________________________ >> edk2-devel mailing list >> edk2-devel@lists.01.org >> https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: TimerTickDiffLib for MdePkg? 2017-08-16 18:24 ` Laszlo Ersek @ 2017-08-16 18:33 ` Kinney, Michael D 0 siblings, 0 replies; 6+ messages in thread From: Kinney, Michael D @ 2017-08-16 18:33 UTC (permalink / raw) To: Laszlo Ersek, Gao, Liming, Kinney, Michael D; +Cc: edk2-devel-01 Laszlo, I can help with the usage review and API proposals for this new lib class. I agree that the caching of GetPerformanceCounterProperties() can be handled in the TimerLib instances. We just need to make sure existing and new instances actually do this as needed. Mike > -----Original Message----- > From: Laszlo Ersek [mailto:lersek@redhat.com] > Sent: Wednesday, August 16, 2017 11:24 AM > To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, Liming > <liming.gao@intel.com> > Cc: edk2-devel-01 <edk2-devel@lists.01.org> > Subject: Re: [edk2] TimerTickDiffLib for MdePkg? > > Mike, > > On 08/16/17 20:01, Kinney, Michael D wrote: > > Hi Laszlo, > > > > I agree with the complexity of handling the combinations. > > > > A single implementation of a new lib class that provides > > helper functions on top of TimerLib class would be valuable. > > > > There is another code pattern we may also want to review to > see > > if adding more helper functions would also have value. > Modules > > that have APIs or loops with a timeout need to know when the > > timeout has been reached with good accuracy and low overhead. > > A couple of examples are: > > > > MdePkg\Library\BaseSynchronizationLib\Synchronization.c: 94 > > AcquireSpinLock() > > > > UefiCpuPkg\Library\MpInitLib\MpLib.c: 1052 > > CheckTimeout() > > > > We can search the repos for calls to > GetPerformanceCounterProperties() > > to find the types of helper functions that might be valuable. > > This sounds very valuable, but a bit larger bite than I expected > :) > > > There are a couple of approaches on timeouts. One is to wait > > until the tick difference reaches the timeout. This works if > > the timeout does not exceed the number of ticks that the > > TimerLib counter rolls over. The second approach is to > accumulate > > the number of ticks that have elapsed within the loop to > support > > timeouts that are longer that the TimerLibs rollover count. > > > > We may also want to consider multiple INF files for this > library. > > Calling GetPerformanceCounterProperties() is extra overhead. > If > > we are executing from RAM and can use global variables, then > we can > > call GetPerformanceCounterProperties() once and cache the > results in > > global variables. > > I thought of this. However, I figured the TimerLib instances > themselves > would make the same distinction (for example, we make a similar > distinction in OvmfPkg, with "BaseRomAcpiTimerLib.inf", > "BaseAcpiTimerLib.inf", and "DxeAcpiTimerLib.inf"). > > Once a TimerLib instance -- e.g. for DXE and later -- caches the > data > needed by GetPerformanceCounterProperties(), any caching layered > on top > becomes a waste. > > So my idea was to let the TimerLib instance cache whatever it > can, > internally to GetPerformanceCounterProperties(). This would be > justified > anyway, considering the current callers of > GetPerformanceCounterProperties(). > > > We only need to call GetPerformanceCounterProperties() > > if the code is XIP from NV storage. An example of this > technique is > > in the implementation of > InternalGetPerformanceCounterFrequency() > > in PcAtChipsetPkg\Library\AcpiTimerLib. There is a Base and > Dxe > > version of this TimerLib. The Dxe one only does the work to > > determine the frequency of the timer once and saves it in a > global > > variable. > > Right. My argument is, if the StartValue and EndValue output > parameters > of GetPerformanceCounterProperties() are not constants, but > require > hardware access and/or some calculation, then a DXE TimerLib > instance > can cache those values as well, not just the frequency. > > So calling GetPerformanceCounterProperties() every time would > add > basically no overhead (while caching the results of > GetPerformanceCounterProperties() could easily lead to duplicate > caching > -- internal and external). > > Thanks, > Laszlo > > > > > Best regards, > > > > Mike > > > >> -----Original Message----- > >> From: edk2-devel [mailto:edk2-devel-bounces@lists.01.org] On > >> Behalf Of Laszlo Ersek > >> Sent: Wednesday, August 16, 2017 9:09 AM > >> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, > Liming > >> <liming.gao@intel.com> > >> Cc: edk2-devel-01 <edk2-devel@lists.01.org> > >> Subject: Re: [edk2] TimerTickDiffLib for MdePkg? > >> > >> On 08/16/17 17:41, Kinney, Michael D wrote: > >>> Laszlo, > >>> > >>> The TimerLib already has the following API. > >>> > >>> /** > >>> Converts elapsed ticks of performance counter to time in > >> nanoseconds. > >>> > >>> This function converts the elapsed ticks of running > >> performance counter to > >>> time value in unit of nanoseconds. > >>> > >>> @param Ticks The number of elapsed ticks of running > >> performance counter. > >>> > >>> @return The elapsed time in nanoseconds. > >>> > >>> **/ > >>> UINT64 > >>> EFIAPI > >>> GetTimeInNanoSecond ( > >>> IN UINT64 Ticks > >>> ); > >>> > >>> I think a couple macros on top of this API could provide the > >> microsecond > >>> and millisecond units. > >> > >> I'm aware of GetTimeInNanoSecond(), and I agree that some > macros > >> on top > >> would be sufficient for providing usec and msec wrappers. > >> > >> However, such wrappers are not the main point of this > library. > >> > >> The main difficulty with using GetTimeInNanoSecond() is that > the > >> caller > >> has to calculate the "Ticks" parameter. In theory, this is a > >> simple > >> difference, such as: > >> > >> // > >> // fetch the start tick > >> // > >> PerformanceCounterStart = GetPerformanceCounter (); > >> // > >> // do some work, then fetch the stop tick > >> // > >> PerformanceCounterStop = GetPerformanceCounter (); > >> // > >> // calculate tick difference > >> // > >> Ticks = PerformanceCounterStop - PerformanceCounterStart; > >> // > >> // get elapsed time > >> // > >> NanoSeconds = GetTimeInNanoSecond (Ticks); > >> > >> However, the Ticks parameter cannot be calculated as naively > as > >> written > >> above, for two reasons: > >> > >> - The performance counter can wrap around while doing the > work. > >> - The performance counter can be counting down as time > >> progresses. > >> > >> Therefore the simple subtraction for Ticks has to be replaced > >> every time > >> with an elaborate four-branched check; for every variation of > >> > >> { counts up, counts down } x { wrapped around, did not wrap > >> around } > >> > >> Additionally, in order to determine the counting direction, > and > >> the > >> boundaries that have to be considered in case of wrap-around, > >> GetPerformanceCounterProperties() must be called first. > >> > >> Extracting this logic is the main point of the library -- > please > >> see the > >> GetTickDifference() function. The rest is just convenience > >> fluff. > >> > >> Thanks > >> Laszlo > >> > >>>> -----Original Message----- > >>>> From: Laszlo Ersek [mailto:lersek@redhat.com] > >>>> Sent: Wednesday, August 16, 2017 4:46 AM > >>>> To: Kinney, Michael D <michael.d.kinney@intel.com>; Gao, > >> Liming > >>>> <liming.gao@intel.com> > >>>> Cc: edk2-devel-01 <edk2-devel@lists.01.org> > >>>> Subject: TimerTickDiffLib for MdePkg? > >>>> > >>>> Hi, > >>>> > >>>> edk2 code frequently needs to calculate a time difference > (in > >>>> nano-, > >>>> micro-, or milliseconds) between two timer tick values > >> retrieved > >>>> with > >>>> TimerLib's GetPerformanceCounter() call. For performance > >>>> measurements, > >>>> PERF_START() and friends can be used, but in many contexts > >> the > >>>> time > >>>> difference is needed for lower-level reasons. > >>>> > >>>> Such users can be enumerated by grepping for > >>>> GetPerformanceCounterProperties() call sites that pass in > >> non- > >>>> NULL > >>>> parameters -- this is needed for interpreting wrap-arounds > in > >>>> tick > >>>> values (direction and boundaries). I'm seeing a whole lot > of > >>>> such call > >>>> sites. (And some call sites don't handle both directions of > >>>> counting.) > >>>> > >>>> I've written a very small library for centralizing this. > >> While > >>>> I'm not > >>>> suggesting that existent code be rebased (although I'm also > >> not > >>>> advising > >>>> against it), I think this library would be convenient for > new > >>>> code. > >>>> > >>>> I don't think TimerLib should be extended with the new > >>>> (suggested) APIs. > >>>> There's a huge number of TimerLib instances (21 in my > count), > >>>> and > >>>> replicating the implementation of the new APIs -- which are > >>>> totally > >>>> platform independent -- would defeat the whole exercise > >> (which > >>>> is to > >>>> prevent code duplication). > >>>> > >>>> The library is currently for OvmfPkg only (in my local > tree). > >>>> I'm > >>>> pasting the patch below. If there is interest, I could > rework > >> it > >>>> for > >>>> MdePkg. > >>>> > >>>> Thanks > >>>> Laszlo > >>>> > >>>>> commit f1963c7b1705c7e46ce369802d8c15f943a114d6 > >>>>> Author: Laszlo Ersek <lersek@redhat.com> > >>>>> Date: Tue Aug 8 22:46:47 2017 +0200 > >>>>> > >>>>> OvmfPkg: add TimerTickDiffLib > >>>>> > >>>>> Contributed-under: TianoCore Contribution Agreement > 1.1 > >>>>> Signed-off-by: Laszlo Ersek <lersek@redhat.com> > >>>>> > >>>>> diff --git a/OvmfPkg/OvmfPkg.dec b/OvmfPkg/OvmfPkg.dec > >>>>> index 6a4c15c7917a..53a0a34d326d 100644 > >>>>> --- a/OvmfPkg/OvmfPkg.dec > >>>>> +++ b/OvmfPkg/OvmfPkg.dec > >>>>> @@ -60,6 +60,10 @@ [LibraryClasses] > >>>>> # > >>>>> HexDumpLib|Include/Library/HexDumpLib.h > >>>>> > >>>>> + ## @libraryclass Timer tick difference functions, to > be > >>>> used with TimerLib. > >>>>> + # > >>>>> + TimerTickDiffLib|Include/Library/TimerTickDiffLib.h > >>>>> + > >>>>> [Guids] > >>>>> gUefiOvmfPkgTokenSpaceGuid = {0x93bb96af, > >> 0xb9f2, > >>>> 0x4eb8, {0x94, 0x62, 0xe0, 0xba, 0x74, 0x56, 0x42, 0x36}} > >>>>> gEfiXenInfoGuid = {0xd3b46f3b, > >> 0xd441, > >>>> 0x1244, {0x9a, 0x12, 0x0, 0x12, 0x27, 0x3f, 0xc1, 0x4d}} > >>>>> diff --git a/OvmfPkg/OvmfPkgIa32.dsc > >> b/OvmfPkg/OvmfPkgIa32.dsc > >>>>> index 5b0461ff46b1..17f1db43f57d 100644 > >>>>> --- a/OvmfPkg/OvmfPkgIa32.dsc > >>>>> +++ b/OvmfPkg/OvmfPkgIa32.dsc > >>>>> @@ -97,6 +97,7 @@ [SkuIds] > >>>>> # > >>>>> > >>>> > >> > ################################################################ > >>>> ################ > >>>>> [LibraryClasses] > >>>>> + > >>>> > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >>>> ib.inf > >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>>>> > >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>>>> diff --git a/OvmfPkg/OvmfPkgIa32X64.dsc > >>>> b/OvmfPkg/OvmfPkgIa32X64.dsc > >>>>> index 0ce3cbd3ebd0..924e17824760 100644 > >>>>> --- a/OvmfPkg/OvmfPkgIa32X64.dsc > >>>>> +++ b/OvmfPkg/OvmfPkgIa32X64.dsc > >>>>> @@ -102,6 +102,7 @@ [SkuIds] > >>>>> # > >>>>> > >>>> > >> > ################################################################ > >>>> ################ > >>>>> [LibraryClasses] > >>>>> + > >>>> > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >>>> ib.inf > >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>>>> > >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>>>> diff --git a/OvmfPkg/OvmfPkgX64.dsc > b/OvmfPkg/OvmfPkgX64.dsc > >>>>> index e7bdf8711b0f..d22384a26768 100644 > >>>>> --- a/OvmfPkg/OvmfPkgX64.dsc > >>>>> +++ b/OvmfPkg/OvmfPkgX64.dsc > >>>>> @@ -102,6 +102,7 @@ [SkuIds] > >>>>> # > >>>>> > >>>> > >> > ################################################################ > >>>> ################ > >>>>> [LibraryClasses] > >>>>> + > >>>> > >> > TimerTickDiffLib|OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffL > >>>> ib.inf > >>>>> HexDumpLib|OvmfPkg/Library/HexDumpLib/HexDumpLib.inf > >>>>> PcdLib|MdePkg/Library/BasePcdLibNull/BasePcdLibNull.inf > >>>>> > >> TimerLib|OvmfPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.inf > >>>>> diff --git > >>>> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >>>> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >>>>> new file mode 100644 > >>>>> index 000000000000..4d464565eb2f > >>>>> --- /dev/null > >>>>> +++ > b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.inf > >>>>> @@ -0,0 +1,31 @@ > >>>>> +## @file > >>>>> +# Timer tick difference functions, to be used with > >> TimerLib. > >>>>> +# > >>>>> +# Copyright (C) 2017, Red Hat, Inc. > >>>>> +# > >>>>> +# This program and the accompanying materials are > licensed > >>>> and made available > >>>>> +# under the terms and conditions of the BSD License which > >>>> accompanies this > >>>>> +# distribution. The full text of the license may be found > >> at > >>>>> +# http://opensource.org/licenses/bsd-license.php > >>>>> +# > >>>>> +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > >> "AS > >>>> IS" BASIS, WITHOUT > >>>>> +# WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS > >>>> OR IMPLIED. > >>>>> +## > >>>>> + > >>>>> +[Defines] > >>>>> + INF_VERSION = 1.26 > >>>>> + BASE_NAME = TimerTickDiffLib > >>>>> + FILE_GUID = F1998AED-934F-4C96- > AEFB- > >>>> 29C39FA62434 > >>>>> + MODULE_TYPE = BASE > >>>>> + VERSION_STRING = 1.0 > >>>>> + LIBRARY_CLASS = TimerTickDiffLib > >>>>> + > >>>>> +[Sources] > >>>>> + TimerTickDiffLib.c > >>>>> + > >>>>> +[Packages] > >>>>> + MdePkg/MdePkg.dec > >>>>> + > >>>>> +[LibraryClasses] > >>>>> + BaseLib > >>>>> + TimerLib > >>>>> diff --git a/OvmfPkg/Include/Library/TimerTickDiffLib.h > >>>> b/OvmfPkg/Include/Library/TimerTickDiffLib.h > >>>>> new file mode 100644 > >>>>> index 000000000000..40052e11b6ed > >>>>> --- /dev/null > >>>>> +++ b/OvmfPkg/Include/Library/TimerTickDiffLib.h > >>>>> @@ -0,0 +1,109 @@ > >>>>> +/** @file > >>>>> + Timer tick difference functions, to be used with > >> TimerLib. > >>>>> + > >>>>> + Copyright (C) 2017, Red Hat, Inc. > >>>>> + > >>>>> + This program and the accompanying materials are > licensed > >>>> and made available > >>>>> + under the terms and conditions of the BSD License which > >>>> accompanies this > >>>>> + distribution. The full text of the license may be found > >> at > >>>>> + http://opensource.org/licenses/bsd-license.php > >>>>> + > >>>>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > >> "AS > >>>> IS" BASIS, WITHOUT > >>>>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS > >>>> OR IMPLIED. > >>>>> +**/ > >>>>> + > >>>>> +#ifndef __TIMER_TICK_DIFF_LIB_H__ > >>>>> +#define __TIMER_TICK_DIFF_LIB_H__ > >>>>> + > >>>>> +#include <Base.h> > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of ticks elapsed between them, such that the > >>>> difference can be > >>>>> + passed to TimerLib's GetTimeInNanoSecond(). > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of ticks corresponding to the > >>>> conceptual difference > >>>>> + (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetTickDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ); > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of nanoseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of nanoseconds corresponding to the > >>>> conceptual difference > >>>>> + (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetNanoSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ); > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of microseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of microseconds corresponding to > the > >>>> conceptual > >>>>> + difference (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetMicroSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ); > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of milliseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of milliseconds corresponding to > the > >>>> conceptual > >>>>> + difference (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetMilliSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ); > >>>>> + > >>>>> +#endif > >>>>> diff --git > >>>> a/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >>>> b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >>>>> new file mode 100644 > >>>>> index 000000000000..03ecae8200aa > >>>>> --- /dev/null > >>>>> +++ b/OvmfPkg/Library/TimerTickDiffLib/TimerTickDiffLib.c > >>>>> @@ -0,0 +1,178 @@ > >>>>> +/** @file > >>>>> + Timer tick difference functions, to be used with > >> TimerLib. > >>>>> + > >>>>> + Copyright (C) 2017, Red Hat, Inc. > >>>>> + > >>>>> + This program and the accompanying materials are > licensed > >>>> and made available > >>>>> + under the terms and conditions of the BSD License which > >>>> accompanies this > >>>>> + distribution. The full text of the license may be found > >> at > >>>>> + http://opensource.org/licenses/bsd-license.php > >>>>> + > >>>>> + THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN > >> "AS > >>>> IS" BASIS, WITHOUT > >>>>> + WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER > EXPRESS > >>>> OR IMPLIED. > >>>>> +**/ > >>>>> + > >>>>> +#include <Library/BaseLib.h> > >>>>> +#include <Library/TimerLib.h> > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of ticks elapsed between them, such that the > >>>> difference can be > >>>>> + passed to TimerLib's GetTimeInNanoSecond(). > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of ticks corresponding to the > >>>> conceptual difference > >>>>> + (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetTickDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ) > >>>>> +{ > >>>>> + UINT64 StartValue; > >>>>> + UINT64 EndValue; > >>>>> + UINT64 TickDifference; > >>>>> + > >>>>> + GetPerformanceCounterProperties (&StartValue, > &EndValue); > >>>>> + > >>>>> + if (StartValue < EndValue) { > >>>>> + // > >>>>> + // The performance counter counts up. > >>>>> + // > >>>>> + if (PerfCounterStart < PerfCounterStop) { > >>>>> + // > >>>>> + // The counter didn't wrap around. > >>>>> + // > >>>>> + TickDifference = PerfCounterStop - > PerfCounterStart; > >>>>> + } else { > >>>>> + // > >>>>> + // The counter wrapped around. > >>>>> + // > >>>>> + TickDifference = (EndValue - PerfCounterStart) + > >>>>> + (PerfCounterStop - StartValue); > >>>>> + } > >>>>> + } else { > >>>>> + // > >>>>> + // The performance counter counts down. > >>>>> + // > >>>>> + if (PerfCounterStart < PerfCounterStop) { > >>>>> + // > >>>>> + // The counter wrapped around. > >>>>> + // > >>>>> + TickDifference = (PerfCounterStart - EndValue) + > >>>>> + (StartValue - PerfCounterStop); > >>>>> + } else { > >>>>> + // > >>>>> + // The counter didn't wrap around. > >>>>> + // > >>>>> + TickDifference = PerfCounterStart - > PerfCounterStop; > >>>>> + } > >>>>> + } > >>>>> + > >>>>> + return TickDifference; > >>>>> +} > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of nanoseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of nanoseconds corresponding to the > >>>> conceptual difference > >>>>> + (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetNanoSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ) > >>>>> +{ > >>>>> + UINT64 TickDifference; > >>>>> + UINT64 NanoSecondDifference; > >>>>> + > >>>>> + TickDifference = GetTickDifference (PerfCounterStart, > >>>> PerfCounterStop); > >>>>> + NanoSecondDifference = GetTimeInNanoSecond > >>>> (TickDifference); > >>>>> + return NanoSecondDifference; > >>>>> +} > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of microseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of microseconds corresponding to > the > >>>> conceptual > >>>>> + difference (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetMicroSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ) > >>>>> +{ > >>>>> + UINT64 NanoSecondDifference; > >>>>> + UINT64 MicroSecondDifference; > >>>>> + > >>>>> + NanoSecondDifference = GetNanoSecondDifference ( > >>>>> + PerfCounterStart, > >>>>> + PerfCounterStop > >>>>> + ); > >>>>> + MicroSecondDifference = DivU64x32 > (NanoSecondDifference, > >>>> 1000); > >>>>> + return MicroSecondDifference; > >>>>> +} > >>>>> + > >>>>> +/** > >>>>> + From two values retrieved with TimerLib's > >>>> GetPerformanceCounter(), calculate > >>>>> + the number of milliseconds elapsed between them. > >>>>> + > >>>>> + The function cannot handle multiple wrap-arounds of the > >>>> performance counter. > >>>>> + > >>>>> + @param[in] PerfCounterStart The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called earlier in wall > clock > >>>> time. > >>>>> + > >>>>> + @param[in] PerfCounterStop The value returned by > >>>> GetPerformanceCounter(), > >>>>> + called later in wall clock > >>>> time. > >>>>> + > >>>>> + @retval The number of milliseconds corresponding to > the > >>>> conceptual > >>>>> + difference (PerfCounterStop-PerfCounterStart). > >>>>> +**/ > >>>>> +UINT64 > >>>>> +EFIAPI > >>>>> +GetMilliSecondDifference ( > >>>>> + IN UINT64 PerfCounterStart, > >>>>> + IN UINT64 PerfCounterStop > >>>>> + ) > >>>>> +{ > >>>>> + UINT64 NanoSecondDifference; > >>>>> + UINT64 MilliSecondDifference; > >>>>> + > >>>>> + NanoSecondDifference = GetNanoSecondDifference ( > >>>>> + PerfCounterStart, > >>>>> + PerfCounterStop > >>>>> + ); > >>>>> + MilliSecondDifference = DivU64x32 > (NanoSecondDifference, > >>>> 1000 * 1000); > >>>>> + return MilliSecondDifference; > >>>>> +} > >> > >> _______________________________________________ > >> edk2-devel mailing list > >> edk2-devel@lists.01.org > >> https://lists.01.org/mailman/listinfo/edk2-devel ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-08-16 18:31 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-08-16 11:45 TimerTickDiffLib for MdePkg? Laszlo Ersek 2017-08-16 15:41 ` Kinney, Michael D 2017-08-16 16:08 ` Laszlo Ersek 2017-08-16 18:01 ` Kinney, Michael D 2017-08-16 18:24 ` Laszlo Ersek 2017-08-16 18:33 ` Kinney, Michael D
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox