Skip to content

Commit 7f47d8c

Browse files
Andi KleenIngo Molnar
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Acked-by: Steven Rostedt <[email protected]> Cc: Arnaldo Carvalho de Melo <[email protected]> Cc: Jiri Olsa <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Stephane Eranian <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Vince Weaver <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent bd2a634 commit 7f47d8c

File tree

5 files changed

+188
-0
lines changed

5 files changed

+188
-0
lines changed

Documentation/trace/events-msr.txt

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
2+
The x86 kernel supports tracing most MSR (Model Specific Register) accesses.
3+
To see the definition of the MSRs on Intel systems please see the SDM
4+
at http://www.intel.com/sdm (Volume 3)
5+
6+
Available trace points:
7+
8+
/sys/kernel/debug/tracing/events/msr/
9+
10+
Trace MSR reads
11+
12+
read_msr
13+
14+
msr: MSR number
15+
val: Value written
16+
failed: 1 if the access failed, otherwise 0
17+
18+
19+
Trace MSR writes
20+
21+
write_msr
22+
23+
msr: MSR number
24+
val: Value written
25+
failed: 1 if the access failed, otherwise 0
26+
27+
28+
Trace RDPMC in kernel
29+
30+
rdpmc
31+
32+
The trace data can be post processed with the postprocess/decode_msr.py script
33+
34+
cat /sys/kernel/debug/tracing/trace | decode_msr.py /usr/src/linux/include/asm/msr-index.h
35+
36+
to add symbolic MSR names.
37+
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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
4+
import sys
5+
import re
6+
7+
msrs = dict()
8+
9+
with 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+
15+
extra_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+
21+
for 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+

arch/x86/include/asm/msr-trace.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
20+
DECLARE_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+
39+
DEFINE_EVENT(msr_trace_class, read_msr,
40+
TP_PROTO(unsigned msr, u64 val, int failed),
41+
TP_ARGS(msr, val, failed)
42+
);
43+
44+
DEFINE_EVENT(msr_trace_class, write_msr,
45+
TP_PROTO(unsigned msr, u64 val, int failed),
46+
TP_ARGS(msr, val, failed)
47+
);
48+
49+
DEFINE_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>

arch/x86/include/asm/msr.h

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,34 @@ static inline unsigned long long native_read_tscp(unsigned int *aux)
5757
#define EAX_EDX_RET(val, low, high) "=A" (val)
5858
#endif
5959

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+
67+
extern struct tracepoint __tracepoint_read_msr;
68+
extern struct tracepoint __tracepoint_write_msr;
69+
extern struct tracepoint __tracepoint_rdpmc;
70+
#define msr_tracepoint_active(t) static_key_false(&(t).key)
71+
extern void do_trace_write_msr(unsigned msr, u64 val, int failed);
72+
extern void do_trace_read_msr(unsigned msr, u64 val, int failed);
73+
extern void do_trace_rdpmc(unsigned msr, u64 val, int failed);
74+
#else
75+
#define msr_tracepoint_active(t) false
76+
static inline void do_trace_write_msr(unsigned msr, u64 val, int failed) {}
77+
static inline void do_trace_read_msr(unsigned msr, u64 val, int failed) {}
78+
static inline void do_trace_rdpmc(unsigned msr, u64 val, int failed) {}
79+
#endif
80+
6081
static inline unsigned long long native_read_msr(unsigned int msr)
6182
{
6283
DECLARE_ARGS(val, low, high);
6384

6485
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);
6588
return EAX_EDX_VAL(val, low, high);
6689
}
6790

@@ -78,13 +101,17 @@ static inline unsigned long long native_read_msr_safe(unsigned int msr,
78101
_ASM_EXTABLE(2b, 3b)
79102
: [err] "=r" (*err), EAX_EDX_RET(val, low, high)
80103
: "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);
81106
return EAX_EDX_VAL(val, low, high);
82107
}
83108

84109
static inline void native_write_msr(unsigned int msr,
85110
unsigned low, unsigned high)
86111
{
87112
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);
88115
}
89116

90117
/* Can be uninlined because referenced by paravirt */
@@ -102,6 +129,8 @@ notrace static inline int native_write_msr_safe(unsigned int msr,
102129
: "c" (msr), "0" (low), "d" (high),
103130
[fault] "i" (-EIO)
104131
: "memory");
132+
if (msr_tracepoint_active(__tracepoint_read_msr))
133+
do_trace_write_msr(msr, ((u64)high << 32 | low), err);
105134
return err;
106135
}
107136

@@ -160,6 +189,8 @@ static inline unsigned long long native_read_pmc(int counter)
160189
DECLARE_ARGS(val, low, high);
161190

162191
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);
163194
return EAX_EDX_VAL(val, low, high);
164195
}
165196

arch/x86/lib/msr.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#include <linux/module.h>
22
#include <linux/preempt.h>
33
#include <asm/msr.h>
4+
#define CREATE_TRACE_POINTS
5+
#include <asm/msr-trace.h>
46

57
struct msr *msrs_alloc(void)
68
{
@@ -108,3 +110,27 @@ int msr_clear_bit(u32 msr, u8 bit)
108110
{
109111
return __flip_bit(msr, bit, false);
110112
}
113+
114+
#ifdef CONFIG_TRACEPOINTS
115+
void do_trace_write_msr(unsigned msr, u64 val, int failed)
116+
{
117+
trace_write_msr(msr, val, failed);
118+
}
119+
EXPORT_SYMBOL(do_trace_write_msr);
120+
EXPORT_TRACEPOINT_SYMBOL(write_msr);
121+
122+
void do_trace_read_msr(unsigned msr, u64 val, int failed)
123+
{
124+
trace_read_msr(msr, val, failed);
125+
}
126+
EXPORT_SYMBOL(do_trace_read_msr);
127+
EXPORT_TRACEPOINT_SYMBOL(read_msr);
128+
129+
void do_trace_rdpmc(unsigned counter, u64 val, int failed)
130+
{
131+
trace_rdpmc(counter, val, failed);
132+
}
133+
EXPORT_SYMBOL(do_trace_rdpmc);
134+
EXPORT_TRACEPOINT_SYMBOL(rdpmc);
135+
136+
#endif

0 commit comments

Comments
 (0)