diff options
author | Alexei Starovoitov <ast@fb.com> | 2016-04-06 21:43:24 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2016-04-07 21:04:26 -0400 |
commit | 1e1dcd93b468901e114f279c94a0b356adc5e7cd (patch) | |
tree | b0bee9a35251caacc44d9a3ffbbae90e8afb237d /kernel/trace/trace_event_perf.c | |
parent | e93735be6a1898dd9f8de8f55254cc76309777ce (diff) |
perf: split perf_trace_buf_prepare into alloc and update parts
split allows to move expensive update of 'struct trace_entry' to later phase.
Repurpose unused 1st argument of perf_tp_event() to indicate event type.
While splitting use temp variable 'rctx' instead of '*rctx' to avoid
unnecessary loads done by the compiler due to -fno-strict-aliasing
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'kernel/trace/trace_event_perf.c')
-rw-r--r-- | kernel/trace/trace_event_perf.c | 39 |
1 files changed, 20 insertions, 19 deletions
diff --git a/kernel/trace/trace_event_perf.c b/kernel/trace/trace_event_perf.c index 7a68afca8249..5a927075977f 100644 --- a/kernel/trace/trace_event_perf.c +++ b/kernel/trace/trace_event_perf.c | |||
@@ -260,42 +260,43 @@ void perf_trace_del(struct perf_event *p_event, int flags) | |||
260 | tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); | 260 | tp_event->class->reg(tp_event, TRACE_REG_PERF_DEL, p_event); |
261 | } | 261 | } |
262 | 262 | ||
263 | void *perf_trace_buf_prepare(int size, unsigned short type, | 263 | void *perf_trace_buf_alloc(int size, struct pt_regs **regs, int *rctxp) |
264 | struct pt_regs **regs, int *rctxp) | ||
265 | { | 264 | { |
266 | struct trace_entry *entry; | ||
267 | unsigned long flags; | ||
268 | char *raw_data; | 265 | char *raw_data; |
269 | int pc; | 266 | int rctx; |
270 | 267 | ||
271 | BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long)); | 268 | BUILD_BUG_ON(PERF_MAX_TRACE_SIZE % sizeof(unsigned long)); |
272 | 269 | ||
273 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, | 270 | if (WARN_ONCE(size > PERF_MAX_TRACE_SIZE, |
274 | "perf buffer not large enough")) | 271 | "perf buffer not large enough")) |
275 | return NULL; | 272 | return NULL; |
276 | 273 | ||
277 | pc = preempt_count(); | 274 | *rctxp = rctx = perf_swevent_get_recursion_context(); |
278 | 275 | if (rctx < 0) | |
279 | *rctxp = perf_swevent_get_recursion_context(); | ||
280 | if (*rctxp < 0) | ||
281 | return NULL; | 276 | return NULL; |
282 | 277 | ||
283 | if (regs) | 278 | if (regs) |
284 | *regs = this_cpu_ptr(&__perf_regs[*rctxp]); | 279 | *regs = this_cpu_ptr(&__perf_regs[rctx]); |
285 | raw_data = this_cpu_ptr(perf_trace_buf[*rctxp]); | 280 | raw_data = this_cpu_ptr(perf_trace_buf[rctx]); |
286 | 281 | ||
287 | /* zero the dead bytes from align to not leak stack to user */ | 282 | /* zero the dead bytes from align to not leak stack to user */ |
288 | memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64)); | 283 | memset(&raw_data[size - sizeof(u64)], 0, sizeof(u64)); |
284 | return raw_data; | ||
285 | } | ||
286 | EXPORT_SYMBOL_GPL(perf_trace_buf_alloc); | ||
287 | NOKPROBE_SYMBOL(perf_trace_buf_alloc); | ||
288 | |||
289 | void perf_trace_buf_update(void *record, u16 type) | ||
290 | { | ||
291 | struct trace_entry *entry = record; | ||
292 | int pc = preempt_count(); | ||
293 | unsigned long flags; | ||
289 | 294 | ||
290 | entry = (struct trace_entry *)raw_data; | ||
291 | local_save_flags(flags); | 295 | local_save_flags(flags); |
292 | tracing_generic_entry_update(entry, flags, pc); | 296 | tracing_generic_entry_update(entry, flags, pc); |
293 | entry->type = type; | 297 | entry->type = type; |
294 | |||
295 | return raw_data; | ||
296 | } | 298 | } |
297 | EXPORT_SYMBOL_GPL(perf_trace_buf_prepare); | 299 | NOKPROBE_SYMBOL(perf_trace_buf_update); |
298 | NOKPROBE_SYMBOL(perf_trace_buf_prepare); | ||
299 | 300 | ||
300 | #ifdef CONFIG_FUNCTION_TRACER | 301 | #ifdef CONFIG_FUNCTION_TRACER |
301 | static void | 302 | static void |
@@ -319,13 +320,13 @@ perf_ftrace_function_call(unsigned long ip, unsigned long parent_ip, | |||
319 | memset(®s, 0, sizeof(regs)); | 320 | memset(®s, 0, sizeof(regs)); |
320 | perf_fetch_caller_regs(®s); | 321 | perf_fetch_caller_regs(®s); |
321 | 322 | ||
322 | entry = perf_trace_buf_prepare(ENTRY_SIZE, TRACE_FN, NULL, &rctx); | 323 | entry = perf_trace_buf_alloc(ENTRY_SIZE, NULL, &rctx); |
323 | if (!entry) | 324 | if (!entry) |
324 | return; | 325 | return; |
325 | 326 | ||
326 | entry->ip = ip; | 327 | entry->ip = ip; |
327 | entry->parent_ip = parent_ip; | 328 | entry->parent_ip = parent_ip; |
328 | perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, 0, | 329 | perf_trace_buf_submit(entry, ENTRY_SIZE, rctx, TRACE_FN, |
329 | 1, ®s, head, NULL); | 330 | 1, ®s, head, NULL); |
330 | 331 | ||
331 | #undef ENTRY_SIZE | 332 | #undef ENTRY_SIZE |