aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndi Kleen <ak@linux.intel.com>2015-12-01 20:00:59 -0500
committerIngo Molnar <mingo@kernel.org>2015-12-06 06:56:10 -0500
commit7f47d8cc039f8746e0038fe05f1ddcb15a2e27f0 (patch)
treebbd8cc8f4dbe6b441325d12d9c86dae26bdfb846
parentbd2a634d9e852b9b6100f9ae9c3c790b0ff91ce0 (diff)
x86, tracing, perf: Add trace point for MSR accesses
For debugging low level code interacting with the CPU it is often useful to trace the MSR read/writes. This gives a concise summary of PMU and other operations. perf has an ad-hoc way to do this using trace_printk, but it's somewhat limited (and also now spews ugly boot messages when enabled) Instead define real trace points for all MSR accesses. This adds three new trace points: read_msr and write_msr and rdpmc. They also report if the access faulted (if *_safe is used) This allows filtering and triggering on specific MSR values, which allows various more advanced debugging techniques. All the values are well defined in the CPU documentation. The trace can be post processed with Documentation/trace/postprocess/decode_msr.py to add symbolic MSR names to the trace. I only added it to native MSR accesses in C, not paravirtualized or in entry*.S (which is not too interesting) Originally the patch kit moved the MSRs out of line. This uses an alternative approach recommended by Steven Rostedt of only moving the trace calls out of line, but open coding the access to the jump label. Signed-off-by: Andi Kleen <ak@linux.intel.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Jiri Olsa <jolsa@redhat.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Mike Galbraith <efault@gmx.de> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Stephane Eranian <eranian@google.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Vince Weaver <vincent.weaver@maine.edu> Link: http://lkml.kernel.org/r/1449018060-1742-3-git-send-email-andi@firstfloor.org Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--Documentation/trace/events-msr.txt37
-rw-r--r--Documentation/trace/postprocess/decode_msr.py37
-rw-r--r--arch/x86/include/asm/msr-trace.h57
-rw-r--r--arch/x86/include/asm/msr.h31
-rw-r--r--arch/x86/lib/msr.c26
5 files changed, 188 insertions, 0 deletions
diff --git a/Documentation/trace/events-msr.txt b/Documentation/trace/events-msr.txt
new file mode 100644
index 000000000000..78c383bf06aa
--- /dev/null
+++ b/Documentation/trace/events-msr.txt
@@ -0,0 +1,37 @@
1
2The x86 kernel supports tracing most MSR (Model Specific Register) accesses.
3To see the definition of the MSRs on Intel systems please see the SDM
4at http://www.intel.com/sdm (Volume 3)
5
6Available trace points:
7
8/sys/kernel/debug/tracing/events/msr/
9
10Trace MSR reads
11
12read_msr
13
14msr: MSR number
15val: Value written
16failed: 1 if the access failed, otherwise 0
17
18
19Trace MSR writes
20
21write_msr
22
23msr: MSR number
24val: Value written
25failed: 1 if the access failed, otherwise 0
26
27
28Trace RDPMC in kernel
29
30rdpmc
31
32The trace data can be post processed with the postprocess/decode_msr.py script
33
34cat /sys/kernel/debug/tracing/trace | decode_msr.py /usr/src/linux/include/asm/msr-index.h
35
36to add symbolic MSR names.
37
diff --git a/Documentation/trace/postprocess/decode_msr.py b/Documentation/trace/postprocess/decode_msr.py
new file mode 100644
index 000000000000..0ab40e0db580
--- /dev/null
+++ b/Documentation/trace/postprocess/decode_msr.py
@@ -0,0 +1,37 @@
1#!/usr/bin/python
2# add symbolic names to read_msr / write_msr in trace
3# decode_msr msr-index.h < trace
4import sys
5import re
6
7msrs = dict()
8
9with open(sys.argv[1] if len(sys.argv) > 1 else "msr-index.h", "r") as f:
10 for j in f:
11 m = re.match(r'#define (MSR_\w+)\s+(0x[0-9a-fA-F]+)', j)
12 if m:
13 msrs[int(m.group(2), 16)] = m.group(1)
14
15extra_ranges = (
16 ( "MSR_LASTBRANCH_%d_FROM_IP", 0x680, 0x69F ),
17 ( "MSR_LASTBRANCH_%d_TO_IP", 0x6C0, 0x6DF ),
18 ( "LBR_INFO_%d", 0xdc0, 0xddf ),
19)
20
21for j in sys.stdin:
22 m = re.search(r'(read|write)_msr:\s+([0-9a-f]+)', j)
23 if m:
24 r = None
25 num = int(m.group(2), 16)
26 if num in msrs:
27 r = msrs[num]
28 else:
29 for er in extra_ranges:
30 if er[1] <= num <= er[2]:
31 r = er[0] % (num - er[1],)
32 break
33 if r:
34 j = j.replace(" " + m.group(2), " " + r + "(" + m.group(2) + ")")
35 print j,
36
37
diff --git a/arch/x86/include/asm/msr-trace.h b/arch/x86/include/asm/msr-trace.h
new file mode 100644
index 000000000000..7567225747d8
--- /dev/null
+++ b/arch/x86/include/asm/msr-trace.h
@@ -0,0 +1,57 @@
1#undef TRACE_SYSTEM
2#define TRACE_SYSTEM msr
3
4#undef TRACE_INCLUDE_FILE
5#define TRACE_INCLUDE_FILE msr-trace
6
7#undef TRACE_INCLUDE_PATH
8#define TRACE_INCLUDE_PATH asm/
9
10#if !defined(_TRACE_MSR_H) || defined(TRACE_HEADER_MULTI_READ)
11#define _TRACE_MSR_H
12
13#include <linux/tracepoint.h>
14
15/*
16 * Tracing for x86 model specific registers. Directly maps to the
17 * RDMSR/WRMSR instructions.
18 */
19
20DECLARE_EVENT_CLASS(msr_trace_class,
21 TP_PROTO(unsigned msr, u64 val, int failed),
22 TP_ARGS(msr, val, failed),
23 TP_STRUCT__entry(
24 __field( unsigned, msr )
25 __field( u64, val )
26 __field( int, failed )
27 ),
28 TP_fast_assign(
29 __entry->msr = msr;
30 __entry->val = val;
31 __entry->failed = failed;
32 ),
33 TP_printk("%x, value %llx%s",
34 __entry->msr,
35 __entry->val,
36 __entry->failed ? " #GP" : "")
37);
38
39DEFINE_EVENT(msr_trace_class, read_msr,
40 TP_PROTO(unsigned msr, u64 val, int failed),
41 TP_ARGS(msr, val, failed)
42);
43
44DEFINE_EVENT(msr_trace_class, write_msr,
45 TP_PROTO(unsigned msr, u64 val, int failed),
46 TP_ARGS(msr, val, failed)
47);
48
49DEFINE_EVENT(msr_trace_class, rdpmc,
50 TP_PROTO(unsigned msr, u64 val, int failed),
51 TP_ARGS(msr, val, failed)
52);
53
54#endif /* _TRACE_MSR_H */
55
56/* This part must be outside protection */
57#include <trace/define_trace.h>
diff --git a/arch/x86/include/asm/msr.h b/arch/x86/include/asm/msr.h
index 77d8b284e4a7..fedd6e6d1e43 100644
--- a/arch/x86/include/asm/msr.h
+++ b/arch/x86/include/asm/msr.h
@@ -57,11 +57,34 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
57#define EAX_EDX_RET(val, low, high) "=A" (val) 57#define EAX_EDX_RET(val, low, high) "=A" (val)
58#endif 58#endif
59 59
60#ifdef CONFIG_TRACEPOINTS
61/*
62 * Be very careful with includes. This header is prone to include loops.
63 */
64#include <asm/atomic.h>
65#include <linux/tracepoint-defs.h>
66
67extern struct tracepoint __tracepoint_read_msr;
68extern struct tracepoint __tracepoint_write_msr;
69extern struct tracepoint __tracepoint_rdpmc;
70#define msr_tracepoint_active(t) static_key_false(&(t).key)
71extern void do_trace_write_msr(unsigned msr, u64 val, int failed);
72extern void do_trace_read_msr(unsigned msr, u64 val, int failed);
73extern void do_trace_rdpmc(unsigned msr, u64 val, int failed);
74#else
75#define msr_tracepoint_active(t) false
76static inline void do_trace_write_msr(unsigned msr, u64 val, int failed) {}
77static inline void do_trace_read_msr(unsigned msr, u64 val, int failed) {}
78static inline void do_trace_rdpmc(unsigned msr, u64 val, int failed) {}
79#endif
80
60static inline unsigned long long native_read_msr(unsigned int msr) 81static inline unsigned long long native_read_msr(unsigned int msr)
61{ 82{
62 DECLARE_ARGS(val, low, high); 83 DECLARE_ARGS(val, low, high);
63 84
64 asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr)); 85 asm volatile("rdmsr" : EAX_EDX_RET(val, low, high) : "c" (msr));
86 if (msr_tracepoint_active(__tracepoint_read_msr))
87 do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), 0);
65 return EAX_EDX_VAL(val, low, high); 88 return EAX_EDX_VAL(val, low, high);
66} 89}
67 90
@@ -78,6 +101,8 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
78 _ASM_EXTABLE(2b, 3b) 101 _ASM_EXTABLE(2b, 3b)
79 : [err] "=r" (*err), EAX_EDX_RET(val, low, high) 102 : [err] "=r" (*err), EAX_EDX_RET(val, low, high)
80 : "c" (msr), [fault] "i" (-EIO)); 103 : "c" (msr), [fault] "i" (-EIO));
104 if (msr_tracepoint_active(__tracepoint_read_msr))
105 do_trace_read_msr(msr, EAX_EDX_VAL(val, low, high), *err);
81 return EAX_EDX_VAL(val, low, high); 106 return EAX_EDX_VAL(val, low, high);
82} 107}
83 108
@@ -85,6 +110,8 @@ static inline void native_write_msr(unsigned int msr,
85 unsigned low, unsigned high) 110 unsigned low, unsigned high)
86{ 111{
87 asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory"); 112 asm volatile("wrmsr" : : "c" (msr), "a"(low), "d" (high) : "memory");
113 if (msr_tracepoint_active(__tracepoint_read_msr))
114 do_trace_write_msr(msr, ((u64)high << 32 | low), 0);
88} 115}
89 116
90/* Can be uninlined because referenced by paravirt */ 117/* Can be uninlined because referenced by paravirt */
@@ -102,6 +129,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
102 : "c" (msr), "0" (low), "d" (high), 129 : "c" (msr), "0" (low), "d" (high),
103 [fault] "i" (-EIO) 130 [fault] "i" (-EIO)
104 : "memory"); 131 : "memory");
132 if (msr_tracepoint_active(__tracepoint_read_msr))
133 do_trace_write_msr(msr, ((u64)high << 32 | low), err);
105 return err; 134 return err;
106} 135}
107 136
@@ -160,6 +189,8 @@ static inline unsigned long long native_read_pmc(int counter)
160 DECLARE_ARGS(val, low, high); 189 DECLARE_ARGS(val, low, high);
161 190
162 asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter)); 191 asm volatile("rdpmc" : EAX_EDX_RET(val, low, high) : "c" (counter));
192 if (msr_tracepoint_active(__tracepoint_rdpmc))
193 do_trace_rdpmc(counter, EAX_EDX_VAL(val, low, high), 0);
163 return EAX_EDX_VAL(val, low, high); 194 return EAX_EDX_VAL(val, low, high);
164} 195}
165 196
diff --git a/arch/x86/lib/msr.c b/arch/x86/lib/msr.c
index 43623739c7cf..004c861b1648 100644
--- a/arch/x86/lib/msr.c
+++ b/arch/x86/lib/msr.c
@@ -1,6 +1,8 @@
1#include <linux/module.h> 1#include <linux/module.h>
2#include <linux/preempt.h> 2#include <linux/preempt.h>
3#include <asm/msr.h> 3#include <asm/msr.h>
4#define CREATE_TRACE_POINTS
5#include <asm/msr-trace.h>
4 6
5struct msr *msrs_alloc(void) 7struct msr *msrs_alloc(void)
6{ 8{
@@ -108,3 +110,27 @@ int msr_clear_bit(u32 msr, u8 bit)
108{ 110{
109 return __flip_bit(msr, bit, false); 111 return __flip_bit(msr, bit, false);
110} 112}
113
114#ifdef CONFIG_TRACEPOINTS
115void do_trace_write_msr(unsigned msr, u64 val, int failed)
116{
117 trace_write_msr(msr, val, failed);
118}
119EXPORT_SYMBOL(do_trace_write_msr);
120EXPORT_TRACEPOINT_SYMBOL(write_msr);
121
122void do_trace_read_msr(unsigned msr, u64 val, int failed)
123{
124 trace_read_msr(msr, val, failed);
125}
126EXPORT_SYMBOL(do_trace_read_msr);
127EXPORT_TRACEPOINT_SYMBOL(read_msr);
128
129void do_trace_rdpmc(unsigned counter, u64 val, int failed)
130{
131 trace_rdpmc(counter, val, failed);
132}
133EXPORT_SYMBOL(do_trace_rdpmc);
134EXPORT_TRACEPOINT_SYMBOL(rdpmc);
135
136#endif