aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarkus Metzger <markut.t.metzger@intel.com>2008-12-11 07:53:26 -0500
committerIngo Molnar <mingo@elte.hu>2008-12-12 02:08:14 -0500
commita93751cab71d63126687551823ed3e70cd85854a (patch)
tree665e9bf274c457edd672ad44320fad962e6c16f5
parentc2724775ce57c98b8af9694857b941dc61056516 (diff)
x86, bts, ftrace: adapt the hw-branch-tracer to the ds.c interface
Impact: restructure code, cleanup Remove BTS bits from the hw-branch-tracer (renamed from bts-tracer) and use the ds interface. Signed-off-by: Markus Metzger <markut.t.metzger@intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--kernel/trace/Kconfig4
-rw-r--r--kernel/trace/Makefile2
-rw-r--r--kernel/trace/trace.c2
-rw-r--r--kernel/trace/trace.h14
-rw-r--r--kernel/trace/trace_hw_branches.c (renamed from kernel/trace/trace_bts.c)163
5 files changed, 56 insertions, 129 deletions
diff --git a/kernel/trace/Kconfig b/kernel/trace/Kconfig
index bde6f03512d5..d8bae6f4219e 100644
--- a/kernel/trace/Kconfig
+++ b/kernel/trace/Kconfig
@@ -251,9 +251,9 @@ config STACK_TRACER
251 251
252 Say N if unsure. 252 Say N if unsure.
253 253
254config BTS_TRACER 254config HW_BRANCH_TRACER
255 depends on HAVE_HW_BRANCH_TRACER 255 depends on HAVE_HW_BRANCH_TRACER
256 bool "Trace branches" 256 bool "Trace hw branches"
257 select TRACING 257 select TRACING
258 help 258 help
259 This tracer records all branches on the system in a circular 259 This tracer records all branches on the system in a circular
diff --git a/kernel/trace/Makefile b/kernel/trace/Makefile
index 62dc561b6676..349d5a93653f 100644
--- a/kernel/trace/Makefile
+++ b/kernel/trace/Makefile
@@ -31,7 +31,7 @@ obj-$(CONFIG_MMIOTRACE) += trace_mmiotrace.o
31obj-$(CONFIG_BOOT_TRACER) += trace_boot.o 31obj-$(CONFIG_BOOT_TRACER) += trace_boot.o
32obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o 32obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += trace_functions_graph.o
33obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o 33obj-$(CONFIG_TRACE_BRANCH_PROFILING) += trace_branch.o
34obj-$(CONFIG_BTS_TRACER) += trace_bts.o 34obj-$(CONFIG_HW_BRANCH_TRACER) += trace_hw_branches.o
35obj-$(CONFIG_POWER_TRACER) += trace_power.o 35obj-$(CONFIG_POWER_TRACER) += trace_power.o
36 36
37libftrace-y := ftrace.o 37libftrace-y := ftrace.o
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 8ebe0070c47a..639344a4d3a2 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -2425,7 +2425,7 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
2425 2425
2426 /* Notify the tracer early; before we stop tracing. */ 2426 /* Notify the tracer early; before we stop tracing. */
2427 if (iter->trace && iter->trace->open) 2427 if (iter->trace && iter->trace->open)
2428 iter->trace->open(iter); 2428 iter->trace->open(iter);
2429 2429
2430 /* Annotate start of buffers if we had overruns */ 2430 /* Annotate start of buffers if we had overruns */
2431 if (ring_buffer_overruns(iter->tr->buffer)) 2431 if (ring_buffer_overruns(iter->tr->buffer))
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 5ac697065a48..f07c246dd73d 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -28,7 +28,7 @@ enum trace_type {
28 TRACE_GRAPH_RET, 28 TRACE_GRAPH_RET,
29 TRACE_GRAPH_ENT, 29 TRACE_GRAPH_ENT,
30 TRACE_USER_STACK, 30 TRACE_USER_STACK,
31 TRACE_BTS, 31 TRACE_HW_BRANCHES,
32 TRACE_POWER, 32 TRACE_POWER,
33 33
34 __TRACE_LAST_TYPE 34 __TRACE_LAST_TYPE
@@ -159,10 +159,10 @@ struct trace_branch {
159 char correct; 159 char correct;
160}; 160};
161 161
162struct bts_entry { 162struct hw_branch_entry {
163 struct trace_entry ent; 163 struct trace_entry ent;
164 unsigned long from; 164 u64 from;
165 unsigned long to; 165 u64 to;
166}; 166};
167 167
168struct trace_power { 168struct trace_power {
@@ -278,7 +278,7 @@ extern void __ftrace_bad_type(void);
278 TRACE_GRAPH_ENT); \ 278 TRACE_GRAPH_ENT); \
279 IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \ 279 IF_ASSIGN(var, ent, struct ftrace_graph_ret_entry, \
280 TRACE_GRAPH_RET); \ 280 TRACE_GRAPH_RET); \
281 IF_ASSIGN(var, ent, struct bts_entry, TRACE_BTS);\ 281 IF_ASSIGN(var, ent, struct hw_branch_entry, TRACE_HW_BRANCHES);\
282 IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \ 282 IF_ASSIGN(var, ent, struct trace_power, TRACE_POWER); \
283 __ftrace_bad_type(); \ 283 __ftrace_bad_type(); \
284 } while (0) 284 } while (0)
@@ -414,9 +414,7 @@ void trace_function(struct trace_array *tr,
414 414
415void trace_graph_return(struct ftrace_graph_ret *trace); 415void trace_graph_return(struct ftrace_graph_ret *trace);
416int trace_graph_entry(struct ftrace_graph_ent *trace); 416int trace_graph_entry(struct ftrace_graph_ent *trace);
417void trace_bts(struct trace_array *tr, 417void trace_hw_branch(struct trace_array *tr, u64 from, u64 to);
418 unsigned long from,
419 unsigned long to);
420 418
421void tracing_start_cmdline_record(void); 419void tracing_start_cmdline_record(void);
422void tracing_stop_cmdline_record(void); 420void tracing_stop_cmdline_record(void);
diff --git a/kernel/trace/trace_bts.c b/kernel/trace/trace_hw_branches.c
index 23b76e4690ef..ee29e012aa97 100644
--- a/kernel/trace/trace_bts.c
+++ b/kernel/trace/trace_hw_branches.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * BTS tracer 2 * h/w branch tracer for x86 based on bts
3 * 3 *
4 * Copyright (C) 2008 Markus Metzger <markus.t.metzger@gmail.com> 4 * Copyright (C) 2008 Markus Metzger <markus.t.metzger@gmail.com>
5 * 5 *
@@ -25,68 +25,6 @@ static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer);
25#define this_buffer per_cpu(buffer, smp_processor_id()) 25#define this_buffer per_cpu(buffer, smp_processor_id())
26 26
27 27
28/*
29 * Information to interpret a BTS record.
30 * This will go into an in-kernel BTS interface.
31 */
32static unsigned char sizeof_field;
33static unsigned long debugctl_mask;
34
35#define sizeof_bts (3 * sizeof_field)
36
37static void bts_trace_cpuinit(struct cpuinfo_x86 *c)
38{
39 switch (c->x86) {
40 case 0x6:
41 switch (c->x86_model) {
42 case 0x0 ... 0xC:
43 break;
44 case 0xD:
45 case 0xE: /* Pentium M */
46 sizeof_field = sizeof(long);
47 debugctl_mask = (1<<6)|(1<<7);
48 break;
49 default:
50 sizeof_field = 8;
51 debugctl_mask = (1<<6)|(1<<7);
52 break;
53 }
54 break;
55 case 0xF:
56 switch (c->x86_model) {
57 case 0x0:
58 case 0x1:
59 case 0x2: /* Netburst */
60 sizeof_field = sizeof(long);
61 debugctl_mask = (1<<2)|(1<<3);
62 break;
63 default:
64 /* sorry, don't know about them */
65 break;
66 }
67 break;
68 default:
69 /* sorry, don't know about them */
70 break;
71 }
72}
73
74static inline void bts_enable(void)
75{
76 unsigned long debugctl;
77
78 rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
79 wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl | debugctl_mask);
80}
81
82static inline void bts_disable(void)
83{
84 unsigned long debugctl;
85
86 rdmsrl(MSR_IA32_DEBUGCTLMSR, debugctl);
87 wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctl & ~debugctl_mask);
88}
89
90static void bts_trace_reset(struct trace_array *tr) 28static void bts_trace_reset(struct trace_array *tr)
91{ 29{
92 int cpu; 30 int cpu;
@@ -99,15 +37,17 @@ static void bts_trace_reset(struct trace_array *tr)
99 37
100static void bts_trace_start_cpu(void *arg) 38static void bts_trace_start_cpu(void *arg)
101{ 39{
40 if (this_tracer)
41 ds_release_bts(this_tracer);
42
102 this_tracer = 43 this_tracer =
103 ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS, 44 ds_request_bts(/* task = */ NULL, this_buffer, SIZEOF_BTS,
104 /* ovfl = */ NULL, /* th = */ (size_t)-1); 45 /* ovfl = */ NULL, /* th = */ (size_t)-1,
46 BTS_KERNEL);
105 if (IS_ERR(this_tracer)) { 47 if (IS_ERR(this_tracer)) {
106 this_tracer = NULL; 48 this_tracer = NULL;
107 return; 49 return;
108 } 50 }
109
110 bts_enable();
111} 51}
112 52
113static void bts_trace_start(struct trace_array *tr) 53static void bts_trace_start(struct trace_array *tr)
@@ -123,8 +63,6 @@ static void bts_trace_start(struct trace_array *tr)
123static void bts_trace_stop_cpu(void *arg) 63static void bts_trace_stop_cpu(void *arg)
124{ 64{
125 if (this_tracer) { 65 if (this_tracer) {
126 bts_disable();
127
128 ds_release_bts(this_tracer); 66 ds_release_bts(this_tracer);
129 this_tracer = NULL; 67 this_tracer = NULL;
130 } 68 }
@@ -140,7 +78,6 @@ static void bts_trace_stop(struct trace_array *tr)
140 78
141static int bts_trace_init(struct trace_array *tr) 79static int bts_trace_init(struct trace_array *tr)
142{ 80{
143 bts_trace_cpuinit(&boot_cpu_data);
144 bts_trace_reset(tr); 81 bts_trace_reset(tr);
145 bts_trace_start(tr); 82 bts_trace_start(tr);
146 83
@@ -149,47 +86,37 @@ static int bts_trace_init(struct trace_array *tr)
149 86
150static void bts_trace_print_header(struct seq_file *m) 87static void bts_trace_print_header(struct seq_file *m)
151{ 88{
152#ifdef __i386__
153 seq_puts(m, "# CPU# FROM TO FUNCTION\n");
154 seq_puts(m, "# | | | |\n");
155#else
156 seq_puts(m, 89 seq_puts(m,
157 "# CPU# FROM TO FUNCTION\n"); 90 "# CPU# FROM TO FUNCTION\n");
158 seq_puts(m, 91 seq_puts(m,
159 "# | | | |\n"); 92 "# | | | |\n");
160#endif
161} 93}
162 94
163static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) 95static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
164{ 96{
165 struct trace_entry *entry = iter->ent; 97 struct trace_entry *entry = iter->ent;
166 struct trace_seq *seq = &iter->seq; 98 struct trace_seq *seq = &iter->seq;
167 struct bts_entry *it; 99 struct hw_branch_entry *it;
168 100
169 trace_assign_type(it, entry); 101 trace_assign_type(it, entry);
170 102
171 if (entry->type == TRACE_BTS) { 103 if (entry->type == TRACE_HW_BRANCHES) {
172 int ret; 104 if (trace_seq_printf(seq, "%4d ", entry->cpu) &&
173#ifdef CONFIG_KALLSYMS 105 trace_seq_printf(seq, "0x%016llx -> 0x%016llx ",
174 char function[KSYM_SYMBOL_LEN]; 106 it->from, it->to) &&
175 sprint_symbol(function, it->from); 107 (!it->from ||
176#else 108 seq_print_ip_sym(seq, it->from, /* sym_flags = */ 0)) &&
177 char *function = "<unknown>"; 109 trace_seq_printf(seq, "\n"))
178#endif 110 return TRACE_TYPE_HANDLED;
179 111 return TRACE_TYPE_PARTIAL_LINE;;
180 ret = trace_seq_printf(seq, "%4d 0x%lx -> 0x%lx [%s]\n",
181 entry->cpu, it->from, it->to, function);
182 if (!ret)
183 return TRACE_TYPE_PARTIAL_LINE;;
184 return TRACE_TYPE_HANDLED;
185 } 112 }
186 return TRACE_TYPE_UNHANDLED; 113 return TRACE_TYPE_UNHANDLED;
187} 114}
188 115
189void trace_bts(struct trace_array *tr, unsigned long from, unsigned long to) 116void trace_hw_branch(struct trace_array *tr, u64 from, u64 to)
190{ 117{
191 struct ring_buffer_event *event; 118 struct ring_buffer_event *event;
192 struct bts_entry *entry; 119 struct hw_branch_entry *entry;
193 unsigned long irq; 120 unsigned long irq;
194 121
195 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), &irq); 122 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), &irq);
@@ -197,56 +124,58 @@ void trace_bts(struct trace_array *tr, unsigned long from, unsigned long to)
197 return; 124 return;
198 entry = ring_buffer_event_data(event); 125 entry = ring_buffer_event_data(event);
199 tracing_generic_entry_update(&entry->ent, 0, from); 126 tracing_generic_entry_update(&entry->ent, 0, from);
200 entry->ent.type = TRACE_BTS; 127 entry->ent.type = TRACE_HW_BRANCHES;
201 entry->ent.cpu = smp_processor_id(); 128 entry->ent.cpu = smp_processor_id();
202 entry->from = from; 129 entry->from = from;
203 entry->to = to; 130 entry->to = to;
204 ring_buffer_unlock_commit(tr->buffer, event, irq); 131 ring_buffer_unlock_commit(tr->buffer, event, irq);
205} 132}
206 133
207static void trace_bts_at(struct trace_array *tr, size_t index) 134static void trace_bts_at(struct trace_array *tr,
135 const struct bts_trace *trace, void *at)
208{ 136{
209 const void *raw = NULL; 137 struct bts_struct bts;
210 unsigned long from, to; 138 int err = 0;
211 int err;
212 139
213 err = ds_access_bts(this_tracer, index, &raw); 140 WARN_ON_ONCE(!trace->read);
214 if (err < 0) 141 if (!trace->read)
215 return; 142 return;
216 143
217 from = *(const unsigned long *)raw; 144 err = trace->read(this_tracer, at, &bts);
218 to = *(const unsigned long *)((const char *)raw + sizeof_field); 145 if (err < 0)
146 return;
219 147
220 trace_bts(tr, from, to); 148 switch (bts.qualifier) {
149 case BTS_BRANCH:
150 trace_hw_branch(tr, bts.variant.lbr.from, bts.variant.lbr.to);
151 break;
152 }
221} 153}
222 154
223static void trace_bts_cpu(void *arg) 155static void trace_bts_cpu(void *arg)
224{ 156{
225 struct trace_array *tr = (struct trace_array *) arg; 157 struct trace_array *tr = (struct trace_array *) arg;
226 size_t index = 0, end = 0, i; 158 const struct bts_trace *trace;
227 int err; 159 unsigned char *at;
228 160
229 if (!this_tracer) 161 if (!this_tracer)
230 return; 162 return;
231 163
232 bts_disable(); 164 ds_suspend_bts(this_tracer);
233 165 trace = ds_read_bts(this_tracer);
234 err = ds_get_bts_index(this_tracer, &index); 166 if (!trace)
235 if (err < 0)
236 goto out;
237
238 err = ds_get_bts_end(this_tracer, &end);
239 if (err < 0)
240 goto out; 167 goto out;
241 168
242 for (i = index; i < end; i++) 169 for (at = trace->ds.top; (void *)at < trace->ds.end;
243 trace_bts_at(tr, i); 170 at += trace->ds.size)
171 trace_bts_at(tr, trace, at);
244 172
245 for (i = 0; i < index; i++) 173 for (at = trace->ds.begin; (void *)at < trace->ds.top;
246 trace_bts_at(tr, i); 174 at += trace->ds.size)
175 trace_bts_at(tr, trace, at);
247 176
248out: 177out:
249 bts_enable(); 178 ds_resume_bts(this_tracer);
250} 179}
251 180
252static void trace_bts_prepare(struct trace_iterator *iter) 181static void trace_bts_prepare(struct trace_iterator *iter)
@@ -259,7 +188,7 @@ static void trace_bts_prepare(struct trace_iterator *iter)
259 188
260struct tracer bts_tracer __read_mostly = 189struct tracer bts_tracer __read_mostly =
261{ 190{
262 .name = "bts", 191 .name = "hw-branch-tracer",
263 .init = bts_trace_init, 192 .init = bts_trace_init,
264 .reset = bts_trace_stop, 193 .reset = bts_trace_stop,
265 .print_header = bts_trace_print_header, 194 .print_header = bts_trace_print_header,