aboutsummaryrefslogtreecommitdiffstats
path: root/include/trace/ftrace.h
diff options
context:
space:
mode:
Diffstat (limited to 'include/trace/ftrace.h')
-rw-r--r--include/trace/ftrace.h183
1 files changed, 158 insertions, 25 deletions
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 3cbb96ef34f4..25d3b02a06f8 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -145,6 +145,9 @@
145#undef TP_fast_assign 145#undef TP_fast_assign
146#define TP_fast_assign(args...) args 146#define TP_fast_assign(args...) args
147 147
148#undef TP_perf_assign
149#define TP_perf_assign(args...)
150
148#undef TRACE_EVENT 151#undef TRACE_EVENT
149#define TRACE_EVENT(call, proto, args, tstruct, func, print) \ 152#define TRACE_EVENT(call, proto, args, tstruct, func, print) \
150static int \ 153static int \
@@ -347,6 +350,56 @@ static inline int ftrace_get_offsets_##call( \
347 350
348#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) 351#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
349 352
353#ifdef CONFIG_EVENT_PROFILE
354
355/*
356 * Generate the functions needed for tracepoint perf_counter support.
357 *
358 * NOTE: The insertion profile callback (ftrace_profile_<call>) is defined later
359 *
360 * static int ftrace_profile_enable_<call>(struct ftrace_event_call *event_call)
361 * {
362 * int ret = 0;
363 *
364 * if (!atomic_inc_return(&event_call->profile_count))
365 * ret = register_trace_<call>(ftrace_profile_<call>);
366 *
367 * return ret;
368 * }
369 *
370 * static void ftrace_profile_disable_<call>(struct ftrace_event_call *event_call)
371 * {
372 * if (atomic_add_negative(-1, &event->call->profile_count))
373 * unregister_trace_<call>(ftrace_profile_<call>);
374 * }
375 *
376 */
377
378#undef TRACE_EVENT
379#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \
380 \
381static void ftrace_profile_##call(proto); \
382 \
383static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \
384{ \
385 int ret = 0; \
386 \
387 if (!atomic_inc_return(&event_call->profile_count)) \
388 ret = register_trace_##call(ftrace_profile_##call); \
389 \
390 return ret; \
391} \
392 \
393static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
394{ \
395 if (atomic_add_negative(-1, &event_call->profile_count)) \
396 unregister_trace_##call(ftrace_profile_##call); \
397}
398
399#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
400
401#endif
402
350/* 403/*
351 * Stage 4 of the trace events. 404 * Stage 4 of the trace events.
352 * 405 *
@@ -449,28 +502,6 @@ static inline int ftrace_get_offsets_##call( \
449#define TP_FMT(fmt, args...) fmt "\n", ##args 502#define TP_FMT(fmt, args...) fmt "\n", ##args
450 503
451#ifdef CONFIG_EVENT_PROFILE 504#ifdef CONFIG_EVENT_PROFILE
452#define _TRACE_PROFILE(call, proto, args) \
453static void ftrace_profile_##call(proto) \
454{ \
455 extern void perf_tpcounter_event(int); \
456 perf_tpcounter_event(event_##call.id); \
457} \
458 \
459static int ftrace_profile_enable_##call(struct ftrace_event_call *event_call) \
460{ \
461 int ret = 0; \
462 \
463 if (!atomic_inc_return(&event_call->profile_count)) \
464 ret = register_trace_##call(ftrace_profile_##call); \
465 \
466 return ret; \
467} \
468 \
469static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
470{ \
471 if (atomic_add_negative(-1, &event_call->profile_count)) \
472 unregister_trace_##call(ftrace_profile_##call); \
473}
474 505
475#define _TRACE_PROFILE_INIT(call) \ 506#define _TRACE_PROFILE_INIT(call) \
476 .profile_count = ATOMIC_INIT(-1), \ 507 .profile_count = ATOMIC_INIT(-1), \
@@ -478,7 +509,6 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
478 .profile_disable = ftrace_profile_disable_##call, 509 .profile_disable = ftrace_profile_disable_##call,
479 510
480#else 511#else
481#define _TRACE_PROFILE(call, proto, args)
482#define _TRACE_PROFILE_INIT(call) 512#define _TRACE_PROFILE_INIT(call)
483#endif 513#endif
484 514
@@ -504,7 +534,6 @@ static void ftrace_profile_disable_##call(struct ftrace_event_call *event_call)\
504 534
505#undef TRACE_EVENT 535#undef TRACE_EVENT
506#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \ 536#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \
507_TRACE_PROFILE(call, PARAMS(proto), PARAMS(args)) \
508 \ 537 \
509static struct ftrace_event_call event_##call; \ 538static struct ftrace_event_call event_##call; \
510 \ 539 \
@@ -588,6 +617,110 @@ __attribute__((section("_ftrace_events"))) event_##call = { \
588 617
589#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) 618#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
590 619
591#undef _TRACE_PROFILE 620/*
621 * Define the insertion callback to profile events
622 *
623 * The job is very similar to ftrace_raw_event_<call> except that we don't
624 * insert in the ring buffer but in a perf counter.
625 *
626 * static void ftrace_profile_<call>(proto)
627 * {
628 * struct ftrace_data_offsets_<call> __maybe_unused __data_offsets;
629 * struct ftrace_event_call *event_call = &event_<call>;
630 * extern void perf_tpcounter_event(int, u64, u64, void *, int);
631 * struct ftrace_raw_##call *entry;
632 * u64 __addr = 0, __count = 1;
633 * unsigned long irq_flags;
634 * int __entry_size;
635 * int __data_size;
636 * int pc;
637 *
638 * local_save_flags(irq_flags);
639 * pc = preempt_count();
640 *
641 * __data_size = ftrace_get_offsets_<call>(&__data_offsets, args);
642 *
643 * // Below we want to get the aligned size by taking into account
644 * // the u32 field that will later store the buffer size
645 * __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),
646 * sizeof(u64));
647 * __entry_size -= sizeof(u32);
648 *
649 * do {
650 * char raw_data[__entry_size]; <- allocate our sample in the stack
651 * struct trace_entry *ent;
652 *
653 * zero dead bytes from alignment to avoid stack leak to userspace:
654 *
655 * *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL;
656 * entry = (struct ftrace_raw_<call> *)raw_data;
657 * ent = &entry->ent;
658 * tracing_generic_entry_update(ent, irq_flags, pc);
659 * ent->type = event_call->id;
660 *
661 * <tstruct> <- do some jobs with dynamic arrays
662 *
663 * <assign> <- affect our values
664 *
665 * perf_tpcounter_event(event_call->id, __addr, __count, entry,
666 * __entry_size); <- submit them to perf counter
667 * } while (0);
668 *
669 * }
670 */
671
672#ifdef CONFIG_EVENT_PROFILE
673
674#undef __perf_addr
675#define __perf_addr(a) __addr = (a)
676
677#undef __perf_count
678#define __perf_count(c) __count = (c)
679
680#undef TRACE_EVENT
681#define TRACE_EVENT(call, proto, args, tstruct, assign, print) \
682static void ftrace_profile_##call(proto) \
683{ \
684 struct ftrace_data_offsets_##call __maybe_unused __data_offsets;\
685 struct ftrace_event_call *event_call = &event_##call; \
686 extern void perf_tpcounter_event(int, u64, u64, void *, int); \
687 struct ftrace_raw_##call *entry; \
688 u64 __addr = 0, __count = 1; \
689 unsigned long irq_flags; \
690 int __entry_size; \
691 int __data_size; \
692 int pc; \
693 \
694 local_save_flags(irq_flags); \
695 pc = preempt_count(); \
696 \
697 __data_size = ftrace_get_offsets_##call(&__data_offsets, args); \
698 __entry_size = ALIGN(__data_size + sizeof(*entry) + sizeof(u32),\
699 sizeof(u64)); \
700 __entry_size -= sizeof(u32); \
701 \
702 do { \
703 char raw_data[__entry_size]; \
704 struct trace_entry *ent; \
705 \
706 *(u64 *)(&raw_data[__entry_size - sizeof(u64)]) = 0ULL; \
707 entry = (struct ftrace_raw_##call *)raw_data; \
708 ent = &entry->ent; \
709 tracing_generic_entry_update(ent, irq_flags, pc); \
710 ent->type = event_call->id; \
711 \
712 tstruct \
713 \
714 { assign; } \
715 \
716 perf_tpcounter_event(event_call->id, __addr, __count, entry,\
717 __entry_size); \
718 } while (0); \
719 \
720}
721
722#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
723#endif /* CONFIG_EVENT_PROFILE */
724
592#undef _TRACE_PROFILE_INIT 725#undef _TRACE_PROFILE_INIT
593 726