x86/tsc: Fix native_sched_clock()
Subsystems (2)
cover x86/tsc: Fix native_sched_clock()
Eric reported that native_sched_clock() gets miscompiled; we loose a seqcount loop. These patches cure that.
After these patches:
native_sched_clock:
pushq %rbp # movq %rsp, %rbp #, ... jump label ... rdtsc salq $32, %rdx #, tmp110 orq %rax, %rdx # low, tmp110 movq %rdx, %r10 # tmp110, _23 movq $cyc2ns, %r9 #, tmp136 .L235: movl %gs:cyc2ns+32(%rip),%eax # cyc2ns.seq.sequence, pfo_ret__ movl %eax, %ecx # pfo_ret__, idx andl $1, %ecx #, idx salq $4, %rcx #, tmp116 addq %r9, %rcx # tmp136, tmp117 movq %gs:8(%rcx),%rdi # cyc2ns.data[idx_14].cyc2ns_offset, pfo_ret__ movl %gs:(%rcx),%esi # cyc2ns.data[idx_14].cyc2ns_mul, pfo_ret__ movl %gs:4(%rcx),%ecx # cyc2ns.data[idx_14].cyc2ns_shift, pfo_ret__ movl %gs:cyc2ns+32(%rip),%r8d # cyc2ns.seq.sequence, pfo_ret__ cmpl %r8d, %eax # pfo_ret__, pfo_ret__ jne .L235 #, movl %esi, %esi # pfo_ret__, pfo_ret__ movq %rsi, %rax # pfo_ret__, tmp133 mulq %r10 # _23 shrdq %rdx, %rax # pfo_ret__,, tmp134 shrq %cl, %rdx # pfo_ret__, testb $64, %cl #, pfo_ret__ cmovne %rdx, %rax #,, tmp134 addq %rdi, %rax # pfo_ret__, <retval> popq %rbp # ret
PATCH 1/2 x86/tsc: Force inlining of cyc2ns bits
Looking at the asm for native_sched_clock() I noticed we don't inline enough. Mostly caused by sharing code with cyc2ns_read_begin(), which we didn't used to do. So mark all that __force_inline to make it DTRT.
--- arch/x86/kernel/tsc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/tsc.c +3 -3
@@ -57,7 +57,7 @@ struct cyc2ns { static DEFINE_PER_CPU_ALIGNED(struct cyc2ns, cyc2ns); -void cyc2ns_read_begin (struct cyc2ns_data *data) +void __always_inline cyc2ns_read_begin(struct cyc2ns_data *data) {int seq, idx;
@@ -74,7 +74,7 @@ void cyc2ns_read_begin(struct cyc2ns_dat }while (unlikely (seq !=this_cpu_read (cyc2ns.seq.sequence))); } -void cyc2ns_read_end (void ) +void __always_inline cyc2ns_read_end(void) {preempt_enable_notrace (); }
@@ -103,7 +103,7 @@ void cyc2ns_read_end(void)* [email protected] "math is hard, lets go shopping!" */ -static inline unsigned long long cycles_2_ns (unsigned long long cyc) +static __always_inline unsigned long long cycles_2_ns (unsigned long long cyc) {struct cyc2ns_data data;unsigned long long ns;
tip-bot for Peter Zijlstra
merge bot[tip:x86/urgent] x86/tsc: Force inlining of cyc2ns bits
x86/tsc: Force inlining of cyc2ns bits
Commit-ID: 4907c68abd3f60f650f98d5a69d4ec77c0bde44f Gitweb: https://git.kernel.org/tip/4907c68abd3f60f650f98d5a69d4ec77c0bde44f Author: Peter Zijlstra <[email protected]> AuthorDate: Thu, 11 Oct 2018 12:38:26 +0200 Committer: Thomas Gleixner <[email protected]> CommitDate: Sun, 14 Oct 2018 11:11:22 +0200
x86/tsc: Force inlining of cyc2ns bits
Looking at the asm for native_sched_clock() I noticed we don't inline enough. Mostly caused by sharing code with cyc2ns_read_begin(), which we didn't used to do. So mark all that __force_inline to make it DTRT.
--- arch/x86/kernel/tsc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
arch/x86/kernel/tsc.c +3 -3
@@ -58,7 +58,7 @@ struct cyc2ns { static DEFINE_PER_CPU_ALIGNED(struct cyc2ns, cyc2ns); -void cyc2ns_read_begin (struct cyc2ns_data *data) +void __always_inline cyc2ns_read_begin(struct cyc2ns_data *data) {int seq, idx;
@@ -75,7 +75,7 @@ void cyc2ns_read_begin(struct cyc2ns_data *data) }while (unlikely (seq !=this_cpu_read (cyc2ns.seq.sequence))); } -void cyc2ns_read_end (void ) +void __always_inline cyc2ns_read_end(void) {preempt_enable_notrace (); }
@@ -104,7 +104,7 @@ void cyc2ns_read_end(void)* [email protected] "math is hard, lets go shopping!" */ -static inline unsigned long long cycles_2_ns (unsigned long long cyc) +static __always_inline unsigned long long cycles_2_ns (unsigned long long cyc) {struct cyc2ns_data data;unsigned long long ns;
PATCH 2/2 x86/percpu: Fix this_cpu_read()
In reply to Peter ZijlstraEric reported that a sequence count loop using this_cpu_read() got optimized out. This is wrong, this_cpu_read() must imply READ_ONCE() because the interface is IRQ-safe, therefore an interrupt can have changed the per-cpu value.
--- arch/x86/include/asm/percpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/percpu.h +4 -4
@@ -185,22 +185,22 @@ do { \typeof (var) pfo_ret__; \switch (sizeof (var)) { \case 1 : \ - asm(op "b "__percpu_arg(1)",%0" \ + asm volatile(op "b "__percpu_arg(1)",%0"\ : "=q" (pfo_ret__) \ : "m" (var)); \ break; \ case 2: \ - asm(op "w "__percpu_arg(1)",%0" \ + asm volatile(op "w "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 4: \ - asm(op "l "__percpu_arg(1)",%0" \ + asm volatile(op "l "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 8: \ - asm(op "q "__percpu_arg(1)",%0" \ + asm volatile(op "q "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \: " m" (var)); \ break; \
Re: [PATCH 2/2] x86/percpu: Fix this_cpu_read()
Quoted 9 lines · Peter Zijlstra
Eric reported that a sequence count loop using
this_cpu_read()got optimized out. This is wrong,this_cpu_read()must implyREAD_ONCE()because the interface is IRQ-safe, therefore an interrupt can have changed the per-cpu value.Fixes 59eaef78bfea ("x86/tsc: Remodel cyc2ns to use seqcount_latch()")Reported-by Eric Dumazet <[email protected]>Signed-off-by Peter Zijlstra (Intel) <[email protected]>
Quoted 35 lines
--- arch/x86/include/asm/percpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)arch/x86/include/asm/percpu.h +4
-4@@ -185,22 +185,22 @@ do { \typeof (var) pfo_ret__; \switch (sizeof (var)) { \case 1 : \ - asm(op "b "__percpu_arg(1)",%0" \ + asm volatile(op "b "__percpu_arg(1)",%0"\ : "=q" (pfo_ret__) \ : "m" (var)); \ break; \ case 2: \ - asm(op "w "__percpu_arg(1)",%0" \ + asm volatile(op "w "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 4: \ - asm(op "l "__percpu_arg(1)",%0" \ + asm volatile(op "l "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 8: \ - asm(op "q "__percpu_arg(1)",%0" \ + asm volatile(op "q "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \: " m" (var)); \ break; \
Re: [PATCH 2/2] x86/percpu: Fix this_cpu_read()
Quoted 8 lines · Eric Dumazet
Quoted 6 lines · Peter Zijlstra
Eric reported that a sequence count loop using
this_cpu_read()got optimized out. This is wrong,this_cpu_read()must implyREAD_ONCE()because the interface is IRQ-safe, therefore an interrupt can have changed the per-cpu value.
Quoted 6 lines
Quoted 3 lines
Fixes 59eaef78bfea ("x86/tsc: Remodel cyc2ns to use seqcount_latch()")Reported-by Eric Dumazet <[email protected]>Signed-off-by Peter Zijlstra (Intel) <[email protected]>Acked-by Eric Dumazet <[email protected]>
Actually the Fixes: tag seems funky.
Bug was not added by 59eaef78bfea
Your patch probably needs to be backported to older versions of linux, just to be safe, since
we might have other places where authors relied on this_cpu_read() semantic (different than this_cpu_read_stable())
Re: [PATCH 2/2] x86/percpu: Fix this_cpu_read()
Quoted 16 lines · Eric Dumazet
Quoted 8 lines · Eric Dumazet
Quoted 6 lines · Peter Zijlstra
Eric reported that a sequence count loop using
this_cpu_read()got optimized out. This is wrong,this_cpu_read()must implyREAD_ONCE()because the interface is IRQ-safe, therefore an interrupt can have changed the per-cpu value.Quoted 6 lines
Quoted 3 lines
Fixes 59eaef78bfea ("x86/tsc: Remodel cyc2ns to use seqcount_latch()")Reported-by Eric Dumazet <[email protected]>Signed-off-by Peter Zijlstra (Intel) <[email protected]>Acked-by Eric Dumazet <[email protected]>
Quoted 8 lines
Actually the Fixes: tag seems funky.
Bug was not added by
59eaef78bfeaYour patch probably needs to be backported to older versions of linux, just to be safe, since
we might have other places where authors relied onthis_cpu_read()semantic (different thanthis_cpu_read_stable())
Right; it goes back a long long way... is:
7c3576d261ce ("[PATCH] i386: Convert PDA into the percpu section")
early enough? That introduces percpu_from_op(), but arguably the pda_from_op() it replaces was buggy already.
Re: [PATCH 2/2] x86/percpu: Fix this_cpu_read()
Quoted 6 lines · Peter Zijlstra
Right; it goes back a long long way... is:
7c3576d261ce("[PATCH] i386: Convert PDA into the percpu section")early enough? That introduces
percpu_from_op(), but arguably thepda_from_op()it replaces was buggy already.
Yeah I guess all stable versions would need a fix anyway, so this tag would suffice,
even if bug was older.
tip-bot for Peter Zijlstra
merge bot[tip:x86/urgent] x86/percpu: Fix this_cpu_read()
In reply to Peter Zijlstrax86/percpu: Fix this_cpu_read()
Commit-ID: b59167ac7bafd804c91e49ad53c6d33a7394d4c8 Gitweb: https://git.kernel.org/tip/b59167ac7bafd804c91e49ad53c6d33a7394d4c8 Author: Peter Zijlstra <[email protected]> AuthorDate: Thu, 11 Oct 2018 12:38:27 +0200 Committer: Thomas Gleixner <[email protected]> CommitDate: Sun, 14 Oct 2018 11:11:22 +0200
x86/percpu: Fix this_cpu_read()
Eric reported that a sequence count loop using this_cpu_read() got optimized out. This is wrong, this_cpu_read() must imply READ_ONCE() because the interface is IRQ-safe, therefore an interrupt can have changed the per-cpu value.
--- arch/x86/include/asm/percpu.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/x86/include/asm/percpu.h +4 -4
@@ -185,22 +185,22 @@ do { \typeof (var) pfo_ret__; \switch (sizeof (var)) { \case 1 : \ - asm(op "b "__percpu_arg(1)",%0" \ + asm volatile(op "b "__percpu_arg(1)",%0"\ : "=q" (pfo_ret__) \ : "m" (var)); \ break; \ case 2: \ - asm(op "w "__percpu_arg(1)",%0" \ + asm volatile(op "w "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 4: \ - asm(op "l "__percpu_arg(1)",%0" \ + asm volatile(op "l "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \ : "m" (var)); \ break; \ case 8: \ - asm(op "q "__percpu_arg(1)",%0" \ + asm volatile(op "q "__percpu_arg(1)",%0"\ : "=r" (pfo_ret__) \: " m" (var)); \ break; \