aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2010-04-22 10:35:55 -0400
committerSteven Rostedt <rostedt@goodmis.org>2010-05-14 14:20:23 -0400
commit2e33af029556cb8bd22bf4f86f42d540249177ea (patch)
tree8a479d21300c7692d61093846054f626e3e71ed5 /kernel/trace
parent2239291aeb0379fe47980b0e560e0eb9fd7e82ec (diff)
tracing: Move fields from event to class structure
Move the defined fields from the event to the class structure. Since the fields of the event are defined by the class they belong to, it makes sense to have the class hold the information instead of the individual events. The events of the same class would just hold duplicate information. After this change the size of the kernel dropped another 3K: text data bss dec hex filename 4913961 1088356 861512 6863829 68bbd5 vmlinux.orig 4900252 1057412 861512 6819176 680d68 vmlinux.regs 4900375 1053380 861512 6815267 67fe23 vmlinux.fields Although the text increased, this was mainly due to the C files having to adapt to the change. This is a constant increase, where new tracepoints will not increase the Text. But the big drop is in the data size (as well as needed allocations to hold the fields). This will give even more savings as more tracepoints are created. Note, if just TRACE_EVENT()s are used and not DECLARE_EVENT_CLASS() with several DEFINE_EVENT()s, then the savings will be lost. But we are pushing developers to consolidate events with DEFINE_EVENT() so this should not be an issue. The kprobes define a unique class to every new event, but are dynamic so it should not be a issue. The syscalls however have a single class but the fields for the individual events are different. The syscalls use a metadata to define the fields. I moved the fields list from the event to the metadata and added a "get_fields()" function to the class. This function is used to find the fields. For normal events and kprobes, get_fields() just returns a pointer to the fields list_head in the class. For syscall events, it returns the fields list_head in the metadata for the event. v2: Fixed the syscall fields. The syscall metadata needs a list of fields for both enter and exit. Acked-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Mathieu Desnoyers <mathieu.desnoyers@efficios.com> Acked-by: Masami Hiramatsu <mhiramat@redhat.com> Cc: Tom Zanussi <tzanussi@gmail.com> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace.h3
-rw-r--r--kernel/trace/trace_events.c48
-rw-r--r--kernel/trace/trace_events_filter.c10
-rw-r--r--kernel/trace/trace_export.c14
-rw-r--r--kernel/trace/trace_kprobe.c8
-rw-r--r--kernel/trace/trace_syscalls.c31
6 files changed, 83 insertions, 31 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 911e9864e94a..c88c563a59a5 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -794,6 +794,9 @@ extern void print_subsystem_event_filter(struct event_subsystem *system,
794 struct trace_seq *s); 794 struct trace_seq *s);
795extern int filter_assign_type(const char *type); 795extern int filter_assign_type(const char *type);
796 796
797struct list_head *
798trace_get_fields(struct ftrace_event_call *event_call);
799
797static inline int 800static inline int
798filter_check_discard(struct ftrace_event_call *call, void *rec, 801filter_check_discard(struct ftrace_event_call *call, void *rec,
799 struct ring_buffer *buffer, 802 struct ring_buffer *buffer,
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 19d1eb0a7188..acc0f55742c3 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -29,11 +29,23 @@ DEFINE_MUTEX(event_mutex);
29 29
30LIST_HEAD(ftrace_events); 30LIST_HEAD(ftrace_events);
31 31
32struct list_head *
33trace_get_fields(struct ftrace_event_call *event_call)
34{
35 if (!event_call->class->get_fields)
36 return &event_call->class->fields;
37 return event_call->class->get_fields(event_call);
38}
39
32int trace_define_field(struct ftrace_event_call *call, const char *type, 40int trace_define_field(struct ftrace_event_call *call, const char *type,
33 const char *name, int offset, int size, int is_signed, 41 const char *name, int offset, int size, int is_signed,
34 int filter_type) 42 int filter_type)
35{ 43{
36 struct ftrace_event_field *field; 44 struct ftrace_event_field *field;
45 struct list_head *head;
46
47 if (WARN_ON(!call->class))
48 return 0;
37 49
38 field = kzalloc(sizeof(*field), GFP_KERNEL); 50 field = kzalloc(sizeof(*field), GFP_KERNEL);
39 if (!field) 51 if (!field)
@@ -56,7 +68,8 @@ int trace_define_field(struct ftrace_event_call *call, const char *type,
56 field->size = size; 68 field->size = size;
57 field->is_signed = is_signed; 69 field->is_signed = is_signed;
58 70
59 list_add(&field->link, &call->fields); 71 head = trace_get_fields(call);
72 list_add(&field->link, head);
60 73
61 return 0; 74 return 0;
62 75
@@ -94,8 +107,10 @@ static int trace_define_common_fields(struct ftrace_event_call *call)
94void trace_destroy_fields(struct ftrace_event_call *call) 107void trace_destroy_fields(struct ftrace_event_call *call)
95{ 108{
96 struct ftrace_event_field *field, *next; 109 struct ftrace_event_field *field, *next;
110 struct list_head *head;
97 111
98 list_for_each_entry_safe(field, next, &call->fields, link) { 112 head = trace_get_fields(call);
113 list_for_each_entry_safe(field, next, head, link) {
99 list_del(&field->link); 114 list_del(&field->link);
100 kfree(field->type); 115 kfree(field->type);
101 kfree(field->name); 116 kfree(field->name);
@@ -111,7 +126,6 @@ int trace_event_raw_init(struct ftrace_event_call *call)
111 if (!id) 126 if (!id)
112 return -ENODEV; 127 return -ENODEV;
113 call->id = id; 128 call->id = id;
114 INIT_LIST_HEAD(&call->fields);
115 129
116 return 0; 130 return 0;
117} 131}
@@ -537,6 +551,7 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
537{ 551{
538 struct ftrace_event_call *call = filp->private_data; 552 struct ftrace_event_call *call = filp->private_data;
539 struct ftrace_event_field *field; 553 struct ftrace_event_field *field;
554 struct list_head *head;
540 struct trace_seq *s; 555 struct trace_seq *s;
541 int common_field_count = 5; 556 int common_field_count = 5;
542 char *buf; 557 char *buf;
@@ -555,7 +570,8 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
555 trace_seq_printf(s, "ID: %d\n", call->id); 570 trace_seq_printf(s, "ID: %d\n", call->id);
556 trace_seq_printf(s, "format:\n"); 571 trace_seq_printf(s, "format:\n");
557 572
558 list_for_each_entry_reverse(field, &call->fields, link) { 573 head = trace_get_fields(call);
574 list_for_each_entry_reverse(field, head, link) {
559 /* 575 /*
560 * Smartly shows the array type(except dynamic array). 576 * Smartly shows the array type(except dynamic array).
561 * Normal: 577 * Normal:
@@ -931,6 +947,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
931 const struct file_operations *filter, 947 const struct file_operations *filter,
932 const struct file_operations *format) 948 const struct file_operations *format)
933{ 949{
950 struct list_head *head;
934 int ret; 951 int ret;
935 952
936 /* 953 /*
@@ -957,14 +974,21 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
957 id); 974 id);
958#endif 975#endif
959 976
960 if (call->define_fields) { 977 if (call->class->define_fields) {
961 ret = trace_define_common_fields(call); 978 /*
962 if (!ret) 979 * Other events may have the same class. Only update
963 ret = call->define_fields(call); 980 * the fields if they are not already defined.
964 if (ret < 0) { 981 */
965 pr_warning("Could not initialize trace point" 982 head = trace_get_fields(call);
966 " events/%s\n", call->name); 983 if (list_empty(head)) {
967 return ret; 984 ret = trace_define_common_fields(call);
985 if (!ret)
986 ret = call->class->define_fields(call);
987 if (ret < 0) {
988 pr_warning("Could not initialize trace point"
989 " events/%s\n", call->name);
990 return ret;
991 }
968 } 992 }
969 trace_create_file("filter", 0644, call->dir, call, 993 trace_create_file("filter", 0644, call->dir, call,
970 filter); 994 filter);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index ca329603d0bf..961f99b74bdd 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -500,8 +500,10 @@ static struct ftrace_event_field *
500find_event_field(struct ftrace_event_call *call, char *name) 500find_event_field(struct ftrace_event_call *call, char *name)
501{ 501{
502 struct ftrace_event_field *field; 502 struct ftrace_event_field *field;
503 struct list_head *head;
503 504
504 list_for_each_entry(field, &call->fields, link) { 505 head = trace_get_fields(call);
506 list_for_each_entry(field, head, link) {
505 if (!strcmp(field->name, name)) 507 if (!strcmp(field->name, name))
506 return field; 508 return field;
507 } 509 }
@@ -625,7 +627,7 @@ static int init_subsystem_preds(struct event_subsystem *system)
625 int err; 627 int err;
626 628
627 list_for_each_entry(call, &ftrace_events, list) { 629 list_for_each_entry(call, &ftrace_events, list) {
628 if (!call->define_fields) 630 if (!call->class || !call->class->define_fields)
629 continue; 631 continue;
630 632
631 if (strcmp(call->class->system, system->name) != 0) 633 if (strcmp(call->class->system, system->name) != 0)
@@ -644,7 +646,7 @@ static void filter_free_subsystem_preds(struct event_subsystem *system)
644 struct ftrace_event_call *call; 646 struct ftrace_event_call *call;
645 647
646 list_for_each_entry(call, &ftrace_events, list) { 648 list_for_each_entry(call, &ftrace_events, list) {
647 if (!call->define_fields) 649 if (!call->class || !call->class->define_fields)
648 continue; 650 continue;
649 651
650 if (strcmp(call->class->system, system->name) != 0) 652 if (strcmp(call->class->system, system->name) != 0)
@@ -1249,7 +1251,7 @@ static int replace_system_preds(struct event_subsystem *system,
1249 list_for_each_entry(call, &ftrace_events, list) { 1251 list_for_each_entry(call, &ftrace_events, list) {
1250 struct event_filter *filter = call->filter; 1252 struct event_filter *filter = call->filter;
1251 1253
1252 if (!call->define_fields) 1254 if (!call->class || !call->class->define_fields)
1253 continue; 1255 continue;
1254 1256
1255 if (strcmp(call->class->system, system->name) != 0) 1257 if (strcmp(call->class->system, system->name) != 0)
diff --git a/kernel/trace/trace_export.c b/kernel/trace/trace_export.c
index 7f16e2163817..e700a0c1803f 100644
--- a/kernel/trace/trace_export.c
+++ b/kernel/trace/trace_export.c
@@ -18,10 +18,6 @@
18#undef TRACE_SYSTEM 18#undef TRACE_SYSTEM
19#define TRACE_SYSTEM ftrace 19#define TRACE_SYSTEM ftrace
20 20
21struct ftrace_event_class event_class_ftrace = {
22 .system = __stringify(TRACE_SYSTEM),
23};
24
25/* not needed for this file */ 21/* not needed for this file */
26#undef __field_struct 22#undef __field_struct
27#define __field_struct(type, item) 23#define __field_struct(type, item)
@@ -131,7 +127,7 @@ ftrace_define_fields_##name(struct ftrace_event_call *event_call) \
131 127
132static int ftrace_raw_init_event(struct ftrace_event_call *call) 128static int ftrace_raw_init_event(struct ftrace_event_call *call)
133{ 129{
134 INIT_LIST_HEAD(&call->fields); 130 INIT_LIST_HEAD(&call->class->fields);
135 return 0; 131 return 0;
136} 132}
137 133
@@ -159,15 +155,19 @@ static int ftrace_raw_init_event(struct ftrace_event_call *call)
159#undef FTRACE_ENTRY 155#undef FTRACE_ENTRY
160#define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \ 156#define FTRACE_ENTRY(call, struct_name, type, tstruct, print) \
161 \ 157 \
158struct ftrace_event_class event_class_ftrace_##call = { \
159 .system = __stringify(TRACE_SYSTEM), \
160 .define_fields = ftrace_define_fields_##call, \
161}; \
162 \
162struct ftrace_event_call __used \ 163struct ftrace_event_call __used \
163__attribute__((__aligned__(4))) \ 164__attribute__((__aligned__(4))) \
164__attribute__((section("_ftrace_events"))) event_##call = { \ 165__attribute__((section("_ftrace_events"))) event_##call = { \
165 .name = #call, \ 166 .name = #call, \
166 .id = type, \ 167 .id = type, \
167 .class = &event_class_ftrace, \ 168 .class = &event_class_ftrace_##call, \
168 .raw_init = ftrace_raw_init_event, \ 169 .raw_init = ftrace_raw_init_event, \
169 .print_fmt = print, \ 170 .print_fmt = print, \
170 .define_fields = ftrace_define_fields_##call, \
171}; \ 171}; \
172 172
173#include "trace_entries.h" 173#include "trace_entries.h"
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index f8af21a53f0c..b14bf745356f 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -1112,8 +1112,6 @@ static void probe_event_disable(struct ftrace_event_call *call)
1112 1112
1113static int probe_event_raw_init(struct ftrace_event_call *event_call) 1113static int probe_event_raw_init(struct ftrace_event_call *event_call)
1114{ 1114{
1115 INIT_LIST_HEAD(&event_call->fields);
1116
1117 return 0; 1115 return 0;
1118} 1116}
1119 1117
@@ -1362,11 +1360,13 @@ static int register_probe_event(struct trace_probe *tp)
1362 if (probe_is_return(tp)) { 1360 if (probe_is_return(tp)) {
1363 tp->event.trace = print_kretprobe_event; 1361 tp->event.trace = print_kretprobe_event;
1364 call->raw_init = probe_event_raw_init; 1362 call->raw_init = probe_event_raw_init;
1365 call->define_fields = kretprobe_event_define_fields; 1363 INIT_LIST_HEAD(&call->class->fields);
1364 call->class->define_fields = kretprobe_event_define_fields;
1366 } else { 1365 } else {
1367 tp->event.trace = print_kprobe_event; 1366 tp->event.trace = print_kprobe_event;
1368 call->raw_init = probe_event_raw_init; 1367 call->raw_init = probe_event_raw_init;
1369 call->define_fields = kprobe_event_define_fields; 1368 INIT_LIST_HEAD(&call->class->fields);
1369 call->class->define_fields = kprobe_event_define_fields;
1370 } 1370 }
1371 if (set_print_fmt(tp) < 0) 1371 if (set_print_fmt(tp) < 0)
1372 return -ENOMEM; 1372 return -ENOMEM;
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index a21d366cae46..cceccf0d2e91 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -20,14 +20,37 @@ static int syscall_enter_register(struct ftrace_event_call *event,
20static int syscall_exit_register(struct ftrace_event_call *event, 20static int syscall_exit_register(struct ftrace_event_call *event,
21 enum trace_reg type); 21 enum trace_reg type);
22 22
23static int syscall_enter_define_fields(struct ftrace_event_call *call);
24static int syscall_exit_define_fields(struct ftrace_event_call *call);
25
26static struct list_head *
27syscall_get_enter_fields(struct ftrace_event_call *call)
28{
29 struct syscall_metadata *entry = call->data;
30
31 return &entry->enter_fields;
32}
33
34static struct list_head *
35syscall_get_exit_fields(struct ftrace_event_call *call)
36{
37 struct syscall_metadata *entry = call->data;
38
39 return &entry->exit_fields;
40}
41
23struct ftrace_event_class event_class_syscall_enter = { 42struct ftrace_event_class event_class_syscall_enter = {
24 .system = "syscalls", 43 .system = "syscalls",
25 .reg = syscall_enter_register 44 .reg = syscall_enter_register,
45 .define_fields = syscall_enter_define_fields,
46 .get_fields = syscall_get_enter_fields,
26}; 47};
27 48
28struct ftrace_event_class event_class_syscall_exit = { 49struct ftrace_event_class event_class_syscall_exit = {
29 .system = "syscalls", 50 .system = "syscalls",
30 .reg = syscall_exit_register 51 .reg = syscall_exit_register,
52 .define_fields = syscall_exit_define_fields,
53 .get_fields = syscall_get_exit_fields,
31}; 54};
32 55
33extern unsigned long __start_syscalls_metadata[]; 56extern unsigned long __start_syscalls_metadata[];
@@ -220,7 +243,7 @@ static void free_syscall_print_fmt(struct ftrace_event_call *call)
220 kfree(call->print_fmt); 243 kfree(call->print_fmt);
221} 244}
222 245
223int syscall_enter_define_fields(struct ftrace_event_call *call) 246static int syscall_enter_define_fields(struct ftrace_event_call *call)
224{ 247{
225 struct syscall_trace_enter trace; 248 struct syscall_trace_enter trace;
226 struct syscall_metadata *meta = call->data; 249 struct syscall_metadata *meta = call->data;
@@ -243,7 +266,7 @@ int syscall_enter_define_fields(struct ftrace_event_call *call)
243 return ret; 266 return ret;
244} 267}
245 268
246int syscall_exit_define_fields(struct ftrace_event_call *call) 269static int syscall_exit_define_fields(struct ftrace_event_call *call)
247{ 270{
248 struct syscall_trace_exit trace; 271 struct syscall_trace_exit trace;
249 int ret; 272 int ret;