From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ml01.01.org (Postfix) with ESMTPS id E367E21CFA605 for ; Wed, 16 Aug 2017 09:06:14 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id AD4EA68CC; Wed, 16 Aug 2017 16:08:40 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com AD4EA68CC Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx10.extmail.prod.ext.phx2.redhat.com; spf=fail smtp.mailfrom=lersek@redhat.com Received: from lacos-laptop-7.usersys.redhat.com (ovpn-116-59.phx2.redhat.com [10.3.116.59]) by smtp.corp.redhat.com (Postfix) with ESMTP id 862307D92C; Wed, 16 Aug 2017 16:08:39 +0000 (UTC) To: "Kinney, Michael D" , "Gao, Liming" Cc: edk2-devel-01 References: <8cba2a58-1333-7733-031d-0883dbd844c6@redhat.com> From: Laszlo Ersek Message-ID: <3e1428f1-0880-17a1-5aed-f73aa2212735@redhat.com> Date: Wed, 16 Aug 2017 18:08:38 +0200 User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101 Thunderbird/52.2.1 MIME-Version: 1.0 In-Reply-To: X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.39]); Wed, 16 Aug 2017 16:08:40 +0000 (UTC) Subject: Re: TimerTickDiffLib for MdePkg? X-BeenThere: edk2-devel@lists.01.org X-Mailman-Version: 2.1.22 Precedence: list List-Id: EDK II Development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Aug 2017 16:06:15 -0000 Content-Type: text/plain; charset=utf-8 Content-Language: en-US Content-Transfer-Encoding: 7bit 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 ; Gao, Liming >> >> Cc: edk2-devel-01 >> 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 >>> Date: Tue Aug 8 22:46:47 2017 +0200 >>> >>> OvmfPkg: add TimerTickDiffLib >>> >>> Contributed-under: TianoCore Contribution Agreement 1.1 >>> Signed-off-by: Laszlo Ersek >>> >>> 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 >>> + >>> +/** >>> + 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 >>> +#include >>> + >>> +/** >>> + 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; >>> +}