aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin KaFai Lau <kafai@fb.com>2016-02-03 15:28:28 -0500
committerIngo Molnar <mingo@kernel.org>2016-02-09 05:08:58 -0500
commita7636d9ecfa3ab7800a7c04c1f89378229eff609 (patch)
tree8b61d2320c6405d671e1a4fe2ff6ace3a98fbbb3
parent156d22386503e1efc58b0f3244895b1c0f930018 (diff)
kprobes: Optimize hot path by using percpu counter to collect 'nhit' statistics
When doing ebpf+kprobe on some hot TCP functions (e.g. tcp_rcv_established), the kprobe_dispatcher() function shows up in 'perf report'. In kprobe_dispatcher(), there is a lot of cache bouncing on 'tk->nhit++'. 'tk->nhit' and 'tk->tp.flags' also share the same cacheline. perf report (cycles:pp): 8.30% ipv4_dst_check 4.74% copy_user_enhanced_fast_string 3.93% dst_release 2.80% tcp_v4_rcv 2.31% queued_spin_lock_slowpath 2.30% _raw_spin_lock 1.88% mlx4_en_process_rx_cq 1.84% eth_get_headlen 1.81% ip_rcv_finish ~~~~ 1.71% kprobe_dispatcher ~~~~ 1.55% mlx4_en_xmit 1.09% __probe_kernel_read perf report after patch: 9.15% ipv4_dst_check 5.00% copy_user_enhanced_fast_string 4.12% dst_release 2.96% tcp_v4_rcv 2.50% _raw_spin_lock 2.39% queued_spin_lock_slowpath 2.11% eth_get_headlen 2.03% mlx4_en_process_rx_cq 1.69% mlx4_en_xmit 1.19% ip_rcv_finish 1.12% __probe_kernel_read 1.02% ehci_hcd_cleanup Signed-off-by: Martin KaFai Lau <kafai@fb.com> Acked-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> Cc: Alexei Starovoitov <alexei.starovoitov@gmail.com> Cc: Josef Bacik <jbacik@fb.com> Cc: Kernel Team <kernel-team@fb.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1454531308-2441898-1-git-send-email-kafai@fb.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
-rw-r--r--kernel/trace/trace_kprobe.c19
1 files changed, 15 insertions, 4 deletions
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index c9956440d0e6..21b81a41dae5 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -30,7 +30,7 @@
30struct trace_kprobe { 30struct trace_kprobe {
31 struct list_head list; 31 struct list_head list;
32 struct kretprobe rp; /* Use rp.kp for kprobe use */ 32 struct kretprobe rp; /* Use rp.kp for kprobe use */
33 unsigned long nhit; 33 unsigned long __percpu *nhit;
34 const char *symbol; /* symbol name */ 34 const char *symbol; /* symbol name */
35 struct trace_probe tp; 35 struct trace_probe tp;
36}; 36};
@@ -274,6 +274,10 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
274 if (!tk) 274 if (!tk)
275 return ERR_PTR(ret); 275 return ERR_PTR(ret);
276 276
277 tk->nhit = alloc_percpu(unsigned long);
278 if (!tk->nhit)
279 goto error;
280
277 if (symbol) { 281 if (symbol) {
278 tk->symbol = kstrdup(symbol, GFP_KERNEL); 282 tk->symbol = kstrdup(symbol, GFP_KERNEL);
279 if (!tk->symbol) 283 if (!tk->symbol)
@@ -313,6 +317,7 @@ static struct trace_kprobe *alloc_trace_kprobe(const char *group,
313error: 317error:
314 kfree(tk->tp.call.name); 318 kfree(tk->tp.call.name);
315 kfree(tk->symbol); 319 kfree(tk->symbol);
320 free_percpu(tk->nhit);
316 kfree(tk); 321 kfree(tk);
317 return ERR_PTR(ret); 322 return ERR_PTR(ret);
318} 323}
@@ -327,6 +332,7 @@ static void free_trace_kprobe(struct trace_kprobe *tk)
327 kfree(tk->tp.call.class->system); 332 kfree(tk->tp.call.class->system);
328 kfree(tk->tp.call.name); 333 kfree(tk->tp.call.name);
329 kfree(tk->symbol); 334 kfree(tk->symbol);
335 free_percpu(tk->nhit);
330 kfree(tk); 336 kfree(tk);
331} 337}
332 338
@@ -874,9 +880,14 @@ static const struct file_operations kprobe_events_ops = {
874static int probes_profile_seq_show(struct seq_file *m, void *v) 880static int probes_profile_seq_show(struct seq_file *m, void *v)
875{ 881{
876 struct trace_kprobe *tk = v; 882 struct trace_kprobe *tk = v;
883 unsigned long nhit = 0;
884 int cpu;
885
886 for_each_possible_cpu(cpu)
887 nhit += *per_cpu_ptr(tk->nhit, cpu);
877 888
878 seq_printf(m, " %-44s %15lu %15lu\n", 889 seq_printf(m, " %-44s %15lu %15lu\n",
879 trace_event_name(&tk->tp.call), tk->nhit, 890 trace_event_name(&tk->tp.call), nhit,
880 tk->rp.kp.nmissed); 891 tk->rp.kp.nmissed);
881 892
882 return 0; 893 return 0;
@@ -1225,7 +1236,7 @@ static int kprobe_dispatcher(struct kprobe *kp, struct pt_regs *regs)
1225{ 1236{
1226 struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp); 1237 struct trace_kprobe *tk = container_of(kp, struct trace_kprobe, rp.kp);
1227 1238
1228 tk->nhit++; 1239 raw_cpu_inc(*tk->nhit);
1229 1240
1230 if (tk->tp.flags & TP_FLAG_TRACE) 1241 if (tk->tp.flags & TP_FLAG_TRACE)
1231 kprobe_trace_func(tk, regs); 1242 kprobe_trace_func(tk, regs);
@@ -1242,7 +1253,7 @@ kretprobe_dispatcher(struct kretprobe_instance *ri, struct pt_regs *regs)
1242{ 1253{
1243 struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp); 1254 struct trace_kprobe *tk = container_of(ri->rp, struct trace_kprobe, rp);
1244 1255
1245 tk->nhit++; 1256 raw_cpu_inc(*tk->nhit);
1246 1257
1247 if (tk->tp.flags & TP_FLAG_TRACE) 1258 if (tk->tp.flags & TP_FLAG_TRACE)
1248 kretprobe_trace_func(tk, ri, regs); 1259 kretprobe_trace_func(tk, ri, regs);