aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ftrace.txt74
-rw-r--r--arch/x86/kernel/ds.c31
-rw-r--r--arch/x86/kernel/dumpstack.c6
-rw-r--r--include/linux/ftrace.h13
-rw-r--r--kernel/trace/trace.h1
-rw-r--r--kernel/trace/trace_hw_branches.c173
-rw-r--r--kernel/trace/trace_workqueue.c64
7 files changed, 280 insertions, 82 deletions
diff --git a/Documentation/ftrace.txt b/Documentation/ftrace.txt
index 803b1318b13d..758fb42a1b68 100644
--- a/Documentation/ftrace.txt
+++ b/Documentation/ftrace.txt
@@ -165,6 +165,8 @@ Here is the list of current tracers that may be configured.
165 nop - This is not a tracer. To remove all tracers from tracing 165 nop - This is not a tracer. To remove all tracers from tracing
166 simply echo "nop" into current_tracer. 166 simply echo "nop" into current_tracer.
167 167
168 hw-branch-tracer - traces branches on all cpu's in a circular buffer.
169
168 170
169Examples of using the tracer 171Examples of using the tracer
170---------------------------- 172----------------------------
@@ -1152,6 +1154,78 @@ int main (int argc, char **argv)
1152 return 0; 1154 return 0;
1153} 1155}
1154 1156
1157
1158hw-branch-tracer (x86 only)
1159---------------------------
1160
1161This tracer uses the x86 last branch tracing hardware feature to
1162collect a branch trace on all cpus with relatively low overhead.
1163
1164The tracer uses a fixed-size circular buffer per cpu and only
1165traces ring 0 branches. The trace file dumps that buffer in the
1166following format:
1167
1168# tracer: hw-branch-tracer
1169#
1170# CPU# TO <- FROM
1171 0 scheduler_tick+0xb5/0x1bf <- task_tick_idle+0x5/0x6
1172 2 run_posix_cpu_timers+0x2b/0x72a <- run_posix_cpu_timers+0x25/0x72a
1173 0 scheduler_tick+0x139/0x1bf <- scheduler_tick+0xed/0x1bf
1174 0 scheduler_tick+0x17c/0x1bf <- scheduler_tick+0x148/0x1bf
1175 2 run_posix_cpu_timers+0x9e/0x72a <- run_posix_cpu_timers+0x5e/0x72a
1176 0 scheduler_tick+0x1b6/0x1bf <- scheduler_tick+0x1aa/0x1bf
1177
1178
1179The tracer may be used to dump the trace for the oops'ing cpu on a
1180kernel oops into the system log. To enable this, ftrace_dump_on_oops
1181must be set. To set ftrace_dump_on_oops, one can either use the sysctl
1182function or set it via the proc system interface.
1183
1184 sysctl kernel.ftrace_dump_on_oops=1
1185
1186or
1187
1188 echo 1 > /proc/sys/kernel/ftrace_dump_on_oops
1189
1190
1191Here's an example of such a dump after a null pointer dereference in a
1192kernel module:
1193
1194[57848.105921] BUG: unable to handle kernel NULL pointer dereference at 0000000000000000
1195[57848.106019] IP: [<ffffffffa0000006>] open+0x6/0x14 [oops]
1196[57848.106019] PGD 2354e9067 PUD 2375e7067 PMD 0
1197[57848.106019] Oops: 0002 [#1] SMP
1198[57848.106019] last sysfs file: /sys/devices/pci0000:00/0000:00:1e.0/0000:20:05.0/local_cpus
1199[57848.106019] Dumping ftrace buffer:
1200[57848.106019] ---------------------------------
1201[...]
1202[57848.106019] 0 chrdev_open+0xe6/0x165 <- cdev_put+0x23/0x24
1203[57848.106019] 0 chrdev_open+0x117/0x165 <- chrdev_open+0xfa/0x165
1204[57848.106019] 0 chrdev_open+0x120/0x165 <- chrdev_open+0x11c/0x165
1205[57848.106019] 0 chrdev_open+0x134/0x165 <- chrdev_open+0x12b/0x165
1206[57848.106019] 0 open+0x0/0x14 [oops] <- chrdev_open+0x144/0x165
1207[57848.106019] 0 page_fault+0x0/0x30 <- open+0x6/0x14 [oops]
1208[57848.106019] 0 error_entry+0x0/0x5b <- page_fault+0x4/0x30
1209[57848.106019] 0 error_kernelspace+0x0/0x31 <- error_entry+0x59/0x5b
1210[57848.106019] 0 error_sti+0x0/0x1 <- error_kernelspace+0x2d/0x31
1211[57848.106019] 0 page_fault+0x9/0x30 <- error_sti+0x0/0x1
1212[57848.106019] 0 do_page_fault+0x0/0x881 <- page_fault+0x1a/0x30
1213[...]
1214[57848.106019] 0 do_page_fault+0x66b/0x881 <- is_prefetch+0x1ee/0x1f2
1215[57848.106019] 0 do_page_fault+0x6e0/0x881 <- do_page_fault+0x67a/0x881
1216[57848.106019] 0 oops_begin+0x0/0x96 <- do_page_fault+0x6e0/0x881
1217[57848.106019] 0 trace_hw_branch_oops+0x0/0x2d <- oops_begin+0x9/0x96
1218[...]
1219[57848.106019] 0 ds_suspend_bts+0x2a/0xe3 <- ds_suspend_bts+0x1a/0xe3
1220[57848.106019] ---------------------------------
1221[57848.106019] CPU 0
1222[57848.106019] Modules linked in: oops
1223[57848.106019] Pid: 5542, comm: cat Tainted: G W 2.6.28 #23
1224[57848.106019] RIP: 0010:[<ffffffffa0000006>] [<ffffffffa0000006>] open+0x6/0x14 [oops]
1225[57848.106019] RSP: 0018:ffff880235457d48 EFLAGS: 00010246
1226[...]
1227
1228
1155dynamic ftrace 1229dynamic ftrace
1156-------------- 1230--------------
1157 1231
diff --git a/arch/x86/kernel/ds.c b/arch/x86/kernel/ds.c
index da91701a2348..169a120587be 100644
--- a/arch/x86/kernel/ds.c
+++ b/arch/x86/kernel/ds.c
@@ -15,8 +15,8 @@
15 * - buffer allocation (memory accounting) 15 * - buffer allocation (memory accounting)
16 * 16 *
17 * 17 *
18 * Copyright (C) 2007-2008 Intel Corporation. 18 * Copyright (C) 2007-2009 Intel Corporation.
19 * Markus Metzger <markus.t.metzger@intel.com>, 2007-2008 19 * Markus Metzger <markus.t.metzger@intel.com>, 2007-2009
20 */ 20 */
21 21
22 22
@@ -890,7 +890,7 @@ int ds_set_pebs_reset(struct pebs_tracer *tracer, u64 value)
890} 890}
891 891
892static const struct ds_configuration ds_cfg_netburst = { 892static const struct ds_configuration ds_cfg_netburst = {
893 .name = "netburst", 893 .name = "Netburst",
894 .ctl[dsf_bts] = (1 << 2) | (1 << 3), 894 .ctl[dsf_bts] = (1 << 2) | (1 << 3),
895 .ctl[dsf_bts_kernel] = (1 << 5), 895 .ctl[dsf_bts_kernel] = (1 << 5),
896 .ctl[dsf_bts_user] = (1 << 6), 896 .ctl[dsf_bts_user] = (1 << 6),
@@ -904,7 +904,7 @@ static const struct ds_configuration ds_cfg_netburst = {
904#endif 904#endif
905}; 905};
906static const struct ds_configuration ds_cfg_pentium_m = { 906static const struct ds_configuration ds_cfg_pentium_m = {
907 .name = "pentium m", 907 .name = "Pentium M",
908 .ctl[dsf_bts] = (1 << 6) | (1 << 7), 908 .ctl[dsf_bts] = (1 << 6) | (1 << 7),
909 909
910 .sizeof_field = sizeof(long), 910 .sizeof_field = sizeof(long),
@@ -915,8 +915,8 @@ static const struct ds_configuration ds_cfg_pentium_m = {
915 .sizeof_rec[ds_pebs] = sizeof(long) * 18, 915 .sizeof_rec[ds_pebs] = sizeof(long) * 18,
916#endif 916#endif
917}; 917};
918static const struct ds_configuration ds_cfg_core2 = { 918static const struct ds_configuration ds_cfg_core2_atom = {
919 .name = "core 2", 919 .name = "Core 2/Atom",
920 .ctl[dsf_bts] = (1 << 6) | (1 << 7), 920 .ctl[dsf_bts] = (1 << 6) | (1 << 7),
921 .ctl[dsf_bts_kernel] = (1 << 9), 921 .ctl[dsf_bts_kernel] = (1 << 9),
922 .ctl[dsf_bts_user] = (1 << 10), 922 .ctl[dsf_bts_user] = (1 << 10),
@@ -949,19 +949,22 @@ void __cpuinit ds_init_intel(struct cpuinfo_x86 *c)
949 switch (c->x86) { 949 switch (c->x86) {
950 case 0x6: 950 case 0x6:
951 switch (c->x86_model) { 951 switch (c->x86_model) {
952 case 0 ... 0xC: 952 case 0x9:
953 /* sorry, don't know about them */ 953 case 0xd: /* Pentium M */
954 break;
955 case 0xD:
956 case 0xE: /* Pentium M */
957 ds_configure(&ds_cfg_pentium_m); 954 ds_configure(&ds_cfg_pentium_m);
958 break; 955 break;
959 default: /* Core2, Atom, ... */ 956 case 0xf:
960 ds_configure(&ds_cfg_core2); 957 case 0x17: /* Core2 */
958 case 0x1c: /* Atom */
959 ds_configure(&ds_cfg_core2_atom);
960 break;
961 case 0x1a: /* i7 */
962 default:
963 /* sorry, don't know about them */
961 break; 964 break;
962 } 965 }
963 break; 966 break;
964 case 0xF: 967 case 0xf:
965 switch (c->x86_model) { 968 switch (c->x86_model) {
966 case 0x0: 969 case 0x0:
967 case 0x1: 970 case 0x1:
diff --git a/arch/x86/kernel/dumpstack.c b/arch/x86/kernel/dumpstack.c
index 6b1f6f6f8661..077c9ea655fc 100644
--- a/arch/x86/kernel/dumpstack.c
+++ b/arch/x86/kernel/dumpstack.c
@@ -14,6 +14,7 @@
14#include <linux/bug.h> 14#include <linux/bug.h>
15#include <linux/nmi.h> 15#include <linux/nmi.h>
16#include <linux/sysfs.h> 16#include <linux/sysfs.h>
17#include <linux/ftrace.h>
17 18
18#include <asm/stacktrace.h> 19#include <asm/stacktrace.h>
19 20
@@ -195,6 +196,11 @@ unsigned __kprobes long oops_begin(void)
195 int cpu; 196 int cpu;
196 unsigned long flags; 197 unsigned long flags;
197 198
199 /* notify the hw-branch tracer so it may disable tracing and
200 add the last trace to the trace buffer -
201 the earlier this happens, the more useful the trace. */
202 trace_hw_branch_oops();
203
198 oops_enter(); 204 oops_enter();
199 205
200 /* racy, but better than risking deadlock. */ 206 /* racy, but better than risking deadlock. */
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 054721487574..9f7880d87c39 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -496,4 +496,17 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk)
496 496
497#endif /* CONFIG_TRACING */ 497#endif /* CONFIG_TRACING */
498 498
499
500#ifdef CONFIG_HW_BRANCH_TRACER
501
502void trace_hw_branch(u64 from, u64 to);
503void trace_hw_branch_oops(void);
504
505#else /* CONFIG_HW_BRANCH_TRACER */
506
507static inline void trace_hw_branch(u64 from, u64 to) {}
508static inline void trace_hw_branch_oops(void) {}
509
510#endif /* CONFIG_HW_BRANCH_TRACER */
511
499#endif /* _LINUX_FTRACE_H */ 512#endif /* _LINUX_FTRACE_H */
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 54b72781e920..b96037d970df 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -438,7 +438,6 @@ void trace_function(struct trace_array *tr,
438 438
439void trace_graph_return(struct ftrace_graph_ret *trace); 439void trace_graph_return(struct ftrace_graph_ret *trace);
440int trace_graph_entry(struct ftrace_graph_ent *trace); 440int trace_graph_entry(struct ftrace_graph_ent *trace);
441void trace_hw_branch(struct trace_array *tr, u64 from, u64 to);
442 441
443void tracing_start_cmdline_record(void); 442void tracing_start_cmdline_record(void);
444void tracing_stop_cmdline_record(void); 443void tracing_stop_cmdline_record(void);
diff --git a/kernel/trace/trace_hw_branches.c b/kernel/trace/trace_hw_branches.c
index df21c1e72b95..fff3545fc866 100644
--- a/kernel/trace/trace_hw_branches.c
+++ b/kernel/trace/trace_hw_branches.c
@@ -1,7 +1,8 @@
1/* 1/*
2 * h/w branch tracer for x86 based on bts 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-2009 Intel Corporation.
5 * Markus Metzger <markus.t.metzger@gmail.com>, 2008-2009
5 * 6 *
6 */ 7 */
7 8
@@ -10,6 +11,9 @@
10#include <linux/debugfs.h> 11#include <linux/debugfs.h>
11#include <linux/ftrace.h> 12#include <linux/ftrace.h>
12#include <linux/kallsyms.h> 13#include <linux/kallsyms.h>
14#include <linux/mutex.h>
15#include <linux/cpu.h>
16#include <linux/smp.h>
13 17
14#include <asm/ds.h> 18#include <asm/ds.h>
15 19
@@ -19,13 +23,32 @@
19 23
20#define SIZEOF_BTS (1 << 13) 24#define SIZEOF_BTS (1 << 13)
21 25
26/* The tracer mutex protects the below per-cpu tracer array.
27 It needs to be held to:
28 - start tracing on all cpus
29 - stop tracing on all cpus
30 - start tracing on a single hotplug cpu
31 - stop tracing on a single hotplug cpu
32 - read the trace from all cpus
33 - read the trace from a single cpu
34*/
35static DEFINE_MUTEX(bts_tracer_mutex);
22static DEFINE_PER_CPU(struct bts_tracer *, tracer); 36static DEFINE_PER_CPU(struct bts_tracer *, tracer);
23static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer); 37static DEFINE_PER_CPU(unsigned char[SIZEOF_BTS], buffer);
24 38
25#define this_tracer per_cpu(tracer, smp_processor_id()) 39#define this_tracer per_cpu(tracer, smp_processor_id())
26#define this_buffer per_cpu(buffer, smp_processor_id()) 40#define this_buffer per_cpu(buffer, smp_processor_id())
27 41
42static int __read_mostly trace_hw_branches_enabled;
43static struct trace_array *hw_branch_trace __read_mostly;
28 44
45
46/*
47 * Start tracing on the current cpu.
48 * The argument is ignored.
49 *
50 * pre: bts_tracer_mutex must be locked.
51 */
29static void bts_trace_start_cpu(void *arg) 52static void bts_trace_start_cpu(void *arg)
30{ 53{
31 if (this_tracer) 54 if (this_tracer)
@@ -43,14 +66,20 @@ static void bts_trace_start_cpu(void *arg)
43 66
44static void bts_trace_start(struct trace_array *tr) 67static void bts_trace_start(struct trace_array *tr)
45{ 68{
46 int cpu; 69 mutex_lock(&bts_tracer_mutex);
47 70
48 tracing_reset_online_cpus(tr); 71 on_each_cpu(bts_trace_start_cpu, NULL, 1);
72 trace_hw_branches_enabled = 1;
49 73
50 for_each_cpu(cpu, cpu_possible_mask) 74 mutex_unlock(&bts_tracer_mutex);
51 smp_call_function_single(cpu, bts_trace_start_cpu, NULL, 1);
52} 75}
53 76
77/*
78 * Start tracing on the current cpu.
79 * The argument is ignored.
80 *
81 * pre: bts_tracer_mutex must be locked.
82 */
54static void bts_trace_stop_cpu(void *arg) 83static void bts_trace_stop_cpu(void *arg)
55{ 84{
56 if (this_tracer) { 85 if (this_tracer) {
@@ -61,26 +90,63 @@ static void bts_trace_stop_cpu(void *arg)
61 90
62static void bts_trace_stop(struct trace_array *tr) 91static void bts_trace_stop(struct trace_array *tr)
63{ 92{
64 int cpu; 93 mutex_lock(&bts_tracer_mutex);
94
95 trace_hw_branches_enabled = 0;
96 on_each_cpu(bts_trace_stop_cpu, NULL, 1);
65 97
66 for_each_cpu(cpu, cpu_possible_mask) 98 mutex_unlock(&bts_tracer_mutex);
99}
100
101static int __cpuinit bts_hotcpu_handler(struct notifier_block *nfb,
102 unsigned long action, void *hcpu)
103{
104 unsigned int cpu = (unsigned long)hcpu;
105
106 mutex_lock(&bts_tracer_mutex);
107
108 if (!trace_hw_branches_enabled)
109 goto out;
110
111 switch (action) {
112 case CPU_ONLINE:
113 case CPU_DOWN_FAILED:
114 smp_call_function_single(cpu, bts_trace_start_cpu, NULL, 1);
115 break;
116 case CPU_DOWN_PREPARE:
67 smp_call_function_single(cpu, bts_trace_stop_cpu, NULL, 1); 117 smp_call_function_single(cpu, bts_trace_stop_cpu, NULL, 1);
118 break;
119 }
120
121 out:
122 mutex_unlock(&bts_tracer_mutex);
123 return NOTIFY_DONE;
68} 124}
69 125
126static struct notifier_block bts_hotcpu_notifier __cpuinitdata = {
127 .notifier_call = bts_hotcpu_handler
128};
129
70static int bts_trace_init(struct trace_array *tr) 130static int bts_trace_init(struct trace_array *tr)
71{ 131{
132 hw_branch_trace = tr;
133
134 register_hotcpu_notifier(&bts_hotcpu_notifier);
72 tracing_reset_online_cpus(tr); 135 tracing_reset_online_cpus(tr);
73 bts_trace_start(tr); 136 bts_trace_start(tr);
74 137
75 return 0; 138 return 0;
76} 139}
77 140
141static void bts_trace_reset(struct trace_array *tr)
142{
143 bts_trace_stop(tr);
144 unregister_hotcpu_notifier(&bts_hotcpu_notifier);
145}
146
78static void bts_trace_print_header(struct seq_file *m) 147static void bts_trace_print_header(struct seq_file *m)
79{ 148{
80 seq_puts(m, 149 seq_puts(m, "# CPU# TO <- FROM\n");
81 "# CPU# FROM TO FUNCTION\n");
82 seq_puts(m,
83 "# | | | |\n");
84} 150}
85 151
86static enum print_line_t bts_trace_print_line(struct trace_iterator *iter) 152static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
@@ -88,15 +154,15 @@ static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
88 struct trace_entry *entry = iter->ent; 154 struct trace_entry *entry = iter->ent;
89 struct trace_seq *seq = &iter->seq; 155 struct trace_seq *seq = &iter->seq;
90 struct hw_branch_entry *it; 156 struct hw_branch_entry *it;
157 unsigned long symflags = TRACE_ITER_SYM_OFFSET;
91 158
92 trace_assign_type(it, entry); 159 trace_assign_type(it, entry);
93 160
94 if (entry->type == TRACE_HW_BRANCHES) { 161 if (entry->type == TRACE_HW_BRANCHES) {
95 if (trace_seq_printf(seq, "%4d ", entry->cpu) && 162 if (trace_seq_printf(seq, "%4d ", entry->cpu) &&
96 trace_seq_printf(seq, "0x%016llx -> 0x%016llx ", 163 seq_print_ip_sym(seq, it->to, symflags) &&
97 it->from, it->to) && 164 trace_seq_printf(seq, "\t <- ") &&
98 (!it->from || 165 seq_print_ip_sym(seq, it->from, symflags) &&
99 seq_print_ip_sym(seq, it->from, /* sym_flags = */ 0)) &&
100 trace_seq_printf(seq, "\n")) 166 trace_seq_printf(seq, "\n"))
101 return TRACE_TYPE_HANDLED; 167 return TRACE_TYPE_HANDLED;
102 return TRACE_TYPE_PARTIAL_LINE;; 168 return TRACE_TYPE_PARTIAL_LINE;;
@@ -104,26 +170,42 @@ static enum print_line_t bts_trace_print_line(struct trace_iterator *iter)
104 return TRACE_TYPE_UNHANDLED; 170 return TRACE_TYPE_UNHANDLED;
105} 171}
106 172
107void trace_hw_branch(struct trace_array *tr, u64 from, u64 to) 173void trace_hw_branch(u64 from, u64 to)
108{ 174{
175 struct trace_array *tr = hw_branch_trace;
109 struct ring_buffer_event *event; 176 struct ring_buffer_event *event;
110 struct hw_branch_entry *entry; 177 struct hw_branch_entry *entry;
111 unsigned long irq; 178 unsigned long irq1, irq2;
179 int cpu;
112 180
113 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), &irq); 181 if (unlikely(!tr))
114 if (!event)
115 return; 182 return;
183
184 if (unlikely(!trace_hw_branches_enabled))
185 return;
186
187 local_irq_save(irq1);
188 cpu = raw_smp_processor_id();
189 if (atomic_inc_return(&tr->data[cpu]->disabled) != 1)
190 goto out;
191
192 event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry), &irq2);
193 if (!event)
194 goto out;
116 entry = ring_buffer_event_data(event); 195 entry = ring_buffer_event_data(event);
117 tracing_generic_entry_update(&entry->ent, 0, from); 196 tracing_generic_entry_update(&entry->ent, 0, from);
118 entry->ent.type = TRACE_HW_BRANCHES; 197 entry->ent.type = TRACE_HW_BRANCHES;
119 entry->ent.cpu = smp_processor_id(); 198 entry->ent.cpu = cpu;
120 entry->from = from; 199 entry->from = from;
121 entry->to = to; 200 entry->to = to;
122 ring_buffer_unlock_commit(tr->buffer, event, irq); 201 ring_buffer_unlock_commit(tr->buffer, event, irq2);
202
203 out:
204 atomic_dec(&tr->data[cpu]->disabled);
205 local_irq_restore(irq1);
123} 206}
124 207
125static void trace_bts_at(struct trace_array *tr, 208static void trace_bts_at(const struct bts_trace *trace, void *at)
126 const struct bts_trace *trace, void *at)
127{ 209{
128 struct bts_struct bts; 210 struct bts_struct bts;
129 int err = 0; 211 int err = 0;
@@ -138,18 +220,29 @@ static void trace_bts_at(struct trace_array *tr,
138 220
139 switch (bts.qualifier) { 221 switch (bts.qualifier) {
140 case BTS_BRANCH: 222 case BTS_BRANCH:
141 trace_hw_branch(tr, bts.variant.lbr.from, bts.variant.lbr.to); 223 trace_hw_branch(bts.variant.lbr.from, bts.variant.lbr.to);
142 break; 224 break;
143 } 225 }
144} 226}
145 227
228/*
229 * Collect the trace on the current cpu and write it into the ftrace buffer.
230 *
231 * pre: bts_tracer_mutex must be locked
232 */
146static void trace_bts_cpu(void *arg) 233static void trace_bts_cpu(void *arg)
147{ 234{
148 struct trace_array *tr = (struct trace_array *) arg; 235 struct trace_array *tr = (struct trace_array *) arg;
149 const struct bts_trace *trace; 236 const struct bts_trace *trace;
150 unsigned char *at; 237 unsigned char *at;
151 238
152 if (!this_tracer) 239 if (unlikely(!tr))
240 return;
241
242 if (unlikely(atomic_read(&tr->data[raw_smp_processor_id()]->disabled)))
243 return;
244
245 if (unlikely(!this_tracer))
153 return; 246 return;
154 247
155 ds_suspend_bts(this_tracer); 248 ds_suspend_bts(this_tracer);
@@ -159,11 +252,11 @@ static void trace_bts_cpu(void *arg)
159 252
160 for (at = trace->ds.top; (void *)at < trace->ds.end; 253 for (at = trace->ds.top; (void *)at < trace->ds.end;
161 at += trace->ds.size) 254 at += trace->ds.size)
162 trace_bts_at(tr, trace, at); 255 trace_bts_at(trace, at);
163 256
164 for (at = trace->ds.begin; (void *)at < trace->ds.top; 257 for (at = trace->ds.begin; (void *)at < trace->ds.top;
165 at += trace->ds.size) 258 at += trace->ds.size)
166 trace_bts_at(tr, trace, at); 259 trace_bts_at(trace, at);
167 260
168out: 261out:
169 ds_resume_bts(this_tracer); 262 ds_resume_bts(this_tracer);
@@ -171,22 +264,38 @@ out:
171 264
172static void trace_bts_prepare(struct trace_iterator *iter) 265static void trace_bts_prepare(struct trace_iterator *iter)
173{ 266{
174 int cpu; 267 mutex_lock(&bts_tracer_mutex);
268
269 on_each_cpu(trace_bts_cpu, iter->tr, 1);
270
271 mutex_unlock(&bts_tracer_mutex);
272}
273
274static void trace_bts_close(struct trace_iterator *iter)
275{
276 tracing_reset_online_cpus(iter->tr);
277}
278
279void trace_hw_branch_oops(void)
280{
281 mutex_lock(&bts_tracer_mutex);
282
283 trace_bts_cpu(hw_branch_trace);
175 284
176 for_each_cpu(cpu, cpu_possible_mask) 285 mutex_unlock(&bts_tracer_mutex);
177 smp_call_function_single(cpu, trace_bts_cpu, iter->tr, 1);
178} 286}
179 287
180struct tracer bts_tracer __read_mostly = 288struct tracer bts_tracer __read_mostly =
181{ 289{
182 .name = "hw-branch-tracer", 290 .name = "hw-branch-tracer",
183 .init = bts_trace_init, 291 .init = bts_trace_init,
184 .reset = bts_trace_stop, 292 .reset = bts_trace_reset,
185 .print_header = bts_trace_print_header, 293 .print_header = bts_trace_print_header,
186 .print_line = bts_trace_print_line, 294 .print_line = bts_trace_print_line,
187 .start = bts_trace_start, 295 .start = bts_trace_start,
188 .stop = bts_trace_stop, 296 .stop = bts_trace_stop,
189 .open = trace_bts_prepare 297 .open = trace_bts_prepare,
298 .close = trace_bts_close
190}; 299};
191 300
192__init static int init_bts_trace(void) 301__init static int init_bts_trace(void)
diff --git a/kernel/trace/trace_workqueue.c b/kernel/trace/trace_workqueue.c
index f8118d39ca9b..4664990fe9c5 100644
--- a/kernel/trace/trace_workqueue.c
+++ b/kernel/trace/trace_workqueue.c
@@ -8,6 +8,7 @@
8 8
9#include <trace/workqueue.h> 9#include <trace/workqueue.h>
10#include <linux/list.h> 10#include <linux/list.h>
11#include <linux/percpu.h>
11#include "trace_stat.h" 12#include "trace_stat.h"
12#include "trace.h" 13#include "trace.h"
13 14
@@ -37,7 +38,8 @@ struct workqueue_global_stats {
37/* Don't need a global lock because allocated before the workqueues, and 38/* Don't need a global lock because allocated before the workqueues, and
38 * never freed. 39 * never freed.
39 */ 40 */
40static struct workqueue_global_stats *all_workqueue_stat; 41static DEFINE_PER_CPU(struct workqueue_global_stats, all_workqueue_stat);
42#define workqueue_cpu_stat(cpu) (&per_cpu(all_workqueue_stat, cpu))
41 43
42/* Insertion of a work */ 44/* Insertion of a work */
43static void 45static void
@@ -48,8 +50,8 @@ probe_workqueue_insertion(struct task_struct *wq_thread,
48 struct cpu_workqueue_stats *node, *next; 50 struct cpu_workqueue_stats *node, *next;
49 unsigned long flags; 51 unsigned long flags;
50 52
51 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 53 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
52 list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list, 54 list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
53 list) { 55 list) {
54 if (node->pid == wq_thread->pid) { 56 if (node->pid == wq_thread->pid) {
55 atomic_inc(&node->inserted); 57 atomic_inc(&node->inserted);
@@ -58,7 +60,7 @@ probe_workqueue_insertion(struct task_struct *wq_thread,
58 } 60 }
59 pr_debug("trace_workqueue: entry not found\n"); 61 pr_debug("trace_workqueue: entry not found\n");
60found: 62found:
61 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 63 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
62} 64}
63 65
64/* Execution of a work */ 66/* Execution of a work */
@@ -70,8 +72,8 @@ probe_workqueue_execution(struct task_struct *wq_thread,
70 struct cpu_workqueue_stats *node, *next; 72 struct cpu_workqueue_stats *node, *next;
71 unsigned long flags; 73 unsigned long flags;
72 74
73 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 75 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
74 list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list, 76 list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
75 list) { 77 list) {
76 if (node->pid == wq_thread->pid) { 78 if (node->pid == wq_thread->pid) {
77 node->executed++; 79 node->executed++;
@@ -80,7 +82,7 @@ probe_workqueue_execution(struct task_struct *wq_thread,
80 } 82 }
81 pr_debug("trace_workqueue: entry not found\n"); 83 pr_debug("trace_workqueue: entry not found\n");
82found: 84found:
83 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 85 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
84} 86}
85 87
86/* Creation of a cpu workqueue thread */ 88/* Creation of a cpu workqueue thread */
@@ -104,11 +106,11 @@ static void probe_workqueue_creation(struct task_struct *wq_thread, int cpu)
104 106
105 cws->pid = wq_thread->pid; 107 cws->pid = wq_thread->pid;
106 108
107 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 109 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
108 if (list_empty(&all_workqueue_stat[cpu].list)) 110 if (list_empty(&workqueue_cpu_stat(cpu)->list))
109 cws->first_entry = true; 111 cws->first_entry = true;
110 list_add_tail(&cws->list, &all_workqueue_stat[cpu].list); 112 list_add_tail(&cws->list, &workqueue_cpu_stat(cpu)->list);
111 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 113 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
112} 114}
113 115
114/* Destruction of a cpu workqueue thread */ 116/* Destruction of a cpu workqueue thread */
@@ -119,8 +121,8 @@ static void probe_workqueue_destruction(struct task_struct *wq_thread)
119 struct cpu_workqueue_stats *node, *next; 121 struct cpu_workqueue_stats *node, *next;
120 unsigned long flags; 122 unsigned long flags;
121 123
122 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 124 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
123 list_for_each_entry_safe(node, next, &all_workqueue_stat[cpu].list, 125 list_for_each_entry_safe(node, next, &workqueue_cpu_stat(cpu)->list,
124 list) { 126 list) {
125 if (node->pid == wq_thread->pid) { 127 if (node->pid == wq_thread->pid) {
126 list_del(&node->list); 128 list_del(&node->list);
@@ -131,7 +133,7 @@ static void probe_workqueue_destruction(struct task_struct *wq_thread)
131 133
132 pr_debug("trace_workqueue: don't find workqueue to destroy\n"); 134 pr_debug("trace_workqueue: don't find workqueue to destroy\n");
133found: 135found:
134 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 136 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
135 137
136} 138}
137 139
@@ -141,13 +143,13 @@ static struct cpu_workqueue_stats *workqueue_stat_start_cpu(int cpu)
141 struct cpu_workqueue_stats *ret = NULL; 143 struct cpu_workqueue_stats *ret = NULL;
142 144
143 145
144 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 146 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
145 147
146 if (!list_empty(&all_workqueue_stat[cpu].list)) 148 if (!list_empty(&workqueue_cpu_stat(cpu)->list))
147 ret = list_entry(all_workqueue_stat[cpu].list.next, 149 ret = list_entry(workqueue_cpu_stat(cpu)->list.next,
148 struct cpu_workqueue_stats, list); 150 struct cpu_workqueue_stats, list);
149 151
150 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 152 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
151 153
152 return ret; 154 return ret;
153} 155}
@@ -172,9 +174,9 @@ static void *workqueue_stat_next(void *prev, int idx)
172 unsigned long flags; 174 unsigned long flags;
173 void *ret = NULL; 175 void *ret = NULL;
174 176
175 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 177 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
176 if (list_is_last(&prev_cws->list, &all_workqueue_stat[cpu].list)) { 178 if (list_is_last(&prev_cws->list, &workqueue_cpu_stat(cpu)->list)) {
177 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 179 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
178 for (++cpu ; cpu < num_possible_cpus(); cpu++) { 180 for (++cpu ; cpu < num_possible_cpus(); cpu++) {
179 ret = workqueue_stat_start_cpu(cpu); 181 ret = workqueue_stat_start_cpu(cpu);
180 if (ret) 182 if (ret)
@@ -182,7 +184,7 @@ static void *workqueue_stat_next(void *prev, int idx)
182 } 184 }
183 return NULL; 185 return NULL;
184 } 186 }
185 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 187 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
186 188
187 return list_entry(prev_cws->list.next, struct cpu_workqueue_stats, 189 return list_entry(prev_cws->list.next, struct cpu_workqueue_stats,
188 list); 190 list);
@@ -199,10 +201,10 @@ static int workqueue_stat_show(struct seq_file *s, void *p)
199 cws->executed, 201 cws->executed,
200 trace_find_cmdline(cws->pid)); 202 trace_find_cmdline(cws->pid));
201 203
202 spin_lock_irqsave(&all_workqueue_stat[cpu].lock, flags); 204 spin_lock_irqsave(&workqueue_cpu_stat(cpu)->lock, flags);
203 if (&cws->list == all_workqueue_stat[cpu].list.next) 205 if (&cws->list == workqueue_cpu_stat(cpu)->list.next)
204 seq_printf(s, "\n"); 206 seq_printf(s, "\n");
205 spin_unlock_irqrestore(&all_workqueue_stat[cpu].lock, flags); 207 spin_unlock_irqrestore(&workqueue_cpu_stat(cpu)->lock, flags);
206 208
207 return 0; 209 return 0;
208} 210}
@@ -258,17 +260,9 @@ int __init trace_workqueue_early_init(void)
258 if (ret) 260 if (ret)
259 goto no_creation; 261 goto no_creation;
260 262
261 all_workqueue_stat = kmalloc(sizeof(struct workqueue_global_stats)
262 * num_possible_cpus(), GFP_KERNEL);
263
264 if (!all_workqueue_stat) {
265 pr_warning("trace_workqueue: not enough memory\n");
266 goto no_creation;
267 }
268
269 for_each_possible_cpu(cpu) { 263 for_each_possible_cpu(cpu) {
270 spin_lock_init(&all_workqueue_stat[cpu].lock); 264 spin_lock_init(&workqueue_cpu_stat(cpu)->lock);
271 INIT_LIST_HEAD(&all_workqueue_stat[cpu].list); 265 INIT_LIST_HEAD(&workqueue_cpu_stat(cpu)->list);
272 } 266 }
273 267
274 return 0; 268 return 0;