diff options
author | Li Zefan <lizf@cn.fujitsu.com> | 2010-05-24 04:22:49 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2010-06-28 17:12:46 -0400 |
commit | 8728fe501ed562c1b46dde3c195eadec77bca033 (patch) | |
tree | c911b4a6af85817ba6bdf3342cbae4838c14b1bb /kernel | |
parent | c9642c49aae1272d7c24008a40ae614470b957a6 (diff) |
tracing: Don't allocate common fields for every trace events
Every event has the same common fields, so it's a big waste of
memory to have a copy of those fields for every event.
Signed-off-by: Li Zefan <lizf@cn.fujitsu.com>
LKML-Reference: <4BFA3759.30105@cn.fujitsu.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/trace/trace.h | 2 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 113 | ||||
-rw-r--r-- | kernel/trace/trace_events_filter.c | 18 |
3 files changed, 81 insertions, 52 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 01ce088c1cdf..cc90ccdad469 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -698,6 +698,8 @@ struct filter_pred { | |||
698 | int pop_n; | 698 | int pop_n; |
699 | }; | 699 | }; |
700 | 700 | ||
701 | extern struct list_head ftrace_common_fields; | ||
702 | |||
701 | extern enum regex_type | 703 | extern enum regex_type |
702 | filter_parse_regex(char *buff, int len, char **search, int *not); | 704 | filter_parse_regex(char *buff, int len, char **search, int *not); |
703 | extern void print_event_filter(struct ftrace_event_call *call, | 705 | extern void print_event_filter(struct ftrace_event_call *call, |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index a594f9a7ee3d..d3b4bdf00b39 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -28,6 +28,7 @@ | |||
28 | DEFINE_MUTEX(event_mutex); | 28 | DEFINE_MUTEX(event_mutex); |
29 | 29 | ||
30 | LIST_HEAD(ftrace_events); | 30 | LIST_HEAD(ftrace_events); |
31 | LIST_HEAD(ftrace_common_fields); | ||
31 | 32 | ||
32 | struct list_head * | 33 | struct list_head * |
33 | trace_get_fields(struct ftrace_event_call *event_call) | 34 | trace_get_fields(struct ftrace_event_call *event_call) |
@@ -37,15 +38,11 @@ trace_get_fields(struct ftrace_event_call *event_call) | |||
37 | return event_call->class->get_fields(event_call); | 38 | return event_call->class->get_fields(event_call); |
38 | } | 39 | } |
39 | 40 | ||
40 | int trace_define_field(struct ftrace_event_call *call, const char *type, | 41 | static int __trace_define_field(struct list_head *head, const char *type, |
41 | const char *name, int offset, int size, int is_signed, | 42 | const char *name, int offset, int size, |
42 | int filter_type) | 43 | int is_signed, int filter_type) |
43 | { | 44 | { |
44 | struct ftrace_event_field *field; | 45 | struct ftrace_event_field *field; |
45 | struct list_head *head; | ||
46 | |||
47 | if (WARN_ON(!call->class)) | ||
48 | return 0; | ||
49 | 46 | ||
50 | field = kzalloc(sizeof(*field), GFP_KERNEL); | 47 | field = kzalloc(sizeof(*field), GFP_KERNEL); |
51 | if (!field) | 48 | if (!field) |
@@ -68,7 +65,6 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, | |||
68 | field->size = size; | 65 | field->size = size; |
69 | field->is_signed = is_signed; | 66 | field->is_signed = is_signed; |
70 | 67 | ||
71 | head = trace_get_fields(call); | ||
72 | list_add(&field->link, head); | 68 | list_add(&field->link, head); |
73 | 69 | ||
74 | return 0; | 70 | return 0; |
@@ -80,17 +76,32 @@ err: | |||
80 | 76 | ||
81 | return -ENOMEM; | 77 | return -ENOMEM; |
82 | } | 78 | } |
79 | |||
80 | int trace_define_field(struct ftrace_event_call *call, const char *type, | ||
81 | const char *name, int offset, int size, int is_signed, | ||
82 | int filter_type) | ||
83 | { | ||
84 | struct list_head *head; | ||
85 | |||
86 | if (WARN_ON(!call->class)) | ||
87 | return 0; | ||
88 | |||
89 | head = trace_get_fields(call); | ||
90 | return __trace_define_field(head, type, name, offset, size, | ||
91 | is_signed, filter_type); | ||
92 | } | ||
83 | EXPORT_SYMBOL_GPL(trace_define_field); | 93 | EXPORT_SYMBOL_GPL(trace_define_field); |
84 | 94 | ||
85 | #define __common_field(type, item) \ | 95 | #define __common_field(type, item) \ |
86 | ret = trace_define_field(call, #type, "common_" #item, \ | 96 | ret = __trace_define_field(&ftrace_common_fields, #type, \ |
87 | offsetof(typeof(ent), item), \ | 97 | "common_" #item, \ |
88 | sizeof(ent.item), \ | 98 | offsetof(typeof(ent), item), \ |
89 | is_signed_type(type), FILTER_OTHER); \ | 99 | sizeof(ent.item), \ |
100 | is_signed_type(type), FILTER_OTHER); \ | ||
90 | if (ret) \ | 101 | if (ret) \ |
91 | return ret; | 102 | return ret; |
92 | 103 | ||
93 | static int trace_define_common_fields(struct ftrace_event_call *call) | 104 | static int trace_define_common_fields(void) |
94 | { | 105 | { |
95 | int ret; | 106 | int ret; |
96 | struct trace_entry ent; | 107 | struct trace_entry ent; |
@@ -544,32 +555,10 @@ out: | |||
544 | return ret; | 555 | return ret; |
545 | } | 556 | } |
546 | 557 | ||
547 | static ssize_t | 558 | static void print_event_fields(struct trace_seq *s, struct list_head *head) |
548 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | ||
549 | loff_t *ppos) | ||
550 | { | 559 | { |
551 | struct ftrace_event_call *call = filp->private_data; | ||
552 | struct ftrace_event_field *field; | 560 | struct ftrace_event_field *field; |
553 | struct list_head *head; | ||
554 | struct trace_seq *s; | ||
555 | int common_field_count = 5; | ||
556 | char *buf; | ||
557 | int r = 0; | ||
558 | |||
559 | if (*ppos) | ||
560 | return 0; | ||
561 | |||
562 | s = kmalloc(sizeof(*s), GFP_KERNEL); | ||
563 | if (!s) | ||
564 | return -ENOMEM; | ||
565 | |||
566 | trace_seq_init(s); | ||
567 | 561 | ||
568 | trace_seq_printf(s, "name: %s\n", call->name); | ||
569 | trace_seq_printf(s, "ID: %d\n", call->event.type); | ||
570 | trace_seq_printf(s, "format:\n"); | ||
571 | |||
572 | head = trace_get_fields(call); | ||
573 | list_for_each_entry_reverse(field, head, link) { | 562 | list_for_each_entry_reverse(field, head, link) { |
574 | /* | 563 | /* |
575 | * Smartly shows the array type(except dynamic array). | 564 | * Smartly shows the array type(except dynamic array). |
@@ -584,29 +573,54 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt, | |||
584 | array_descriptor = NULL; | 573 | array_descriptor = NULL; |
585 | 574 | ||
586 | if (!array_descriptor) { | 575 | if (!array_descriptor) { |
587 | r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" | 576 | trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" |
588 | "\tsize:%u;\tsigned:%d;\n", | 577 | "\tsize:%u;\tsigned:%d;\n", |
589 | field->type, field->name, field->offset, | 578 | field->type, field->name, field->offset, |
590 | field->size, !!field->is_signed); | 579 | field->size, !!field->is_signed); |
591 | } else { | 580 | } else { |
592 | r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" | 581 | trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" |
593 | "\tsize:%u;\tsigned:%d;\n", | 582 | "\tsize:%u;\tsigned:%d;\n", |
594 | (int)(array_descriptor - field->type), | 583 | (int)(array_descriptor - field->type), |
595 | field->type, field->name, | 584 | field->type, field->name, |
596 | array_descriptor, field->offset, | 585 | array_descriptor, field->offset, |
597 | field->size, !!field->is_signed); | 586 | field->size, !!field->is_signed); |
598 | } | 587 | } |
588 | } | ||
589 | } | ||
599 | 590 | ||
600 | if (--common_field_count == 0) | 591 | static ssize_t |
601 | r = trace_seq_printf(s, "\n"); | 592 | event_format_read(struct file *filp, char __user *ubuf, size_t cnt, |
593 | loff_t *ppos) | ||
594 | { | ||
595 | struct ftrace_event_call *call = filp->private_data; | ||
596 | struct list_head *head; | ||
597 | struct trace_seq *s; | ||
598 | char *buf; | ||
599 | int r; | ||
602 | 600 | ||
603 | if (!r) | 601 | if (*ppos) |
604 | break; | 602 | return 0; |
605 | } | ||
606 | 603 | ||
607 | if (r) | 604 | s = kmalloc(sizeof(*s), GFP_KERNEL); |
608 | r = trace_seq_printf(s, "\nprint fmt: %s\n", | 605 | if (!s) |
609 | call->print_fmt); | 606 | return -ENOMEM; |
607 | |||
608 | trace_seq_init(s); | ||
609 | |||
610 | trace_seq_printf(s, "name: %s\n", call->name); | ||
611 | trace_seq_printf(s, "ID: %d\n", call->event.type); | ||
612 | trace_seq_printf(s, "format:\n"); | ||
613 | |||
614 | /* print common fields */ | ||
615 | print_event_fields(s, &ftrace_common_fields); | ||
616 | |||
617 | trace_seq_putc(s, '\n'); | ||
618 | |||
619 | /* print event specific fields */ | ||
620 | head = trace_get_fields(call); | ||
621 | print_event_fields(s, head); | ||
622 | |||
623 | r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt); | ||
610 | 624 | ||
611 | if (!r) { | 625 | if (!r) { |
612 | /* | 626 | /* |
@@ -980,9 +994,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, | |||
980 | */ | 994 | */ |
981 | head = trace_get_fields(call); | 995 | head = trace_get_fields(call); |
982 | if (list_empty(head)) { | 996 | if (list_empty(head)) { |
983 | ret = trace_define_common_fields(call); | 997 | ret = call->class->define_fields(call); |
984 | if (!ret) | ||
985 | ret = call->class->define_fields(call); | ||
986 | if (ret < 0) { | 998 | if (ret < 0) { |
987 | pr_warning("Could not initialize trace point" | 999 | pr_warning("Could not initialize trace point" |
988 | " events/%s\n", call->name); | 1000 | " events/%s\n", call->name); |
@@ -1319,6 +1331,9 @@ static __init int event_trace_init(void) | |||
1319 | trace_create_file("enable", 0644, d_events, | 1331 | trace_create_file("enable", 0644, d_events, |
1320 | NULL, &ftrace_system_enable_fops); | 1332 | NULL, &ftrace_system_enable_fops); |
1321 | 1333 | ||
1334 | if (trace_define_common_fields()) | ||
1335 | pr_warning("tracing: Failed to allocate common fields"); | ||
1336 | |||
1322 | for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { | 1337 | for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { |
1323 | /* The linker may leave blanks */ | 1338 | /* The linker may leave blanks */ |
1324 | if (!call->name) | 1339 | if (!call->name) |
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c index 57bb1bb32999..330fefd1de1c 100644 --- a/kernel/trace/trace_events_filter.c +++ b/kernel/trace/trace_events_filter.c | |||
@@ -497,12 +497,10 @@ void print_subsystem_event_filter(struct event_subsystem *system, | |||
497 | } | 497 | } |
498 | 498 | ||
499 | static struct ftrace_event_field * | 499 | static struct ftrace_event_field * |
500 | find_event_field(struct ftrace_event_call *call, char *name) | 500 | __find_event_field(struct list_head *head, char *name) |
501 | { | 501 | { |
502 | struct ftrace_event_field *field; | 502 | struct ftrace_event_field *field; |
503 | struct list_head *head; | ||
504 | 503 | ||
505 | head = trace_get_fields(call); | ||
506 | list_for_each_entry(field, head, link) { | 504 | list_for_each_entry(field, head, link) { |
507 | if (!strcmp(field->name, name)) | 505 | if (!strcmp(field->name, name)) |
508 | return field; | 506 | return field; |
@@ -511,6 +509,20 @@ find_event_field(struct ftrace_event_call *call, char *name) | |||
511 | return NULL; | 509 | return NULL; |
512 | } | 510 | } |
513 | 511 | ||
512 | static struct ftrace_event_field * | ||
513 | find_event_field(struct ftrace_event_call *call, char *name) | ||
514 | { | ||
515 | struct ftrace_event_field *field; | ||
516 | struct list_head *head; | ||
517 | |||
518 | field = __find_event_field(&ftrace_common_fields, name); | ||
519 | if (field) | ||
520 | return field; | ||
521 | |||
522 | head = trace_get_fields(call); | ||
523 | return __find_event_field(head, name); | ||
524 | } | ||
525 | |||
514 | static void filter_free_pred(struct filter_pred *pred) | 526 | static void filter_free_pred(struct filter_pred *pred) |
515 | { | 527 | { |
516 | if (!pred) | 528 | if (!pred) |