reduce TSC deadline frequency errors
v4 cover reduce TSC deadline frequency errors
The v3 series can be found at
http://lkml.kernel.org/g/[email protected]
Applicable to linux-next-20160708 (in case you wonder why I turned back from the 20160712 given in v3 to 20160708 again: mysteriously, 20160712 doesn't boot neither w/ nor w/o this series anymore).
The individual patches don't depend on each other.
Changes to v3:
As Paolo Bonzini pointed out in reply to v3, for the values of 2, 4 and 8 of TSC_DIVISOR, the 64 bit division
(u32)(((u64)tsc_khz * 1000) / TSC_DIVISOR)
can be safely turned into a 32 bit division by changing associativity:
tsc_khz * (1000 / TSC_DIVISOR) In doing so, it suggests itself to squash former [1/3] ("arch, x86, tsc deadline clockevent dev: reduce frequency roundoff error") and [2/3] ("arch, x86, tsc deadline clockevent dev: reduce TSC_DIVISOR to 2") into a single patch. Furthermore, reducing TSC_DIVISOR down to 2 becomes unnessecary -- setting it to 8 suffices already.
Thus,
- [1/2] ("arch, x86, tsc deadline clockevent dev: eliminate frequency roundoff error")
Former [1/3] and [2/3] squashed together. Don't reduce TSC_DIVISOR to 2 but to 8 only. Change associativity in order to get rid of the 64 bit division. Adapt the commit message accordingly.
- [2/2] ("arch, x86, tsc: inform TSC deadline clockevent device about recalibration")
Former [3/3]. Likewise change associativity in order to get rid of the 64 bit division here, too.
Changes to v2:
- [3/3] ("arch, x86, tsc: inform TSC deadline clockevent device about recalibration")
Use clockevents_update_freq() rather than clockevents_config().
- Former [4/4] ("kernel/time/clockevents: compensate for monotonic clock's dynamic frequency")
Split off, not a member of this series anymore.
Changes to v1:
- [1/3] ("arch, x86, tsc deadline clockevent dev: reduce frequency roundoff error")
No changes to the patch. Note that the v1 mail could not be delivered to the author of the TSC_DIVISOR introducing commit 279f1461432c ("x86: apic: Use tsc deadline for oneshot when available"), Suresh Siddha <[email protected]>, so I had to remove him from the CC list.
- [2/3] ("arch, x86, tsc deadline clockevent dev: reduce TSC_DIVISOR
to 2")
Likewise. - [3/3] ("arch, x86, tsc: inform TSC deadline clockevent device about recalibration")
Silence the kbuild test robot on ARCH=i386 by wrapping the new call to lapic_update_tsc_freq() from arch/x86/kernel/tsc.c in an #ifdef CONFIG_X86_LOCAL_APIC.
Nicolai Stange (2):
arch, x86, tsc deadline clockevent dev: eliminate frequency roundoff
error
arch, x86, tsc: inform TSC deadline clockevent device about
recalibration
arch/x86/include/asm/apic.h | 1 + arch/x86/kernel/apic/apic.c | 28 ++++++++++++++++++++++++++-- arch/x86/kernel/tsc.c | 6 ++++++ 3 files changed, 33 insertions(+), 2 deletions(-)
Signature · 1 line
2.9.0
PATCH v4 1/2 arch, x86, tsc deadline clockevent dev: eliminate frequency roundoff error
In setup_APIC_timer(), the registered clockevent device's frequency is calculated by first dividing tsc_khz by TSC_DIVISOR and multiplying it with 1000 afterwards:
(tsc_khz / TSC_DIVISOR) * 1000
The multiplication with 1000 is done for converting from kHz to Hz and the division by TSC_DIVISOR is carried out in order to make sure that the final result fits into an u32.
However, with the order given in this calculation, the roundoff error introduced by the division gets magnified by a factor of 1000 by the following multiplication. Thus, reversing the order of the division and the multiplication a la
(tsc_khz * 1000) / TSC_DIVISOR
reduces the roundoff error already.
Furthermore, if TSC_DIVISOR divides 1000, associativity holds
(tsc_khz * 1000) / TSC_DIVISOR = tsc_khz * (1000 / TSC_DIVISOR)
and thus, the roundoff error even vanishes and the whole operation can be carried out within 32 bits.
The powers of two that divide 1000 are 2, 4 and 8. A value of 8 for TSC_DIVISOR still allows for TSC frequencies up to
2^32 / 10^9ns * 8 = 34.4GHz which is way larger than anything to expect in the next years.
Thus, replace the current TSC_DIVISOR value of 32 by 8. Reverse the order of the divison and the multiplication in the calculation of the registered clockevent device's frequency.
--- arch/x86/kernel/apic/apic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/apic.c +2 -2
@@ -311,7 +311,7 @@ int lapic_get_maxlvt(void)/* Clock divisor */ #define APIC_DIVISOR 16 -#define TSC_DIVISOR 32 +#define TSC_DIVISOR 8/* * This function sets up the local APIC timer, with a timeout of
@@ -563,7 +563,7 @@ static void setup_APIC_timer(void) CLOCK_EVT_FEAT_DUMMY); levt->set_next_event = lapic_next_deadline;clockevents_config_and_register (levt, - (tsc_khz /TSC_DIVISOR ) *1000 , + tsc_khz * (1000 /TSC_DIVISOR ),0xF , ~0UL ); }else clockevents_register_device (levt);
Signature · 1 line
2.9.0
Re: [PATCH v4 1/2] arch, x86, tsc deadline clockevent dev: eliminate frequency roundoff error
Quoted 55 lines · Nicolai Stange
In
setup_APIC_timer(), the registered clockevent device's frequency is calculated by first dividingtsc_khzbyTSC_DIVISORand multiplying it with 1000 afterwards:(
tsc_khz/TSC_DIVISOR) * 1000The multiplication with 1000 is done for converting from kHz to Hz and the division by
TSC_DIVISORis carried out in order to make sure that the final result fits into an u32.However, with the order given in this calculation, the roundoff error introduced by the division gets magnified by a factor of 1000 by the following multiplication. Thus, reversing the order of the division and the multiplication a la
(
tsc_khz* 1000) /TSC_DIVISORreduces the roundoff error already.
Furthermore, if
TSC_DIVISORdivides 1000, associativity holds(
tsc_khz* 1000) /TSC_DIVISOR=tsc_khz* (1000 /TSC_DIVISOR)and thus, the roundoff error even vanishes and the whole operation can be carried out within 32 bits.
The powers of two that divide 1000 are 2, 4 and 8. A value of 8 for
TSC_DIVISORstill allows for TSC frequencies up to
2^32 / 10^9ns * 8 = 34.4GHz which is way larger than anything to expect in the next years.Thus, replace the current
TSC_DIVISORvalue of 32 by 8. Reverse the order of the divison and the multiplication in the calculation of the registered clockevent device's frequency.Signed-off-by Nicolai Stange <[email protected]>--- arch/x86/kernel/apic/apic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kernel/apic/apic.c +1
-1@@ -311,7 +311,7 @@ int lapic_get_maxlvt(void)/* Clock divisor */ #define APIC_DIVISOR 16 -#define TSC_DIVISOR 32 +#define TSC_DIVISOR 8/* * This function sets up the local APIC timer, with a timeout of
arch/x86/kernel/apic/apic.c static void setup_APIC_timer(void) · line 569
Quoted 8 lines
arch/x86/kernel/apic/apic.c +1
-1@@ -563,7 +563,7 @@ static void setup_APIC_timer(void) CLOCK_EVT_FEAT_DUMMY); levt->set_next_event = lapic_next_deadline;clockevents_config_and_register (levt, - (tsc_khz /TSC_DIVISOR ) *1000 , + tsc_khz * (1000 /TSC_DIVISOR ),0xF , ~0UL ); }else clockevents_register_device (levt);
and I suggest even CCing this to stable as it's pretty safe and an improvement.
Paolo
Re: [PATCH v4 1/2] arch, x86, tsc deadline clockevent dev: eliminate frequency roundoff error
Quoted 52 lines · Paolo Bonzini
Quoted 51 lines · Nicolai Stange
In
setup_APIC_timer(), the registered clockevent device's frequency is calculated by first dividingtsc_khzbyTSC_DIVISORand multiplying it with 1000 afterwards:(
tsc_khz/TSC_DIVISOR) * 1000The multiplication with 1000 is done for converting from kHz to Hz and the division by
TSC_DIVISORis carried out in order to make sure that the final result fits into an u32.However, with the order given in this calculation, the roundoff error introduced by the division gets magnified by a factor of 1000 by the following multiplication. Thus, reversing the order of the division and the multiplication a la
(
tsc_khz* 1000) /TSC_DIVISORreduces the roundoff error already.
Furthermore, if
TSC_DIVISORdivides 1000, associativity holds(
tsc_khz* 1000) /TSC_DIVISOR=tsc_khz* (1000 /TSC_DIVISOR)and thus, the roundoff error even vanishes and the whole operation can be carried out within 32 bits.
The powers of two that divide 1000 are 2, 4 and 8. A value of 8 for
TSC_DIVISORstill allows for TSC frequencies up to
2^32 / 10^9ns * 8 = 34.4GHz which is way larger than anything to expect in the next years.Thus, replace the current
TSC_DIVISORvalue of 32 by 8. Reverse the order of the divison and the multiplication in the calculation of the registered clockevent device's frequency.Signed-off-by Nicolai Stange <[email protected]>--- arch/x86/kernel/apic/apic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)arch/x86/kernel/apic/apic.c +1
-1@@ -311,7 +311,7 @@ int lapic_get_maxlvt(void)/* Clock divisor */ #define APIC_DIVISOR 16 -#define TSC_DIVISOR 32 +#define TSC_DIVISOR 8
Quoted 14 lines
arch/x86/kernel/apic/apic.c static void setup_APIC_timer(void) · line 569
Quoted 12 lines
arch/x86/kernel/apic/apic.c +1
-1/* * This function sets up the local APIC timer, with a timeout of @@ -563,7 +563,7 @@ static void setup_APIC_timer(void) CLOCK_EVT_FEAT_DUMMY); levt->set_next_event = lapic_next_deadline;clockevents_config_and_register (levt, - (tsc_khz /TSC_DIVISOR ) *1000 , + tsc_khz * (1000 /TSC_DIVISOR ),0xF , ~0UL ); }else clockevents_register_device (levt);Reviewed-by Paolo Bonzini <[email protected]>
Thank you very much!
Quoted 2 lines
and I suggest even CCing this to stable as it's pretty safe and an improvement.
I've just collected both, the "coarse" TSC frequencies obtained through the PIT calibration as well as the "refined" TSC frequencies across 1000 boots (CPU: Intel i7-4800MQ, Haswell).
My interpretation of the outcome is that the application of this patch alone (i.e. w/o [2/2] "arch, x86, tsc: inform TSC deadline clockevent device about recalibration") is not only worthless but has the potential for making things worse.
1. Worthlessness
The "coarse" TSC frequency's mean is 2693.801 MHz with a standard deviation of 122 kHz. Given that this patch changes the outcome by at most 31kHz (15.5 kHz on average), the error corrected is relatively small when compared to the standard deviation.
2. Potential for making things worse
Note that this patch never decreases frequency values. The roundoff error fixed by this patch turns the "coarse" frequency mean of 2693.801 MHz into 2693.785 MHz. This errorneous value is significantly closer to the "refined" frequency's mean of 2693.773 MHz (sdev: 5.8 kHz). Thus, the two errors addressed by this series' two patches seem to be of opposite direction on average and cancel each other to some extent -> picking only one of the two makes the frequency bias worse on average.
So, since it is unlikely that [2/2] ("arch, x86, tsc: inform TSC deadline clockevent device about recalibration") is considered safe enough for inclusion into -stable, I'd recommend not to send this one (i.e. [1/2]) to stable either.
Thanks,
Nicolai
tip-bot for Nicolai Stange
merge bot[tip:timers/urgent] x86/timers/apic: Fix imprecise timer interrupts by eliminating TSC clockevents frequency roundoff error
In reply to Nicolai Stangex86/timers/apic: Fix imprecise timer interrupts by eliminating TSC clockevents frequency roundoff error
Commit-ID: 1a9e4c564ab174e53ed86def922804a5ddc63e7d Gitweb: http://git.kernel.org/tip/1a9e4c564ab174e53ed86def922804a5ddc63e7d Author: Nicolai Stange <[email protected]> AuthorDate: Thu, 14 Jul 2016 17:22:54 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 10 Aug 2016 12:37:38 +0200
x86/timers/apic: Fix imprecise timer interrupts by eliminating TSC clockevents frequency roundoff error
I noticed the following bug/misbehavior on certain Intel systems: with a single task running on a NOHZ CPU on an Intel Haswell, I recognized that I did not only get the one expected local_timer APIC interrupt, but two per second at minimum. (!)
Further tracing showed that the first one precedes the programmed deadline by up to ~50us and hence, it did nothing except for reprogramming the TSC deadline clockevent device to trigger shortly thereafter again.
The reason for this is imprecise calibration, the timeout we program into the APIC results in 'too short' timer interrupts. The core (hr)timer code notices this (because it has a precise ktime source and sees the short interrupt) and fixes it up by programming an additional very short interrupt period.
This is obviously suboptimal.
The reason for the imprecise calibration is twofold, and this patch fixes the first reason:
In setup_APIC_timer(), the registered clockevent device's frequency is calculated by first dividing tsc_khz by TSC_DIVISOR and multiplying it with 1000 afterwards:
(tsc_khz / TSC_DIVISOR) * 1000
The multiplication with 1000 is done for converting from kHz to Hz and the division by TSC_DIVISOR is carried out in order to make sure that the final result fits into an u32.
However, with the order given in this calculation, the roundoff error introduced by the division gets magnified by a factor of 1000 by the following multiplication.
To fix it, reversing the order of the division and the multiplication a la:
(tsc_khz * 1000) / TSC_DIVISOR
... reduces the roundoff error already.
Furthermore, if TSC_DIVISOR divides 1000, associativity holds:
(tsc_khz * 1000) / TSC_DIVISOR = tsc_khz * (1000 / TSC_DIVISOR)
and thus, the roundoff error even vanishes and the whole operation can be carried out within 32 bits.
The powers of two that divide 1000 are 2, 4 and 8. A value of 8 for TSC_DIVISOR still allows for TSC frequencies up to
2^32 / 10^9ns * 8 = 34.4GHz which is way larger than anything to expect in the next years.
Thus we also replace the current TSC_DIVISOR value of 32 by 8. Reverse the order of the divison and the multiplication in the calculation of the registered clockevent device's frequency.
--- arch/x86/kernel/apic/apic.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
arch/x86/kernel/apic/apic.c +2 -2
@@ -313,7 +313,7 @@ int lapic_get_maxlvt(void)/* Clock divisor */ #define APIC_DIVISOR 16 -#define TSC_DIVISOR 32 +#define TSC_DIVISOR 8/* * This function sets up the local APIC timer, with a timeout of
@@ -565,7 +565,7 @@ static void setup_APIC_timer(void) CLOCK_EVT_FEAT_DUMMY); levt->set_next_event = lapic_next_deadline;clockevents_config_and_register (levt, - (tsc_khz /TSC_DIVISOR ) *1000 , + tsc_khz * (1000 /TSC_DIVISOR ),0xF , ~0UL ); }else clockevents_register_device (levt);
PATCH v4 2/2 arch, x86, tsc: inform TSC deadline clockevent device about recalibration
In reply to Nicolai StangeThe TSC deadline clockevent devices' configuration and registration happens before the TSC frequency calibration is refined in tsc_refine_calibration_work().
This results in the TSC clocksource and the TSC deadline clockevent devices being configured with slightly different frequencies: the former gets the refined one and the latter are configured with the inaccurate frequency detected earlier by means of the
"Fast TSC calibration using PIT".
Within the APIC code, introduce the notifier function lapic_update_tsc_freq() which reconfigures all per-CPU TSC deadline clockevent devices with the current tsc_khz.
Call it from the TSC code after TSC calibration refinement has happened.
--- arch/x86/include/asm/apic.h | 1 + arch/x86/kernel/apic/apic.c | 24 ++++++++++++++++++++++++ arch/x86/kernel/tsc.c | 6 ++++++ 3 files changed, 31 insertions(+)
arch/x86/include/asm/apic.h +1 -0
@@ -135,6 +135,7 @@ extern void init_apic_mappings(void);void register_lapic_address (unsigned long address);extern void setup_boot_APIC_clock (void );extern void setup_secondary_APIC_clock (void ); +extern void lapic_update_tsc_freq (void );extern int APIC_init_uniprocessor (void );#ifdef CONFIG_X86_64
arch/x86/kernel/apic/apic.c +24 -0
@@ -570,6 +570,30 @@ static void setup_APIC_timer(void) }/* +* Install the updated TSC frequency from recalibration at the TSC +* deadline clockevent devices. +*/ +static void __lapic_update_tsc_freq (void *info) +{ +struct clock_event_device *levt =this_cpu_ptr (&lapic_events); + +if (!this_cpu_has (X86_FEATURE_TSC_DEADLINE_TIMER )) +return ; + +clockevents_update_freq (levt, tsc_khz * (1000 /TSC_DIVISOR )); +} + +void lapic_update_tsc_freq (void ) +{ +/* +* The clockevent device's ->mult and ->shift can both be +* changed. In order to avoid races, schedule the frequency +* update code on each CPU. +*/ +on_each_cpu (__lapic_update_tsc_freq,NULL ,0 ); +} + +/* * In this functions we calibrate APIC bus clocks to the external timer. * * We want to do the calibration only once since we want to have local timer
arch/x86/kernel/tsc.c +6 -0
@@ -22,6 +22,7 @@#include <asm/nmi.h> #include <asm/x86_init.h> #include <asm/geode.h> +#include <asm/apic.h> unsigned int __read_mostly cpu_khz;/* TSC clocks / usec, not used here */ EXPORT_SYMBOL (cpu_khz);
@@ -1193,6 +1194,11 @@ static void tsc_refine_calibration_work(struct work_struct *work) (unsigned long )tsc_khz /1000 , (unsigned long)tsc_khz % 1000); +#ifdef CONFIG_X86_LOCAL_APIC +/* Inform the TSC deadline clockevent devices about the recalibration */ +lapic_update_tsc_freq (); +#endif + out:if (boot_cpu_has (X86_FEATURE_ART )) art_related_clocksource = &clocksource_tsc;
Signature · 1 line
2.9.0
tip-bot for Nicolai Stange
merge bot[tip:timers/urgent] x86/timers/apic: Inform TSC deadline clockevent device about recalibration
x86/timers/apic: Inform TSC deadline clockevent device about recalibration
Commit-ID: 6731b0d611a1274f9e785fa0189ac2aeeabd0591 Gitweb: http://git.kernel.org/tip/6731b0d611a1274f9e785fa0189ac2aeeabd0591 Author: Nicolai Stange <[email protected]> AuthorDate: Thu, 14 Jul 2016 17:22:55 +0200 Committer: Ingo Molnar <[email protected]> CommitDate: Wed, 10 Aug 2016 12:38:12 +0200
x86/timers/apic: Inform TSC deadline clockevent device about recalibration
This patch eliminates a source of imprecise APIC timer interrupts, which imprecision may result in double interrupts or even late interrupts.
The TSC deadline clockevent devices' configuration and registration happens before the TSC frequency calibration is refined in tsc_refine_calibration_work().
This results in the TSC clocksource and the TSC deadline clockevent devices being configured with slightly different frequencies: the former gets the refined one and the latter are configured with the inaccurate frequency detected earlier by means of the "Fast TSC calibration using PIT".
Within the APIC code, introduce the notifier function lapic_update_tsc_freq() which reconfigures all per-CPU TSC deadline clockevent devices with the current tsc_khz.
Call it from the TSC code after TSC calibration refinement has happened.
--- arch/x86/include/asm/apic.h | 2 ++ arch/x86/kernel/apic/apic.c | 24 ++++++++++++++++++++++++ arch/x86/kernel/tsc.c | 4 ++++ 3 files changed, 30 insertions(+)
arch/x86/include/asm/apic.h +2 -0
@@ -135,6 +135,7 @@ extern void init_apic_mappings(void);void register_lapic_address (unsigned long address);extern void setup_boot_APIC_clock (void );extern void setup_secondary_APIC_clock (void ); +extern void lapic_update_tsc_freq (void );extern int APIC_init_uniprocessor (void );#ifdef CONFIG_X86_64
@@ -170,6 +171,7 @@ static inline void init_apic_mappings(void) { }static inline void disable_local_APIC (void ) { }# define setup_boot_APIC_clock x86_init_noop# define setup_secondary_APIC_clock x86_init_noop +static inline void lapic_update_tsc_freq (void ) { }#endif /* !CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_X2APIC
arch/x86/kernel/apic/apic.c +24 -0
@@ -572,6 +572,30 @@ static void setup_APIC_timer(void) }/* +* Install the updated TSC frequency from recalibration at the TSC +* deadline clockevent devices. +*/ +static void __lapic_update_tsc_freq (void *info) +{ +struct clock_event_device *levt =this_cpu_ptr (&lapic_events); + +if (!this_cpu_has (X86_FEATURE_TSC_DEADLINE_TIMER )) +return ; + +clockevents_update_freq (levt, tsc_khz * (1000 /TSC_DIVISOR )); +} + +void lapic_update_tsc_freq (void ) +{ +/* +* The clockevent device's ->mult and ->shift can both be +* changed. In order to avoid races, schedule the frequency +* update code on each CPU. +*/ +on_each_cpu (__lapic_update_tsc_freq,NULL ,0 ); +} + +/* * In this functions we calibrate APIC bus clocks to the external timer. * * We want to do the calibration only once since we want to have local timer
arch/x86/kernel/tsc.c +4 -0
@@ -22,6 +22,7 @@#include <asm/nmi.h> #include <asm/x86_init.h> #include <asm/geode.h> +#include <asm/apic.h> unsigned int __read_mostly cpu_khz;/* TSC clocks / usec, not used here */ EXPORT_SYMBOL (cpu_khz);
@@ -1249,6 +1250,9 @@ static void tsc_refine_calibration_work(struct work_struct *work) (unsigned long )tsc_khz /1000 , (unsigned long)tsc_khz % 1000); +/* Inform the TSC deadline clockevent devices about the recalibration */ +lapic_update_tsc_freq (); + out:if (boot_cpu_has (X86_FEATURE_ART )) art_related_clocksource = &clocksource_tsc;