From: "Zeng, Star" <star.zeng@intel.com>
To: Paolo Bonzini <pbonzini@redhat.com>, edk2-devel@lists.01.org
Cc: Michael D Kinney <michael.d.kinney@intel.com>,
Liming Gao <liming.gao@intel.com>
Subject: Re: [PATCH] PcAtChipsetPkg AcpiTimerLib: Get more accurate TSC Frequency
Date: Fri, 12 Aug 2016 16:43:26 +0800 [thread overview]
Message-ID: <aa0c0680-0916-6d1b-3e4b-5a254af361a9@intel.com> (raw)
In-Reply-To: <0229321a-849c-b264-7b26-146d6608c754@redhat.com>
On 2016/8/12 16:31, Paolo Bonzini wrote:
>
>
> On 11/08/2016 04:37, Star Zeng wrote:
>> Minimize the code overhead between the two TSC reads by adding
>> new internal API to calculate TSC Frequency instead of reusing
>> MicroSecondDelay ().
>>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Liming Gao <liming.gao@intel.com>
>> Cc: Paul A Lohr <paul.a.lohr@intel.com>
>> Contributed-under: TianoCore Contribution Agreement 1.0
>> Signed-off-by: Star Zeng <star.zeng@intel.com>
>> ---
>> PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c | 56 +++++++++++++++++++++-
>> .../Library/AcpiTimerLib/BaseAcpiTimerLib.c | 33 ++++++++-----
>> .../Library/AcpiTimerLib/DxeAcpiTimerLib.c | 31 ++++++++----
>> 3 files changed, 99 insertions(+), 21 deletions(-)
>>
>> diff --git a/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c b/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c
>> index 806a4f7ce24c..e6fea231123d 100644
>> --- a/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c
>> +++ b/PcAtChipsetPkg/Library/AcpiTimerLib/AcpiTimerLib.c
>> @@ -1,7 +1,7 @@
>> /** @file
>> ACPI Timer implements one instance of Timer Library.
>>
>> - Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
>> + Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
>> 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
>> @@ -335,3 +335,57 @@ GetTimeInNanoSecond (
>>
>> return NanoSeconds;
>> }
>> +
>> +/**
>> + Calculate TSC frequency.
>> +
>> + The TSC counting frequency is determined by comparing how far it counts
>> + during a 100us period as determined by the ACPI timer. The ACPI timer is
>> + used because it counts at a known frequency.
>> + The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
>> + clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
>> + difference multiplied by 10000 is the TSC frequency. There will be a small
>> + error because of the overhead of reading the ACPI timer. An attempt is
>> + made to determine and compensate for this error.
>> +
>> + @return The number of TSC counts per second.
>> +
>> +**/
>> +UINT64
>> +InternalCalculateTscFrequency (
>> + VOID
>> + )
>> +{
>> + UINT64 StartTSC;
>> + UINT64 EndTSC;
>> + UINT16 TimerAddr;
>> + UINT32 Ticks;
>> + UINT64 TscFrequency;
>> + BOOLEAN InterruptState;
>> +
>> + InterruptState = SaveAndDisableInterrupts ();
>> +
>> + TimerAddr = InternalAcpiGetAcpiTimerIoPort ();
>> + Ticks = IoRead32 (TimerAddr) + (ACPI_TIMER_FREQUENCY / 10000); // Set Ticks to 100us in the future
>
> ACPI_TIMER_FREQUENCY is 3579545, thus you're waiting 357 ticks but the
> actual result of the division is much closer to 358. The error is only
> 0.26%, but it's so simple to reduce it that I think it's worth it. Just
> change (ACPI_TIMER_FREQUENCY / 10000) to (ACPI_TIMER_FREQUENCY + 5000) /
> 10000.
Paolo,
It is nice to have it I think, and I prefer to use (ACPI_TIMER_FREQUENCY
+ 5000) / 10000.
Since I have pushed this patch, do you mind to contribute the proposal
with a new patch?
Thanks,
Star
>
> Another possibility is to count 343 ticks and multiply by 10436; 343 *
> 10436 is almost exactly ACPI_TIMER_FREQUENCY.
>
> Paolo
>
>> + StartTSC = AsmReadTsc (); // Get base value for the TSC
>> + //
>> + // Wait until the ACPI timer has counted 100us.
>> + // Timer wrap-arounds are handled correctly by this function.
>> + // When the current ACPI timer value is greater than 'Ticks', the while loop will exit.
>> + //
>> + while (((Ticks - IoRead32 (TimerAddr)) & BIT23) == 0) {
>> + CpuPause();
>> + }
>> + EndTSC = AsmReadTsc (); // TSC value 100us later
>> +
>> + TscFrequency = MultU64x32 (
>> + (EndTSC - StartTSC), // Number of TSC counts in 100us
>> + 10000 // Number of 100us in a second
>> + );
>> +
>> + SetInterruptState (InterruptState);
>> +
>> + return TscFrequency;
>> +}
>> +
>> diff --git a/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c b/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c
>> index 21fdb79908b8..8819ebcfccef 100644
>> --- a/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c
>> +++ b/PcAtChipsetPkg/Library/AcpiTimerLib/BaseAcpiTimerLib.c
>> @@ -1,7 +1,7 @@
>> /** @file
>> ACPI Timer implements one instance of Timer Library.
>>
>> - Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> + Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
>> 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
>> @@ -17,6 +17,26 @@
>> #include <Library/BaseLib.h>
>>
>> /**
>> + Calculate TSC frequency.
>> +
>> + The TSC counting frequency is determined by comparing how far it counts
>> + during a 100us period as determined by the ACPI timer. The ACPI timer is
>> + used because it counts at a known frequency.
>> + The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
>> + clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
>> + difference multiplied by 10000 is the TSC frequency. There will be a small
>> + error because of the overhead of reading the ACPI timer. An attempt is
>> + made to determine and compensate for this error.
>> +
>> + @return The number of TSC counts per second.
>> +
>> +**/
>> +UINT64
>> +InternalCalculateTscFrequency (
>> + VOID
>> + );
>> +
>> +/**
>> Internal function to retrieves the 64-bit frequency in Hz.
>>
>> Internal function to retrieves the 64-bit frequency in Hz.
>> @@ -29,14 +49,5 @@ InternalGetPerformanceCounterFrequency (
>> VOID
>> )
>> {
>> - BOOLEAN InterruptState;
>> - UINT64 Count;
>> - UINT64 Frequency;
>> -
>> - InterruptState = SaveAndDisableInterrupts ();
>> - Count = GetPerformanceCounter ();
>> - MicroSecondDelay (100);
>> - Frequency = MultU64x32 (GetPerformanceCounter () - Count, 10000);
>> - SetInterruptState (InterruptState);
>> - return Frequency;
>> + return InternalCalculateTscFrequency ();
>> }
>> diff --git a/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c b/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c
>> index 6f5c07a4f0b4..7f7b0f8f6294 100644
>> --- a/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c
>> +++ b/PcAtChipsetPkg/Library/AcpiTimerLib/DxeAcpiTimerLib.c
>> @@ -1,7 +1,7 @@
>> /** @file
>> ACPI Timer implements one instance of Timer Library.
>>
>> - Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
>> + Copyright (c) 2013 - 2016, Intel Corporation. All rights reserved.<BR>
>> 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
>> @@ -16,6 +16,26 @@
>> #include <Library/TimerLib.h>
>> #include <Library/BaseLib.h>
>>
>> +/**
>> + Calculate TSC frequency.
>> +
>> + The TSC counting frequency is determined by comparing how far it counts
>> + during a 100us period as determined by the ACPI timer. The ACPI timer is
>> + used because it counts at a known frequency.
>> + The TSC is sampled, followed by waiting for ACPI_TIMER_FREQUENCY / 10000
>> + clocks of the ACPI timer, or 100us. The TSC is then sampled again. The
>> + difference multiplied by 10000 is the TSC frequency. There will be a small
>> + error because of the overhead of reading the ACPI timer. An attempt is
>> + made to determine and compensate for this error.
>> +
>> + @return The number of TSC counts per second.
>> +
>> +**/
>> +UINT64
>> +InternalCalculateTscFrequency (
>> + VOID
>> + );
>> +
>> //
>> // Cached performance counter frequency
>> //
>> @@ -34,15 +54,8 @@ InternalGetPerformanceCounterFrequency (
>> VOID
>> )
>> {
>> - BOOLEAN InterruptState;
>> - UINT64 Count;
>> -
>> if (mPerformanceCounterFrequency == 0) {
>> - InterruptState = SaveAndDisableInterrupts ();
>> - Count = GetPerformanceCounter ();
next prev parent reply other threads:[~2016-08-12 8:44 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2016-08-11 2:37 [PATCH] PcAtChipsetPkg AcpiTimerLib: Get more accurate TSC Frequency Star Zeng
2016-08-11 2:42 ` Gao, Liming
2016-08-11 5:01 ` Kinney, Michael D
2016-08-11 13:41 ` Brian J. Johnson
2016-08-12 1:07 ` Zeng, Star
2016-08-12 8:31 ` Paolo Bonzini
2016-08-12 8:43 ` Zeng, Star [this message]
2016-08-12 18:27 ` 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=aa0c0680-0916-6d1b-3e4b-5a254af361a9@intel.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