public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: Laszlo Ersek <lersek@redhat.com>
To: Michael Kinney <michael.d.kinney@intel.com>,
	"Gao, Liming" <liming.gao@intel.com>
Cc: edk2-devel-01 <edk2-devel@lists.01.org>
Subject: TimerTickDiffLib for MdePkg?
Date: Wed, 16 Aug 2017 13:45:36 +0200	[thread overview]
Message-ID: <8cba2a58-1333-7733-031d-0883dbd844c6@redhat.com> (raw)

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;
> +}


             reply	other threads:[~2017-08-16 11:43 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-08-16 11:45 Laszlo Ersek [this message]
2017-08-16 15:41 ` TimerTickDiffLib for MdePkg? 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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=8cba2a58-1333-7733-031d-0883dbd844c6@redhat.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox