diff options
author | Dave Hansen <dave.hansen@linux.intel.com> | 2016-06-01 13:42:20 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@kernel.org> | 2016-06-08 07:33:33 -0400 |
commit | d1898b733619bd46194bd25aa6452d238ff2dc4e (patch) | |
tree | 4cc10df3594b68becae9a7dac03e35025aa5c7d1 | |
parent | c8ae067f2635be0f8c7e5db1bb74b757d623e05b (diff) |
x86/fpu: Add tracepoints to dump FPU state at key points
I've been carrying this patch around for a bit and it's helped me
solve at least a couple FPU-related bugs. In addition to using
it for debugging, I also drug it out because using AVX (and
AVX2/AVX-512) can have serious power consequences for a modern
core. It's very important to be able to figure out who is using
it.
It's also insanely useful to go out and see who is using a given
feature, like MPX or Memory Protection Keys. If you, for
instance, want to find all processes using protection keys, you
can do:
echo 'xfeatures & 0x200' > filter
Since 0x200 is the protection keys feature bit.
Note that this touches the KVM code. KVM did a CREATE_TRACE_POINTS
and then included a bunch of random headers. If anyone one of
those included other tracepoints, it would have defined the *OTHER*
tracepoints. That's bogus, so move it to the right place.
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Cc: Andy Lutomirski <luto@amacapital.net>
Cc: Borislav Petkov <bp@alien8.de>
Cc: Brian Gerst <brgerst@gmail.com>
Cc: Dave Hansen <dave@sr71.net>
Cc: Denys Vlasenko <dvlasenk@redhat.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: H. Peter Anvin <hpa@zytor.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Oleg Nesterov <oleg@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Quentin Casasnovas <quentin.casasnovas@oracle.com>
Cc: Steven Rostedt <rostedt@goodmis.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/20160601174220.3CDFB90E@viggo.jf.intel.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r-- | arch/x86/include/asm/fpu/internal.h | 5 | ||||
-rw-r--r-- | arch/x86/include/asm/trace/fpu.h | 119 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/core.c | 18 | ||||
-rw-r--r-- | arch/x86/kernel/fpu/signal.c | 3 | ||||
-rw-r--r-- | arch/x86/kvm/x86.c | 6 |
5 files changed, 148 insertions, 3 deletions
diff --git a/arch/x86/include/asm/fpu/internal.h b/arch/x86/include/asm/fpu/internal.h index 31ac8e6d9f36..116b58347501 100644 --- a/arch/x86/include/asm/fpu/internal.h +++ b/arch/x86/include/asm/fpu/internal.h | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/fpu/api.h> | 18 | #include <asm/fpu/api.h> |
19 | #include <asm/fpu/xstate.h> | 19 | #include <asm/fpu/xstate.h> |
20 | #include <asm/cpufeature.h> | 20 | #include <asm/cpufeature.h> |
21 | #include <asm/trace/fpu.h> | ||
21 | 22 | ||
22 | /* | 23 | /* |
23 | * High level FPU state handling functions: | 24 | * High level FPU state handling functions: |
@@ -524,6 +525,7 @@ static inline void __fpregs_deactivate(struct fpu *fpu) | |||
524 | 525 | ||
525 | fpu->fpregs_active = 0; | 526 | fpu->fpregs_active = 0; |
526 | this_cpu_write(fpu_fpregs_owner_ctx, NULL); | 527 | this_cpu_write(fpu_fpregs_owner_ctx, NULL); |
528 | trace_x86_fpu_regs_deactivated(fpu); | ||
527 | } | 529 | } |
528 | 530 | ||
529 | /* Must be paired with a 'clts' (fpregs_activate_hw()) before! */ | 531 | /* Must be paired with a 'clts' (fpregs_activate_hw()) before! */ |
@@ -533,6 +535,7 @@ static inline void __fpregs_activate(struct fpu *fpu) | |||
533 | 535 | ||
534 | fpu->fpregs_active = 1; | 536 | fpu->fpregs_active = 1; |
535 | this_cpu_write(fpu_fpregs_owner_ctx, fpu); | 537 | this_cpu_write(fpu_fpregs_owner_ctx, fpu); |
538 | trace_x86_fpu_regs_activated(fpu); | ||
536 | } | 539 | } |
537 | 540 | ||
538 | /* | 541 | /* |
@@ -604,11 +607,13 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu) | |||
604 | 607 | ||
605 | /* But leave fpu_fpregs_owner_ctx! */ | 608 | /* But leave fpu_fpregs_owner_ctx! */ |
606 | old_fpu->fpregs_active = 0; | 609 | old_fpu->fpregs_active = 0; |
610 | trace_x86_fpu_regs_deactivated(old_fpu); | ||
607 | 611 | ||
608 | /* Don't change CR0.TS if we just switch! */ | 612 | /* Don't change CR0.TS if we just switch! */ |
609 | if (fpu.preload) { | 613 | if (fpu.preload) { |
610 | new_fpu->counter++; | 614 | new_fpu->counter++; |
611 | __fpregs_activate(new_fpu); | 615 | __fpregs_activate(new_fpu); |
616 | trace_x86_fpu_regs_activated(new_fpu); | ||
612 | prefetch(&new_fpu->state); | 617 | prefetch(&new_fpu->state); |
613 | } else { | 618 | } else { |
614 | __fpregs_deactivate_hw(); | 619 | __fpregs_deactivate_hw(); |
diff --git a/arch/x86/include/asm/trace/fpu.h b/arch/x86/include/asm/trace/fpu.h new file mode 100644 index 000000000000..9217ab1f5bf6 --- /dev/null +++ b/arch/x86/include/asm/trace/fpu.h | |||
@@ -0,0 +1,119 @@ | |||
1 | #undef TRACE_SYSTEM | ||
2 | #define TRACE_SYSTEM x86_fpu | ||
3 | |||
4 | #if !defined(_TRACE_FPU_H) || defined(TRACE_HEADER_MULTI_READ) | ||
5 | #define _TRACE_FPU_H | ||
6 | |||
7 | #include <linux/tracepoint.h> | ||
8 | |||
9 | DECLARE_EVENT_CLASS(x86_fpu, | ||
10 | TP_PROTO(struct fpu *fpu), | ||
11 | TP_ARGS(fpu), | ||
12 | |||
13 | TP_STRUCT__entry( | ||
14 | __field(struct fpu *, fpu) | ||
15 | __field(bool, fpregs_active) | ||
16 | __field(bool, fpstate_active) | ||
17 | __field(int, counter) | ||
18 | __field(u64, xfeatures) | ||
19 | __field(u64, xcomp_bv) | ||
20 | ), | ||
21 | |||
22 | TP_fast_assign( | ||
23 | __entry->fpu = fpu; | ||
24 | __entry->fpregs_active = fpu->fpregs_active; | ||
25 | __entry->fpstate_active = fpu->fpstate_active; | ||
26 | __entry->counter = fpu->counter; | ||
27 | if (boot_cpu_has(X86_FEATURE_OSXSAVE)) { | ||
28 | __entry->xfeatures = fpu->state.xsave.header.xfeatures; | ||
29 | __entry->xcomp_bv = fpu->state.xsave.header.xcomp_bv; | ||
30 | } | ||
31 | ), | ||
32 | TP_printk("x86/fpu: %p fpregs_active: %d fpstate_active: %d counter: %d xfeatures: %llx xcomp_bv: %llx", | ||
33 | __entry->fpu, | ||
34 | __entry->fpregs_active, | ||
35 | __entry->fpstate_active, | ||
36 | __entry->counter, | ||
37 | __entry->xfeatures, | ||
38 | __entry->xcomp_bv | ||
39 | ) | ||
40 | ); | ||
41 | |||
42 | DEFINE_EVENT(x86_fpu, x86_fpu_state, | ||
43 | TP_PROTO(struct fpu *fpu), | ||
44 | TP_ARGS(fpu) | ||
45 | ); | ||
46 | |||
47 | DEFINE_EVENT(x86_fpu, x86_fpu_before_save, | ||
48 | TP_PROTO(struct fpu *fpu), | ||
49 | TP_ARGS(fpu) | ||
50 | ); | ||
51 | |||
52 | DEFINE_EVENT(x86_fpu, x86_fpu_after_save, | ||
53 | TP_PROTO(struct fpu *fpu), | ||
54 | TP_ARGS(fpu) | ||
55 | ); | ||
56 | |||
57 | DEFINE_EVENT(x86_fpu, x86_fpu_before_restore, | ||
58 | TP_PROTO(struct fpu *fpu), | ||
59 | TP_ARGS(fpu) | ||
60 | ); | ||
61 | |||
62 | DEFINE_EVENT(x86_fpu, x86_fpu_after_restore, | ||
63 | TP_PROTO(struct fpu *fpu), | ||
64 | TP_ARGS(fpu) | ||
65 | ); | ||
66 | |||
67 | DEFINE_EVENT(x86_fpu, x86_fpu_regs_activated, | ||
68 | TP_PROTO(struct fpu *fpu), | ||
69 | TP_ARGS(fpu) | ||
70 | ); | ||
71 | |||
72 | DEFINE_EVENT(x86_fpu, x86_fpu_regs_deactivated, | ||
73 | TP_PROTO(struct fpu *fpu), | ||
74 | TP_ARGS(fpu) | ||
75 | ); | ||
76 | |||
77 | DEFINE_EVENT(x86_fpu, x86_fpu_activate_state, | ||
78 | TP_PROTO(struct fpu *fpu), | ||
79 | TP_ARGS(fpu) | ||
80 | ); | ||
81 | |||
82 | DEFINE_EVENT(x86_fpu, x86_fpu_deactivate_state, | ||
83 | TP_PROTO(struct fpu *fpu), | ||
84 | TP_ARGS(fpu) | ||
85 | ); | ||
86 | |||
87 | DEFINE_EVENT(x86_fpu, x86_fpu_init_state, | ||
88 | TP_PROTO(struct fpu *fpu), | ||
89 | TP_ARGS(fpu) | ||
90 | ); | ||
91 | |||
92 | DEFINE_EVENT(x86_fpu, x86_fpu_dropped, | ||
93 | TP_PROTO(struct fpu *fpu), | ||
94 | TP_ARGS(fpu) | ||
95 | ); | ||
96 | |||
97 | DEFINE_EVENT(x86_fpu, x86_fpu_copy_src, | ||
98 | TP_PROTO(struct fpu *fpu), | ||
99 | TP_ARGS(fpu) | ||
100 | ); | ||
101 | |||
102 | DEFINE_EVENT(x86_fpu, x86_fpu_copy_dst, | ||
103 | TP_PROTO(struct fpu *fpu), | ||
104 | TP_ARGS(fpu) | ||
105 | ); | ||
106 | |||
107 | DEFINE_EVENT(x86_fpu, x86_fpu_xstate_check_failed, | ||
108 | TP_PROTO(struct fpu *fpu), | ||
109 | TP_ARGS(fpu) | ||
110 | ); | ||
111 | |||
112 | #undef TRACE_INCLUDE_PATH | ||
113 | #define TRACE_INCLUDE_PATH asm/trace/ | ||
114 | #undef TRACE_INCLUDE_FILE | ||
115 | #define TRACE_INCLUDE_FILE fpu | ||
116 | #endif /* _TRACE_FPU_H */ | ||
117 | |||
118 | /* This part must be outside protection */ | ||
119 | #include <trace/define_trace.h> | ||
diff --git a/arch/x86/kernel/fpu/core.c b/arch/x86/kernel/fpu/core.c index 97027545a72d..7d564742e499 100644 --- a/arch/x86/kernel/fpu/core.c +++ b/arch/x86/kernel/fpu/core.c | |||
@@ -12,6 +12,9 @@ | |||
12 | 12 | ||
13 | #include <linux/hardirq.h> | 13 | #include <linux/hardirq.h> |
14 | 14 | ||
15 | #define CREATE_TRACE_POINTS | ||
16 | #include <asm/trace/fpu.h> | ||
17 | |||
15 | /* | 18 | /* |
16 | * Represents the initial FPU state. It's mostly (but not completely) zeroes, | 19 | * Represents the initial FPU state. It's mostly (but not completely) zeroes, |
17 | * depending on the FPU hardware format: | 20 | * depending on the FPU hardware format: |
@@ -192,6 +195,7 @@ void fpu__save(struct fpu *fpu) | |||
192 | WARN_ON_FPU(fpu != ¤t->thread.fpu); | 195 | WARN_ON_FPU(fpu != ¤t->thread.fpu); |
193 | 196 | ||
194 | preempt_disable(); | 197 | preempt_disable(); |
198 | trace_x86_fpu_before_save(fpu); | ||
195 | if (fpu->fpregs_active) { | 199 | if (fpu->fpregs_active) { |
196 | if (!copy_fpregs_to_fpstate(fpu)) { | 200 | if (!copy_fpregs_to_fpstate(fpu)) { |
197 | if (use_eager_fpu()) | 201 | if (use_eager_fpu()) |
@@ -200,6 +204,7 @@ void fpu__save(struct fpu *fpu) | |||
200 | fpregs_deactivate(fpu); | 204 | fpregs_deactivate(fpu); |
201 | } | 205 | } |
202 | } | 206 | } |
207 | trace_x86_fpu_after_save(fpu); | ||
203 | preempt_enable(); | 208 | preempt_enable(); |
204 | } | 209 | } |
205 | EXPORT_SYMBOL_GPL(fpu__save); | 210 | EXPORT_SYMBOL_GPL(fpu__save); |
@@ -275,6 +280,9 @@ int fpu__copy(struct fpu *dst_fpu, struct fpu *src_fpu) | |||
275 | } | 280 | } |
276 | preempt_enable(); | 281 | preempt_enable(); |
277 | 282 | ||
283 | trace_x86_fpu_copy_src(src_fpu); | ||
284 | trace_x86_fpu_copy_dst(dst_fpu); | ||
285 | |||
278 | return 0; | 286 | return 0; |
279 | } | 287 | } |
280 | 288 | ||
@@ -288,7 +296,9 @@ void fpu__activate_curr(struct fpu *fpu) | |||
288 | 296 | ||
289 | if (!fpu->fpstate_active) { | 297 | if (!fpu->fpstate_active) { |
290 | fpstate_init(&fpu->state); | 298 | fpstate_init(&fpu->state); |
299 | trace_x86_fpu_init_state(fpu); | ||
291 | 300 | ||
301 | trace_x86_fpu_activate_state(fpu); | ||
292 | /* Safe to do for the current task: */ | 302 | /* Safe to do for the current task: */ |
293 | fpu->fpstate_active = 1; | 303 | fpu->fpstate_active = 1; |
294 | } | 304 | } |
@@ -314,7 +324,9 @@ void fpu__activate_fpstate_read(struct fpu *fpu) | |||
314 | } else { | 324 | } else { |
315 | if (!fpu->fpstate_active) { | 325 | if (!fpu->fpstate_active) { |
316 | fpstate_init(&fpu->state); | 326 | fpstate_init(&fpu->state); |
327 | trace_x86_fpu_init_state(fpu); | ||
317 | 328 | ||
329 | trace_x86_fpu_activate_state(fpu); | ||
318 | /* Safe to do for current and for stopped child tasks: */ | 330 | /* Safe to do for current and for stopped child tasks: */ |
319 | fpu->fpstate_active = 1; | 331 | fpu->fpstate_active = 1; |
320 | } | 332 | } |
@@ -347,7 +359,9 @@ void fpu__activate_fpstate_write(struct fpu *fpu) | |||
347 | fpu->last_cpu = -1; | 359 | fpu->last_cpu = -1; |
348 | } else { | 360 | } else { |
349 | fpstate_init(&fpu->state); | 361 | fpstate_init(&fpu->state); |
362 | trace_x86_fpu_init_state(fpu); | ||
350 | 363 | ||
364 | trace_x86_fpu_activate_state(fpu); | ||
351 | /* Safe to do for stopped child tasks: */ | 365 | /* Safe to do for stopped child tasks: */ |
352 | fpu->fpstate_active = 1; | 366 | fpu->fpstate_active = 1; |
353 | } | 367 | } |
@@ -432,9 +446,11 @@ void fpu__restore(struct fpu *fpu) | |||
432 | 446 | ||
433 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ | 447 | /* Avoid __kernel_fpu_begin() right after fpregs_activate() */ |
434 | kernel_fpu_disable(); | 448 | kernel_fpu_disable(); |
449 | trace_x86_fpu_before_restore(fpu); | ||
435 | fpregs_activate(fpu); | 450 | fpregs_activate(fpu); |
436 | copy_kernel_to_fpregs(&fpu->state); | 451 | copy_kernel_to_fpregs(&fpu->state); |
437 | fpu->counter++; | 452 | fpu->counter++; |
453 | trace_x86_fpu_after_restore(fpu); | ||
438 | kernel_fpu_enable(); | 454 | kernel_fpu_enable(); |
439 | } | 455 | } |
440 | EXPORT_SYMBOL_GPL(fpu__restore); | 456 | EXPORT_SYMBOL_GPL(fpu__restore); |
@@ -463,6 +479,8 @@ void fpu__drop(struct fpu *fpu) | |||
463 | 479 | ||
464 | fpu->fpstate_active = 0; | 480 | fpu->fpstate_active = 0; |
465 | 481 | ||
482 | trace_x86_fpu_dropped(fpu); | ||
483 | |||
466 | preempt_enable(); | 484 | preempt_enable(); |
467 | } | 485 | } |
468 | 486 | ||
diff --git a/arch/x86/kernel/fpu/signal.c b/arch/x86/kernel/fpu/signal.c index 31c6a60505e6..c6f2a3cee2c2 100644 --- a/arch/x86/kernel/fpu/signal.c +++ b/arch/x86/kernel/fpu/signal.c | |||
@@ -10,6 +10,7 @@ | |||
10 | #include <asm/fpu/regset.h> | 10 | #include <asm/fpu/regset.h> |
11 | 11 | ||
12 | #include <asm/sigframe.h> | 12 | #include <asm/sigframe.h> |
13 | #include <asm/trace/fpu.h> | ||
13 | 14 | ||
14 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; | 15 | static struct _fpx_sw_bytes fx_sw_reserved, fx_sw_reserved_ia32; |
15 | 16 | ||
@@ -282,6 +283,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
282 | */ | 283 | */ |
283 | state_size = sizeof(struct fxregs_state); | 284 | state_size = sizeof(struct fxregs_state); |
284 | fx_only = 1; | 285 | fx_only = 1; |
286 | trace_x86_fpu_xstate_check_failed(fpu); | ||
285 | } else { | 287 | } else { |
286 | state_size = fx_sw_user.xstate_size; | 288 | state_size = fx_sw_user.xstate_size; |
287 | xfeatures = fx_sw_user.xfeatures; | 289 | xfeatures = fx_sw_user.xfeatures; |
@@ -311,6 +313,7 @@ static int __fpu__restore_sig(void __user *buf, void __user *buf_fx, int size) | |||
311 | if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || | 313 | if (__copy_from_user(&fpu->state.xsave, buf_fx, state_size) || |
312 | __copy_from_user(&env, buf, sizeof(env))) { | 314 | __copy_from_user(&env, buf, sizeof(env))) { |
313 | fpstate_init(&fpu->state); | 315 | fpstate_init(&fpu->state); |
316 | trace_x86_fpu_init_state(fpu); | ||
314 | err = -1; | 317 | err = -1; |
315 | } else { | 318 | } else { |
316 | sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); | 319 | sanitize_restored_xstate(tsk, &env, xfeatures, fx_only); |
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 902d9da12392..1ba3b7d3cae9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -55,9 +55,6 @@ | |||
55 | #include <linux/irqbypass.h> | 55 | #include <linux/irqbypass.h> |
56 | #include <trace/events/kvm.h> | 56 | #include <trace/events/kvm.h> |
57 | 57 | ||
58 | #define CREATE_TRACE_POINTS | ||
59 | #include "trace.h" | ||
60 | |||
61 | #include <asm/debugreg.h> | 58 | #include <asm/debugreg.h> |
62 | #include <asm/msr.h> | 59 | #include <asm/msr.h> |
63 | #include <asm/desc.h> | 60 | #include <asm/desc.h> |
@@ -68,6 +65,9 @@ | |||
68 | #include <asm/div64.h> | 65 | #include <asm/div64.h> |
69 | #include <asm/irq_remapping.h> | 66 | #include <asm/irq_remapping.h> |
70 | 67 | ||
68 | #define CREATE_TRACE_POINTS | ||
69 | #include "trace.h" | ||
70 | |||
71 | #define MAX_IO_MSRS 256 | 71 | #define MAX_IO_MSRS 256 |
72 | #define KVM_MAX_MCE_BANKS 32 | 72 | #define KVM_MAX_MCE_BANKS 32 |
73 | #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P) | 73 | #define KVM_MCE_CAP_SUPPORTED (MCG_CTL_P | MCG_SER_P) |