public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
* 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