Commit 8728fe50 authored by Li Zefan's avatar Li Zefan Committed by Steven Rostedt

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: default avatarLi Zefan <lizf@cn.fujitsu.com>
LKML-Reference: <4BFA3759.30105@cn.fujitsu.com>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent c9642c49
...@@ -698,6 +698,8 @@ struct filter_pred { ...@@ -698,6 +698,8 @@ struct filter_pred {
int pop_n; int pop_n;
}; };
extern struct list_head ftrace_common_fields;
extern enum regex_type extern enum regex_type
filter_parse_regex(char *buff, int len, char **search, int *not); filter_parse_regex(char *buff, int len, char **search, int *not);
extern void print_event_filter(struct ftrace_event_call *call, extern void print_event_filter(struct ftrace_event_call *call,
......
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
DEFINE_MUTEX(event_mutex); DEFINE_MUTEX(event_mutex);
LIST_HEAD(ftrace_events); LIST_HEAD(ftrace_events);
LIST_HEAD(ftrace_common_fields);
struct list_head * struct list_head *
trace_get_fields(struct ftrace_event_call *event_call) trace_get_fields(struct ftrace_event_call *event_call)
...@@ -37,15 +38,11 @@ trace_get_fields(struct ftrace_event_call *event_call) ...@@ -37,15 +38,11 @@ trace_get_fields(struct ftrace_event_call *event_call)
return event_call->class->get_fields(event_call); return event_call->class->get_fields(event_call);
} }
int trace_define_field(struct ftrace_event_call *call, const char *type, static int __trace_define_field(struct list_head *head, const char *type,
const char *name, int offset, int size, int is_signed, const char *name, int offset, int size,
int filter_type) int is_signed, int filter_type)
{ {
struct ftrace_event_field *field; struct ftrace_event_field *field;
struct list_head *head;
if (WARN_ON(!call->class))
return 0;
field = kzalloc(sizeof(*field), GFP_KERNEL); field = kzalloc(sizeof(*field), GFP_KERNEL);
if (!field) if (!field)
...@@ -68,7 +65,6 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, ...@@ -68,7 +65,6 @@ int trace_define_field(struct ftrace_event_call *call, const char *type,
field->size = size; field->size = size;
field->is_signed = is_signed; field->is_signed = is_signed;
head = trace_get_fields(call);
list_add(&field->link, head); list_add(&field->link, head);
return 0; return 0;
...@@ -80,17 +76,32 @@ int trace_define_field(struct ftrace_event_call *call, const char *type, ...@@ -80,17 +76,32 @@ int trace_define_field(struct ftrace_event_call *call, const char *type,
return -ENOMEM; return -ENOMEM;
} }
int trace_define_field(struct ftrace_event_call *call, const char *type,
const char *name, int offset, int size, int is_signed,
int filter_type)
{
struct list_head *head;
if (WARN_ON(!call->class))
return 0;
head = trace_get_fields(call);
return __trace_define_field(head, type, name, offset, size,
is_signed, filter_type);
}
EXPORT_SYMBOL_GPL(trace_define_field); EXPORT_SYMBOL_GPL(trace_define_field);
#define __common_field(type, item) \ #define __common_field(type, item) \
ret = trace_define_field(call, #type, "common_" #item, \ ret = __trace_define_field(&ftrace_common_fields, #type, \
offsetof(typeof(ent), item), \ "common_" #item, \
sizeof(ent.item), \ offsetof(typeof(ent), item), \
is_signed_type(type), FILTER_OTHER); \ sizeof(ent.item), \
is_signed_type(type), FILTER_OTHER); \
if (ret) \ if (ret) \
return ret; return ret;
static int trace_define_common_fields(struct ftrace_event_call *call) static int trace_define_common_fields(void)
{ {
int ret; int ret;
struct trace_entry ent; struct trace_entry ent;
...@@ -544,32 +555,10 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt, ...@@ -544,32 +555,10 @@ system_enable_write(struct file *filp, const char __user *ubuf, size_t cnt,
return ret; return ret;
} }
static ssize_t static void print_event_fields(struct trace_seq *s, struct list_head *head)
event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{ {
struct ftrace_event_call *call = filp->private_data;
struct ftrace_event_field *field; struct ftrace_event_field *field;
struct list_head *head;
struct trace_seq *s;
int common_field_count = 5;
char *buf;
int r = 0;
if (*ppos)
return 0;
s = kmalloc(sizeof(*s), GFP_KERNEL);
if (!s)
return -ENOMEM;
trace_seq_init(s);
trace_seq_printf(s, "name: %s\n", call->name);
trace_seq_printf(s, "ID: %d\n", call->event.type);
trace_seq_printf(s, "format:\n");
head = trace_get_fields(call);
list_for_each_entry_reverse(field, head, link) { list_for_each_entry_reverse(field, head, link) {
/* /*
* Smartly shows the array type(except dynamic array). * 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,29 +573,54 @@ event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
array_descriptor = NULL; array_descriptor = NULL;
if (!array_descriptor) { if (!array_descriptor) {
r = trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;" trace_seq_printf(s, "\tfield:%s %s;\toffset:%u;"
"\tsize:%u;\tsigned:%d;\n", "\tsize:%u;\tsigned:%d;\n",
field->type, field->name, field->offset, field->type, field->name, field->offset,
field->size, !!field->is_signed); field->size, !!field->is_signed);
} else { } else {
r = trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;" trace_seq_printf(s, "\tfield:%.*s %s%s;\toffset:%u;"
"\tsize:%u;\tsigned:%d;\n", "\tsize:%u;\tsigned:%d;\n",
(int)(array_descriptor - field->type), (int)(array_descriptor - field->type),
field->type, field->name, field->type, field->name,
array_descriptor, field->offset, array_descriptor, field->offset,
field->size, !!field->is_signed); field->size, !!field->is_signed);
} }
}
}
if (--common_field_count == 0) static ssize_t
r = trace_seq_printf(s, "\n"); event_format_read(struct file *filp, char __user *ubuf, size_t cnt,
loff_t *ppos)
{
struct ftrace_event_call *call = filp->private_data;
struct list_head *head;
struct trace_seq *s;
char *buf;
int r;
if (!r) if (*ppos)
break; return 0;
}
if (r) s = kmalloc(sizeof(*s), GFP_KERNEL);
r = trace_seq_printf(s, "\nprint fmt: %s\n", if (!s)
call->print_fmt); return -ENOMEM;
trace_seq_init(s);
trace_seq_printf(s, "name: %s\n", call->name);
trace_seq_printf(s, "ID: %d\n", call->event.type);
trace_seq_printf(s, "format:\n");
/* print common fields */
print_event_fields(s, &ftrace_common_fields);
trace_seq_putc(s, '\n');
/* print event specific fields */
head = trace_get_fields(call);
print_event_fields(s, head);
r = trace_seq_printf(s, "\nprint fmt: %s\n", call->print_fmt);
if (!r) { if (!r) {
/* /*
...@@ -980,9 +994,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events, ...@@ -980,9 +994,7 @@ event_create_dir(struct ftrace_event_call *call, struct dentry *d_events,
*/ */
head = trace_get_fields(call); head = trace_get_fields(call);
if (list_empty(head)) { if (list_empty(head)) {
ret = trace_define_common_fields(call); ret = call->class->define_fields(call);
if (!ret)
ret = call->class->define_fields(call);
if (ret < 0) { if (ret < 0) {
pr_warning("Could not initialize trace point" pr_warning("Could not initialize trace point"
" events/%s\n", call->name); " events/%s\n", call->name);
...@@ -1319,6 +1331,9 @@ static __init int event_trace_init(void) ...@@ -1319,6 +1331,9 @@ static __init int event_trace_init(void)
trace_create_file("enable", 0644, d_events, trace_create_file("enable", 0644, d_events,
NULL, &ftrace_system_enable_fops); NULL, &ftrace_system_enable_fops);
if (trace_define_common_fields())
pr_warning("tracing: Failed to allocate common fields");
for_each_event(call, __start_ftrace_events, __stop_ftrace_events) { for_each_event(call, __start_ftrace_events, __stop_ftrace_events) {
/* The linker may leave blanks */ /* The linker may leave blanks */
if (!call->name) if (!call->name)
......
...@@ -497,12 +497,10 @@ void print_subsystem_event_filter(struct event_subsystem *system, ...@@ -497,12 +497,10 @@ void print_subsystem_event_filter(struct event_subsystem *system,
} }
static struct ftrace_event_field * static struct ftrace_event_field *
find_event_field(struct ftrace_event_call *call, char *name) __find_event_field(struct list_head *head, char *name)
{ {
struct ftrace_event_field *field; struct ftrace_event_field *field;
struct list_head *head;
head = trace_get_fields(call);
list_for_each_entry(field, head, link) { list_for_each_entry(field, head, link) {
if (!strcmp(field->name, name)) if (!strcmp(field->name, name))
return field; return field;
...@@ -511,6 +509,20 @@ find_event_field(struct ftrace_event_call *call, char *name) ...@@ -511,6 +509,20 @@ find_event_field(struct ftrace_event_call *call, char *name)
return NULL; return NULL;
} }
static struct ftrace_event_field *
find_event_field(struct ftrace_event_call *call, char *name)
{
struct ftrace_event_field *field;
struct list_head *head;
field = __find_event_field(&ftrace_common_fields, name);
if (field)
return field;
head = trace_get_fields(call);
return __find_event_field(head, name);
}
static void filter_free_pred(struct filter_pred *pred) static void filter_free_pred(struct filter_pred *pred)
{ {
if (!pred) if (!pred)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment