diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 18:23:47 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-05-27 18:23:47 -0400 |
| commit | c5617b200ac52e35f7e8cf05a17b0a2d50f6b3e9 (patch) | |
| tree | 40d5e99660c77c5791392d349a93113c044dbf14 /include/linux | |
| parent | cad719d86e9dbd06634eaba6401e022c8101d6b2 (diff) | |
| parent | 49c177461bfbedeccbab22bf3905db2f9da7f1c3 (diff) | |
Merge branch 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'perf-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: (61 commits)
tracing: Add __used annotation to event variable
perf, trace: Fix !x86 build bug
perf report: Support multiple events on the TUI
perf annotate: Fix up usage of the build id cache
x86/mmiotrace: Remove redundant instruction prefix checks
perf annotate: Add TUI interface
perf tui: Remove annotate from popup menu after failure
perf report: Don't start the TUI if -D is used
perf: Fix getline undeclared
perf: Optimize perf_tp_event_match()
perf: Remove more code from the fastpath
perf: Optimize the !vmalloc backed buffer
perf: Optimize perf_output_copy()
perf: Fix wakeup storm for RO mmap()s
perf-record: Share per-cpu buffers
perf-record: Remove -M
perf: Ensure that IOC_OUTPUT isn't used to create multi-writer buffers
perf, trace: Optimize tracepoints by using per-tracepoint-per-cpu hlist to track events
perf, trace: Optimize tracepoints by removing IRQ-disable from perf/tracepoint interaction
perf tui: Allow disabling the TUI on a per command basis in ~/.perfconfig
...
Diffstat (limited to 'include/linux')
| -rw-r--r-- | include/linux/ftrace_event.h | 103 | ||||
| -rw-r--r-- | include/linux/perf_event.h | 28 | ||||
| -rw-r--r-- | include/linux/syscalls.h | 57 | ||||
| -rw-r--r-- | include/linux/tracepoint.h | 98 |
4 files changed, 183 insertions, 103 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h index c082f223e2fe..3167f2df4126 100644 --- a/include/linux/ftrace_event.h +++ b/include/linux/ftrace_event.h | |||
| @@ -73,18 +73,25 @@ struct trace_iterator { | |||
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | 75 | ||
| 76 | struct trace_event; | ||
| 77 | |||
| 76 | typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter, | 78 | typedef enum print_line_t (*trace_print_func)(struct trace_iterator *iter, |
| 77 | int flags); | 79 | int flags, struct trace_event *event); |
| 78 | struct trace_event { | 80 | |
| 79 | struct hlist_node node; | 81 | struct trace_event_functions { |
| 80 | struct list_head list; | ||
| 81 | int type; | ||
| 82 | trace_print_func trace; | 82 | trace_print_func trace; |
| 83 | trace_print_func raw; | 83 | trace_print_func raw; |
| 84 | trace_print_func hex; | 84 | trace_print_func hex; |
| 85 | trace_print_func binary; | 85 | trace_print_func binary; |
| 86 | }; | 86 | }; |
| 87 | 87 | ||
| 88 | struct trace_event { | ||
| 89 | struct hlist_node node; | ||
| 90 | struct list_head list; | ||
| 91 | int type; | ||
| 92 | struct trace_event_functions *funcs; | ||
| 93 | }; | ||
| 94 | |||
| 88 | extern int register_ftrace_event(struct trace_event *event); | 95 | extern int register_ftrace_event(struct trace_event *event); |
| 89 | extern int unregister_ftrace_event(struct trace_event *event); | 96 | extern int unregister_ftrace_event(struct trace_event *event); |
| 90 | 97 | ||
| @@ -116,28 +123,70 @@ void tracing_record_cmdline(struct task_struct *tsk); | |||
| 116 | 123 | ||
| 117 | struct event_filter; | 124 | struct event_filter; |
| 118 | 125 | ||
| 126 | enum trace_reg { | ||
| 127 | TRACE_REG_REGISTER, | ||
| 128 | TRACE_REG_UNREGISTER, | ||
| 129 | TRACE_REG_PERF_REGISTER, | ||
| 130 | TRACE_REG_PERF_UNREGISTER, | ||
| 131 | }; | ||
| 132 | |||
| 133 | struct ftrace_event_call; | ||
| 134 | |||
| 135 | struct ftrace_event_class { | ||
| 136 | char *system; | ||
| 137 | void *probe; | ||
| 138 | #ifdef CONFIG_PERF_EVENTS | ||
| 139 | void *perf_probe; | ||
| 140 | #endif | ||
| 141 | int (*reg)(struct ftrace_event_call *event, | ||
| 142 | enum trace_reg type); | ||
| 143 | int (*define_fields)(struct ftrace_event_call *); | ||
| 144 | struct list_head *(*get_fields)(struct ftrace_event_call *); | ||
| 145 | struct list_head fields; | ||
| 146 | int (*raw_init)(struct ftrace_event_call *); | ||
| 147 | }; | ||
| 148 | |||
| 149 | enum { | ||
| 150 | TRACE_EVENT_FL_ENABLED_BIT, | ||
| 151 | TRACE_EVENT_FL_FILTERED_BIT, | ||
| 152 | }; | ||
| 153 | |||
| 154 | enum { | ||
| 155 | TRACE_EVENT_FL_ENABLED = (1 << TRACE_EVENT_FL_ENABLED_BIT), | ||
| 156 | TRACE_EVENT_FL_FILTERED = (1 << TRACE_EVENT_FL_FILTERED_BIT), | ||
| 157 | }; | ||
| 158 | |||
| 119 | struct ftrace_event_call { | 159 | struct ftrace_event_call { |
| 120 | struct list_head list; | 160 | struct list_head list; |
| 161 | struct ftrace_event_class *class; | ||
| 121 | char *name; | 162 | char *name; |
| 122 | char *system; | ||
| 123 | struct dentry *dir; | 163 | struct dentry *dir; |
| 124 | struct trace_event *event; | 164 | struct trace_event event; |
| 125 | int enabled; | ||
| 126 | int (*regfunc)(struct ftrace_event_call *); | ||
| 127 | void (*unregfunc)(struct ftrace_event_call *); | ||
| 128 | int id; | ||
| 129 | const char *print_fmt; | 165 | const char *print_fmt; |
| 130 | int (*raw_init)(struct ftrace_event_call *); | ||
| 131 | int (*define_fields)(struct ftrace_event_call *); | ||
| 132 | struct list_head fields; | ||
| 133 | int filter_active; | ||
| 134 | struct event_filter *filter; | 166 | struct event_filter *filter; |
| 135 | void *mod; | 167 | void *mod; |
| 136 | void *data; | 168 | void *data; |
| 137 | 169 | ||
| 170 | /* | ||
| 171 | * 32 bit flags: | ||
| 172 | * bit 1: enabled | ||
| 173 | * bit 2: filter_active | ||
| 174 | * | ||
| 175 | * Changes to flags must hold the event_mutex. | ||
| 176 | * | ||
| 177 | * Note: Reads of flags do not hold the event_mutex since | ||
| 178 | * they occur in critical sections. But the way flags | ||
| 179 | * is currently used, these changes do no affect the code | ||
| 180 | * except that when a change is made, it may have a slight | ||
| 181 | * delay in propagating the changes to other CPUs due to | ||
| 182 | * caching and such. | ||
| 183 | */ | ||
| 184 | unsigned int flags; | ||
| 185 | |||
| 186 | #ifdef CONFIG_PERF_EVENTS | ||
| 138 | int perf_refcount; | 187 | int perf_refcount; |
| 139 | int (*perf_event_enable)(struct ftrace_event_call *); | 188 | struct hlist_head *perf_events; |
| 140 | void (*perf_event_disable)(struct ftrace_event_call *); | 189 | #endif |
| 141 | }; | 190 | }; |
| 142 | 191 | ||
| 143 | #define PERF_MAX_TRACE_SIZE 2048 | 192 | #define PERF_MAX_TRACE_SIZE 2048 |
| @@ -194,24 +243,22 @@ struct perf_event; | |||
| 194 | 243 | ||
| 195 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); | 244 | DECLARE_PER_CPU(struct pt_regs, perf_trace_regs); |
| 196 | 245 | ||
| 197 | extern int perf_trace_enable(int event_id); | 246 | extern int perf_trace_init(struct perf_event *event); |
| 198 | extern void perf_trace_disable(int event_id); | 247 | extern void perf_trace_destroy(struct perf_event *event); |
| 199 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | 248 | extern int perf_trace_enable(struct perf_event *event); |
| 249 | extern void perf_trace_disable(struct perf_event *event); | ||
| 250 | extern int ftrace_profile_set_filter(struct perf_event *event, int event_id, | ||
| 200 | char *filter_str); | 251 | char *filter_str); |
| 201 | extern void ftrace_profile_free_filter(struct perf_event *event); | 252 | extern void ftrace_profile_free_filter(struct perf_event *event); |
| 202 | extern void * | 253 | extern void *perf_trace_buf_prepare(int size, unsigned short type, |
| 203 | perf_trace_buf_prepare(int size, unsigned short type, int *rctxp, | 254 | struct pt_regs *regs, int *rctxp); |
| 204 | unsigned long *irq_flags); | ||
| 205 | 255 | ||
| 206 | static inline void | 256 | static inline void |
| 207 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, | 257 | perf_trace_buf_submit(void *raw_data, int size, int rctx, u64 addr, |
| 208 | u64 count, unsigned long irq_flags, struct pt_regs *regs) | 258 | u64 count, struct pt_regs *regs, void *head) |
| 209 | { | 259 | { |
| 210 | struct trace_entry *entry = raw_data; | 260 | perf_tp_event(addr, count, raw_data, size, regs, head); |
| 211 | |||
| 212 | perf_tp_event(entry->type, addr, count, raw_data, size, regs); | ||
| 213 | perf_swevent_put_recursion_context(rctx); | 261 | perf_swevent_put_recursion_context(rctx); |
| 214 | local_irq_restore(irq_flags); | ||
| 215 | } | 262 | } |
| 216 | #endif | 263 | #endif |
| 217 | 264 | ||
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index 3fd5c82e0e18..fb6c91eac7e3 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h | |||
| @@ -485,6 +485,7 @@ struct perf_guest_info_callbacks { | |||
| 485 | #include <linux/ftrace.h> | 485 | #include <linux/ftrace.h> |
| 486 | #include <linux/cpu.h> | 486 | #include <linux/cpu.h> |
| 487 | #include <asm/atomic.h> | 487 | #include <asm/atomic.h> |
| 488 | #include <asm/local.h> | ||
| 488 | 489 | ||
| 489 | #define PERF_MAX_STACK_DEPTH 255 | 490 | #define PERF_MAX_STACK_DEPTH 255 |
| 490 | 491 | ||
| @@ -587,21 +588,19 @@ struct perf_mmap_data { | |||
| 587 | struct rcu_head rcu_head; | 588 | struct rcu_head rcu_head; |
| 588 | #ifdef CONFIG_PERF_USE_VMALLOC | 589 | #ifdef CONFIG_PERF_USE_VMALLOC |
| 589 | struct work_struct work; | 590 | struct work_struct work; |
| 591 | int page_order; /* allocation order */ | ||
| 590 | #endif | 592 | #endif |
| 591 | int data_order; | ||
| 592 | int nr_pages; /* nr of data pages */ | 593 | int nr_pages; /* nr of data pages */ |
| 593 | int writable; /* are we writable */ | 594 | int writable; /* are we writable */ |
| 594 | int nr_locked; /* nr pages mlocked */ | 595 | int nr_locked; /* nr pages mlocked */ |
| 595 | 596 | ||
| 596 | atomic_t poll; /* POLL_ for wakeups */ | 597 | atomic_t poll; /* POLL_ for wakeups */ |
| 597 | atomic_t events; /* event_id limit */ | ||
| 598 | 598 | ||
| 599 | atomic_long_t head; /* write position */ | 599 | local_t head; /* write position */ |
| 600 | atomic_long_t done_head; /* completed head */ | 600 | local_t nest; /* nested writers */ |
| 601 | 601 | local_t events; /* event limit */ | |
| 602 | atomic_t lock; /* concurrent writes */ | 602 | local_t wakeup; /* wakeup stamp */ |
| 603 | atomic_t wakeup; /* needs a wakeup */ | 603 | local_t lost; /* nr records lost */ |
| 604 | atomic_t lost; /* nr records lost */ | ||
| 605 | 604 | ||
| 606 | long watermark; /* wakeup watermark */ | 605 | long watermark; /* wakeup watermark */ |
| 607 | 606 | ||
| @@ -728,6 +727,7 @@ struct perf_event { | |||
| 728 | perf_overflow_handler_t overflow_handler; | 727 | perf_overflow_handler_t overflow_handler; |
| 729 | 728 | ||
| 730 | #ifdef CONFIG_EVENT_TRACING | 729 | #ifdef CONFIG_EVENT_TRACING |
| 730 | struct ftrace_event_call *tp_event; | ||
| 731 | struct event_filter *filter; | 731 | struct event_filter *filter; |
| 732 | #endif | 732 | #endif |
| 733 | 733 | ||
| @@ -803,11 +803,12 @@ struct perf_cpu_context { | |||
| 803 | struct perf_output_handle { | 803 | struct perf_output_handle { |
| 804 | struct perf_event *event; | 804 | struct perf_event *event; |
| 805 | struct perf_mmap_data *data; | 805 | struct perf_mmap_data *data; |
| 806 | unsigned long head; | 806 | unsigned long wakeup; |
| 807 | unsigned long offset; | 807 | unsigned long size; |
| 808 | void *addr; | ||
| 809 | int page; | ||
| 808 | int nmi; | 810 | int nmi; |
| 809 | int sample; | 811 | int sample; |
| 810 | int locked; | ||
| 811 | }; | 812 | }; |
| 812 | 813 | ||
| 813 | #ifdef CONFIG_PERF_EVENTS | 814 | #ifdef CONFIG_PERF_EVENTS |
| @@ -993,8 +994,9 @@ static inline bool perf_paranoid_kernel(void) | |||
| 993 | } | 994 | } |
| 994 | 995 | ||
| 995 | extern void perf_event_init(void); | 996 | extern void perf_event_init(void); |
| 996 | extern void perf_tp_event(int event_id, u64 addr, u64 count, void *record, | 997 | extern void perf_tp_event(u64 addr, u64 count, void *record, |
| 997 | int entry_size, struct pt_regs *regs); | 998 | int entry_size, struct pt_regs *regs, |
| 999 | struct hlist_head *head); | ||
| 998 | extern void perf_bp_event(struct perf_event *event, void *data); | 1000 | extern void perf_bp_event(struct perf_event *event, void *data); |
| 999 | 1001 | ||
| 1000 | #ifndef perf_misc_flags | 1002 | #ifndef perf_misc_flags |
diff --git a/include/linux/syscalls.h b/include/linux/syscalls.h index 057929b0a651..a1a86a53bc73 100644 --- a/include/linux/syscalls.h +++ b/include/linux/syscalls.h | |||
| @@ -103,22 +103,6 @@ struct perf_event_attr; | |||
| 103 | #define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) | 103 | #define __SC_TEST5(t5, a5, ...) __SC_TEST(t5); __SC_TEST4(__VA_ARGS__) |
| 104 | #define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) | 104 | #define __SC_TEST6(t6, a6, ...) __SC_TEST(t6); __SC_TEST5(__VA_ARGS__) |
| 105 | 105 | ||
| 106 | #ifdef CONFIG_PERF_EVENTS | ||
| 107 | |||
| 108 | #define TRACE_SYS_ENTER_PERF_INIT(sname) \ | ||
| 109 | .perf_event_enable = perf_sysenter_enable, \ | ||
| 110 | .perf_event_disable = perf_sysenter_disable, | ||
| 111 | |||
| 112 | #define TRACE_SYS_EXIT_PERF_INIT(sname) \ | ||
| 113 | .perf_event_enable = perf_sysexit_enable, \ | ||
| 114 | .perf_event_disable = perf_sysexit_disable, | ||
| 115 | #else | ||
| 116 | #define TRACE_SYS_ENTER_PERF(sname) | ||
| 117 | #define TRACE_SYS_ENTER_PERF_INIT(sname) | ||
| 118 | #define TRACE_SYS_EXIT_PERF(sname) | ||
| 119 | #define TRACE_SYS_EXIT_PERF_INIT(sname) | ||
| 120 | #endif /* CONFIG_PERF_EVENTS */ | ||
| 121 | |||
| 122 | #ifdef CONFIG_FTRACE_SYSCALLS | 106 | #ifdef CONFIG_FTRACE_SYSCALLS |
| 123 | #define __SC_STR_ADECL1(t, a) #a | 107 | #define __SC_STR_ADECL1(t, a) #a |
| 124 | #define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__) | 108 | #define __SC_STR_ADECL2(t, a, ...) #a, __SC_STR_ADECL1(__VA_ARGS__) |
| @@ -134,54 +118,43 @@ struct perf_event_attr; | |||
| 134 | #define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__) | 118 | #define __SC_STR_TDECL5(t, a, ...) #t, __SC_STR_TDECL4(__VA_ARGS__) |
| 135 | #define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__) | 119 | #define __SC_STR_TDECL6(t, a, ...) #t, __SC_STR_TDECL5(__VA_ARGS__) |
| 136 | 120 | ||
| 121 | extern struct ftrace_event_class event_class_syscall_enter; | ||
| 122 | extern struct ftrace_event_class event_class_syscall_exit; | ||
| 123 | extern struct trace_event_functions enter_syscall_print_funcs; | ||
| 124 | extern struct trace_event_functions exit_syscall_print_funcs; | ||
| 125 | |||
| 137 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ | 126 | #define SYSCALL_TRACE_ENTER_EVENT(sname) \ |
| 138 | static const struct syscall_metadata __syscall_meta_##sname; \ | 127 | static struct syscall_metadata __syscall_meta_##sname; \ |
| 139 | static struct ftrace_event_call \ | 128 | static struct ftrace_event_call \ |
| 140 | __attribute__((__aligned__(4))) event_enter_##sname; \ | 129 | __attribute__((__aligned__(4))) event_enter_##sname; \ |
| 141 | static struct trace_event enter_syscall_print_##sname = { \ | ||
| 142 | .trace = print_syscall_enter, \ | ||
| 143 | }; \ | ||
| 144 | static struct ftrace_event_call __used \ | 130 | static struct ftrace_event_call __used \ |
| 145 | __attribute__((__aligned__(4))) \ | 131 | __attribute__((__aligned__(4))) \ |
| 146 | __attribute__((section("_ftrace_events"))) \ | 132 | __attribute__((section("_ftrace_events"))) \ |
| 147 | event_enter_##sname = { \ | 133 | event_enter_##sname = { \ |
| 148 | .name = "sys_enter"#sname, \ | 134 | .name = "sys_enter"#sname, \ |
| 149 | .system = "syscalls", \ | 135 | .class = &event_class_syscall_enter, \ |
| 150 | .event = &enter_syscall_print_##sname, \ | 136 | .event.funcs = &enter_syscall_print_funcs, \ |
| 151 | .raw_init = init_syscall_trace, \ | ||
| 152 | .define_fields = syscall_enter_define_fields, \ | ||
| 153 | .regfunc = reg_event_syscall_enter, \ | ||
| 154 | .unregfunc = unreg_event_syscall_enter, \ | ||
| 155 | .data = (void *)&__syscall_meta_##sname,\ | 137 | .data = (void *)&__syscall_meta_##sname,\ |
| 156 | TRACE_SYS_ENTER_PERF_INIT(sname) \ | ||
| 157 | } | 138 | } |
| 158 | 139 | ||
| 159 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ | 140 | #define SYSCALL_TRACE_EXIT_EVENT(sname) \ |
| 160 | static const struct syscall_metadata __syscall_meta_##sname; \ | 141 | static struct syscall_metadata __syscall_meta_##sname; \ |
| 161 | static struct ftrace_event_call \ | 142 | static struct ftrace_event_call \ |
| 162 | __attribute__((__aligned__(4))) event_exit_##sname; \ | 143 | __attribute__((__aligned__(4))) event_exit_##sname; \ |
| 163 | static struct trace_event exit_syscall_print_##sname = { \ | ||
| 164 | .trace = print_syscall_exit, \ | ||
| 165 | }; \ | ||
| 166 | static struct ftrace_event_call __used \ | 144 | static struct ftrace_event_call __used \ |
| 167 | __attribute__((__aligned__(4))) \ | 145 | __attribute__((__aligned__(4))) \ |
| 168 | __attribute__((section("_ftrace_events"))) \ | 146 | __attribute__((section("_ftrace_events"))) \ |
| 169 | event_exit_##sname = { \ | 147 | event_exit_##sname = { \ |
| 170 | .name = "sys_exit"#sname, \ | 148 | .name = "sys_exit"#sname, \ |
| 171 | .system = "syscalls", \ | 149 | .class = &event_class_syscall_exit, \ |
| 172 | .event = &exit_syscall_print_##sname, \ | 150 | .event.funcs = &exit_syscall_print_funcs, \ |
| 173 | .raw_init = init_syscall_trace, \ | ||
| 174 | .define_fields = syscall_exit_define_fields, \ | ||
| 175 | .regfunc = reg_event_syscall_exit, \ | ||
| 176 | .unregfunc = unreg_event_syscall_exit, \ | ||
| 177 | .data = (void *)&__syscall_meta_##sname,\ | 151 | .data = (void *)&__syscall_meta_##sname,\ |
| 178 | TRACE_SYS_EXIT_PERF_INIT(sname) \ | ||
| 179 | } | 152 | } |
| 180 | 153 | ||
| 181 | #define SYSCALL_METADATA(sname, nb) \ | 154 | #define SYSCALL_METADATA(sname, nb) \ |
| 182 | SYSCALL_TRACE_ENTER_EVENT(sname); \ | 155 | SYSCALL_TRACE_ENTER_EVENT(sname); \ |
| 183 | SYSCALL_TRACE_EXIT_EVENT(sname); \ | 156 | SYSCALL_TRACE_EXIT_EVENT(sname); \ |
| 184 | static const struct syscall_metadata __used \ | 157 | static struct syscall_metadata __used \ |
| 185 | __attribute__((__aligned__(4))) \ | 158 | __attribute__((__aligned__(4))) \ |
| 186 | __attribute__((section("__syscalls_metadata"))) \ | 159 | __attribute__((section("__syscalls_metadata"))) \ |
| 187 | __syscall_meta_##sname = { \ | 160 | __syscall_meta_##sname = { \ |
| @@ -191,12 +164,14 @@ struct perf_event_attr; | |||
| 191 | .args = args_##sname, \ | 164 | .args = args_##sname, \ |
| 192 | .enter_event = &event_enter_##sname, \ | 165 | .enter_event = &event_enter_##sname, \ |
| 193 | .exit_event = &event_exit_##sname, \ | 166 | .exit_event = &event_exit_##sname, \ |
| 167 | .enter_fields = LIST_HEAD_INIT(__syscall_meta_##sname.enter_fields), \ | ||
| 168 | .exit_fields = LIST_HEAD_INIT(__syscall_meta_##sname.exit_fields), \ | ||
| 194 | }; | 169 | }; |
| 195 | 170 | ||
| 196 | #define SYSCALL_DEFINE0(sname) \ | 171 | #define SYSCALL_DEFINE0(sname) \ |
| 197 | SYSCALL_TRACE_ENTER_EVENT(_##sname); \ | 172 | SYSCALL_TRACE_ENTER_EVENT(_##sname); \ |
| 198 | SYSCALL_TRACE_EXIT_EVENT(_##sname); \ | 173 | SYSCALL_TRACE_EXIT_EVENT(_##sname); \ |
| 199 | static const struct syscall_metadata __used \ | 174 | static struct syscall_metadata __used \ |
| 200 | __attribute__((__aligned__(4))) \ | 175 | __attribute__((__aligned__(4))) \ |
| 201 | __attribute__((section("__syscalls_metadata"))) \ | 176 | __attribute__((section("__syscalls_metadata"))) \ |
| 202 | __syscall_meta__##sname = { \ | 177 | __syscall_meta__##sname = { \ |
| @@ -204,6 +179,8 @@ struct perf_event_attr; | |||
| 204 | .nb_args = 0, \ | 179 | .nb_args = 0, \ |
| 205 | .enter_event = &event_enter__##sname, \ | 180 | .enter_event = &event_enter__##sname, \ |
| 206 | .exit_event = &event_exit__##sname, \ | 181 | .exit_event = &event_exit__##sname, \ |
| 182 | .enter_fields = LIST_HEAD_INIT(__syscall_meta__##sname.enter_fields), \ | ||
| 183 | .exit_fields = LIST_HEAD_INIT(__syscall_meta__##sname.exit_fields), \ | ||
| 207 | }; \ | 184 | }; \ |
| 208 | asmlinkage long sys_##sname(void) | 185 | asmlinkage long sys_##sname(void) |
| 209 | #else | 186 | #else |
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 1d85f9a6a199..9a59d1f98cd4 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
| @@ -20,12 +20,17 @@ | |||
| 20 | struct module; | 20 | struct module; |
| 21 | struct tracepoint; | 21 | struct tracepoint; |
| 22 | 22 | ||
| 23 | struct tracepoint_func { | ||
| 24 | void *func; | ||
| 25 | void *data; | ||
| 26 | }; | ||
| 27 | |||
| 23 | struct tracepoint { | 28 | struct tracepoint { |
| 24 | const char *name; /* Tracepoint name */ | 29 | const char *name; /* Tracepoint name */ |
| 25 | int state; /* State. */ | 30 | int state; /* State. */ |
| 26 | void (*regfunc)(void); | 31 | void (*regfunc)(void); |
| 27 | void (*unregfunc)(void); | 32 | void (*unregfunc)(void); |
| 28 | void **funcs; | 33 | struct tracepoint_func *funcs; |
| 29 | } __attribute__((aligned(32))); /* | 34 | } __attribute__((aligned(32))); /* |
| 30 | * Aligned on 32 bytes because it is | 35 | * Aligned on 32 bytes because it is |
| 31 | * globally visible and gcc happily | 36 | * globally visible and gcc happily |
| @@ -37,16 +42,19 @@ struct tracepoint { | |||
| 37 | * Connect a probe to a tracepoint. | 42 | * Connect a probe to a tracepoint. |
| 38 | * Internal API, should not be used directly. | 43 | * Internal API, should not be used directly. |
| 39 | */ | 44 | */ |
| 40 | extern int tracepoint_probe_register(const char *name, void *probe); | 45 | extern int tracepoint_probe_register(const char *name, void *probe, void *data); |
| 41 | 46 | ||
| 42 | /* | 47 | /* |
| 43 | * Disconnect a probe from a tracepoint. | 48 | * Disconnect a probe from a tracepoint. |
| 44 | * Internal API, should not be used directly. | 49 | * Internal API, should not be used directly. |
| 45 | */ | 50 | */ |
| 46 | extern int tracepoint_probe_unregister(const char *name, void *probe); | 51 | extern int |
| 52 | tracepoint_probe_unregister(const char *name, void *probe, void *data); | ||
| 47 | 53 | ||
| 48 | extern int tracepoint_probe_register_noupdate(const char *name, void *probe); | 54 | extern int tracepoint_probe_register_noupdate(const char *name, void *probe, |
| 49 | extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe); | 55 | void *data); |
| 56 | extern int tracepoint_probe_unregister_noupdate(const char *name, void *probe, | ||
| 57 | void *data); | ||
| 50 | extern void tracepoint_probe_update_all(void); | 58 | extern void tracepoint_probe_update_all(void); |
| 51 | 59 | ||
| 52 | struct tracepoint_iter { | 60 | struct tracepoint_iter { |
| @@ -102,17 +110,27 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
| 102 | /* | 110 | /* |
| 103 | * it_func[0] is never NULL because there is at least one element in the array | 111 | * it_func[0] is never NULL because there is at least one element in the array |
| 104 | * when the array itself is non NULL. | 112 | * when the array itself is non NULL. |
| 113 | * | ||
| 114 | * Note, the proto and args passed in includes "__data" as the first parameter. | ||
| 115 | * The reason for this is to handle the "void" prototype. If a tracepoint | ||
| 116 | * has a "void" prototype, then it is invalid to declare a function | ||
| 117 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just | ||
| 118 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". | ||
| 105 | */ | 119 | */ |
| 106 | #define __DO_TRACE(tp, proto, args) \ | 120 | #define __DO_TRACE(tp, proto, args) \ |
| 107 | do { \ | 121 | do { \ |
| 108 | void **it_func; \ | 122 | struct tracepoint_func *it_func_ptr; \ |
| 123 | void *it_func; \ | ||
| 124 | void *__data; \ | ||
| 109 | \ | 125 | \ |
| 110 | rcu_read_lock_sched_notrace(); \ | 126 | rcu_read_lock_sched_notrace(); \ |
| 111 | it_func = rcu_dereference_sched((tp)->funcs); \ | 127 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ |
| 112 | if (it_func) { \ | 128 | if (it_func_ptr) { \ |
| 113 | do { \ | 129 | do { \ |
| 114 | ((void(*)(proto))(*it_func))(args); \ | 130 | it_func = (it_func_ptr)->func; \ |
| 115 | } while (*(++it_func)); \ | 131 | __data = (it_func_ptr)->data; \ |
| 132 | ((void(*)(proto))(it_func))(args); \ | ||
| 133 | } while ((++it_func_ptr)->func); \ | ||
| 116 | } \ | 134 | } \ |
| 117 | rcu_read_unlock_sched_notrace(); \ | 135 | rcu_read_unlock_sched_notrace(); \ |
| 118 | } while (0) | 136 | } while (0) |
| @@ -122,24 +140,32 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
| 122 | * not add unwanted padding between the beginning of the section and the | 140 | * not add unwanted padding between the beginning of the section and the |
| 123 | * structure. Force alignment to the same alignment as the section start. | 141 | * structure. Force alignment to the same alignment as the section start. |
| 124 | */ | 142 | */ |
| 125 | #define DECLARE_TRACE(name, proto, args) \ | 143 | #define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ |
| 126 | extern struct tracepoint __tracepoint_##name; \ | 144 | extern struct tracepoint __tracepoint_##name; \ |
| 127 | static inline void trace_##name(proto) \ | 145 | static inline void trace_##name(proto) \ |
| 128 | { \ | 146 | { \ |
| 129 | if (unlikely(__tracepoint_##name.state)) \ | 147 | if (unlikely(__tracepoint_##name.state)) \ |
| 130 | __DO_TRACE(&__tracepoint_##name, \ | 148 | __DO_TRACE(&__tracepoint_##name, \ |
| 131 | TP_PROTO(proto), TP_ARGS(args)); \ | 149 | TP_PROTO(data_proto), \ |
| 150 | TP_ARGS(data_args)); \ | ||
| 151 | } \ | ||
| 152 | static inline int \ | ||
| 153 | register_trace_##name(void (*probe)(data_proto), void *data) \ | ||
| 154 | { \ | ||
| 155 | return tracepoint_probe_register(#name, (void *)probe, \ | ||
| 156 | data); \ | ||
| 132 | } \ | 157 | } \ |
| 133 | static inline int register_trace_##name(void (*probe)(proto)) \ | 158 | static inline int \ |
| 159 | unregister_trace_##name(void (*probe)(data_proto), void *data) \ | ||
| 134 | { \ | 160 | { \ |
| 135 | return tracepoint_probe_register(#name, (void *)probe); \ | 161 | return tracepoint_probe_unregister(#name, (void *)probe, \ |
| 162 | data); \ | ||
| 136 | } \ | 163 | } \ |
| 137 | static inline int unregister_trace_##name(void (*probe)(proto)) \ | 164 | static inline void \ |
| 165 | check_trace_callback_type_##name(void (*cb)(data_proto)) \ | ||
| 138 | { \ | 166 | { \ |
| 139 | return tracepoint_probe_unregister(#name, (void *)probe);\ | ||
| 140 | } | 167 | } |
| 141 | 168 | ||
| 142 | |||
| 143 | #define DEFINE_TRACE_FN(name, reg, unreg) \ | 169 | #define DEFINE_TRACE_FN(name, reg, unreg) \ |
| 144 | static const char __tpstrtab_##name[] \ | 170 | static const char __tpstrtab_##name[] \ |
| 145 | __attribute__((section("__tracepoints_strings"))) = #name; \ | 171 | __attribute__((section("__tracepoints_strings"))) = #name; \ |
| @@ -156,18 +182,23 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
| 156 | EXPORT_SYMBOL(__tracepoint_##name) | 182 | EXPORT_SYMBOL(__tracepoint_##name) |
| 157 | 183 | ||
| 158 | #else /* !CONFIG_TRACEPOINTS */ | 184 | #else /* !CONFIG_TRACEPOINTS */ |
| 159 | #define DECLARE_TRACE(name, proto, args) \ | 185 | #define __DECLARE_TRACE(name, proto, args, data_proto, data_args) \ |
| 160 | static inline void _do_trace_##name(struct tracepoint *tp, proto) \ | ||
| 161 | { } \ | ||
| 162 | static inline void trace_##name(proto) \ | 186 | static inline void trace_##name(proto) \ |
| 163 | { } \ | 187 | { } \ |
| 164 | static inline int register_trace_##name(void (*probe)(proto)) \ | 188 | static inline int \ |
| 189 | register_trace_##name(void (*probe)(data_proto), \ | ||
| 190 | void *data) \ | ||
| 165 | { \ | 191 | { \ |
| 166 | return -ENOSYS; \ | 192 | return -ENOSYS; \ |
| 167 | } \ | 193 | } \ |
| 168 | static inline int unregister_trace_##name(void (*probe)(proto)) \ | 194 | static inline int \ |
| 195 | unregister_trace_##name(void (*probe)(data_proto), \ | ||
| 196 | void *data) \ | ||
| 169 | { \ | 197 | { \ |
| 170 | return -ENOSYS; \ | 198 | return -ENOSYS; \ |
| 199 | } \ | ||
| 200 | static inline void check_trace_callback_type_##name(void (*cb)(data_proto)) \ | ||
| 201 | { \ | ||
| 171 | } | 202 | } |
| 172 | 203 | ||
| 173 | #define DEFINE_TRACE_FN(name, reg, unreg) | 204 | #define DEFINE_TRACE_FN(name, reg, unreg) |
| @@ -176,6 +207,29 @@ static inline void tracepoint_update_probe_range(struct tracepoint *begin, | |||
| 176 | #define EXPORT_TRACEPOINT_SYMBOL(name) | 207 | #define EXPORT_TRACEPOINT_SYMBOL(name) |
| 177 | 208 | ||
| 178 | #endif /* CONFIG_TRACEPOINTS */ | 209 | #endif /* CONFIG_TRACEPOINTS */ |
| 210 | |||
| 211 | /* | ||
| 212 | * The need for the DECLARE_TRACE_NOARGS() is to handle the prototype | ||
| 213 | * (void). "void" is a special value in a function prototype and can | ||
| 214 | * not be combined with other arguments. Since the DECLARE_TRACE() | ||
| 215 | * macro adds a data element at the beginning of the prototype, | ||
| 216 | * we need a way to differentiate "(void *data, proto)" from | ||
| 217 | * "(void *data, void)". The second prototype is invalid. | ||
| 218 | * | ||
| 219 | * DECLARE_TRACE_NOARGS() passes "void" as the tracepoint prototype | ||
| 220 | * and "void *__data" as the callback prototype. | ||
| 221 | * | ||
| 222 | * DECLARE_TRACE() passes "proto" as the tracepoint protoype and | ||
| 223 | * "void *__data, proto" as the callback prototype. | ||
| 224 | */ | ||
| 225 | #define DECLARE_TRACE_NOARGS(name) \ | ||
| 226 | __DECLARE_TRACE(name, void, , void *__data, __data) | ||
| 227 | |||
| 228 | #define DECLARE_TRACE(name, proto, args) \ | ||
| 229 | __DECLARE_TRACE(name, PARAMS(proto), PARAMS(args), \ | ||
| 230 | PARAMS(void *__data, proto), \ | ||
| 231 | PARAMS(__data, args)) | ||
| 232 | |||
| 179 | #endif /* DECLARE_TRACE */ | 233 | #endif /* DECLARE_TRACE */ |
| 180 | 234 | ||
| 181 | #ifndef TRACE_EVENT | 235 | #ifndef TRACE_EVENT |
