Tracing/ftrace: Adds a marker to allow user comments
Subsystems (6)
PATCH 1/1 Tracing/ftrace: Adds a marker to allow user comments
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
It applies on last version of tip tree.
--- kernel/trace/trace.c | 264 ++++++++++++++++++++++++++++++++++++-------------- kernel/trace/trace.h | 5 + 2 files changed, 198 insertions(+), 71 deletions(-)
kernel/trace/trace.c +193 -71
@@ -955,6 +955,121 @@ __trace_special(void *__tr, void *__data,trace_wake_up (); } +/* Add a message provided by the user (TRACE_MARK) or by __ftrace_printk */ + +void trace_print (char *buf,int len,struct trace_entry *tmp_ent, +struct trace_array *tr,struct trace_array_cpu *data, +unsigned long flags) +{ +struct trace_entry *entry; +int write, written =0 ; + +__raw_spin_lock (&data->lock); + entry =tracing_get_trace_entry (tr, data); +tracing_generic_entry_update (entry, flags); + entry->type = tmp_ent->type; + +if (entry->type ==TRACE_PRINT ) + entry->field.print.ip = tmp_ent->field.print.ip; + + write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); +memcpy (&entry->field.print.buf, buf, write); + entry->field.print.buf[write] =0 ; + + written = write; + +if (written != len) + entry->field.flags |=TRACE_FLAG_CONT ; + +while (written != len) { + entry =tracing_get_trace_entry (tr, data); + + entry->type =TRACE_CONT ; + write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); +memcpy (&entry->cont.buf, buf+written, write); + entry->cont.buf[write] =0 ; + written += write; + } +__raw_spin_unlock (&data->lock); +} + +/* Add a message provided by the user towards the tracing_mark file */ +int tracing_mark (char *buf,int size) +{ +struct trace_array *tr = &global_trace; +struct trace_array_cpu *data; +struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +int cpu; + +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 )) + goto out; + + size =min (size,TRACE_BUF_SIZE -1 ); + tmp_ent.type =TRACE_MARK ; + buf[size -1 ] =0 ; + +trace_print (buf, size, &tmp_ent, tr, data, flags); + +out: +atomic_dec (&data->disabled); +local_irq_restore (flags); +return size; +} + + +int __ftrace_printk (unsigned long ip,const char *fmt, ...) +{ +struct trace_array *tr = &global_trace; +static DEFINE_SPINLOCK (trace_buf_lock); +static char trace_buf[TRACE_BUF_SIZE ]; +struct trace_array_cpu *data; +struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +va_list ap; +int cpu, len =0 ; + +if (likely (!ftrace_function_enabled)) +return 0 ; + +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 || !ftrace_function_enabled)) + goto out; + + tmp_ent.type =TRACE_PRINT ; + tmp_ent.field.print.ip = ip; + +spin_lock (&trace_buf_lock); +va_start (ap, fmt); + len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); +va_end (ap); + + len =min (len,TRACE_BUF_SIZE -1 ); + trace_buf[len] =0 ; + +trace_print (trace_buf, len, &tmp_ent, tr, data, flags); + +spin_unlock (&trace_buf_lock); + + out: +atomic_dec (&data->disabled); +local_irq_restore (flags); + +return len; +} +EXPORT_SYMBOL_GPL (__ftrace_printk); + void tracing_sched_switch_trace(struct trace_array *tr, struct trace_array_cpu *data,
@@ -1943,6 +2058,26 @@ static int print_bin_fmt(struct trace_iterator *iter)return 1 ; } +/* Add the user message on the pipe */ +static int print_mark (struct trace_iterator *iter) +{ +struct trace_seq *s = &iter->seq; +struct trace_entry *entry = iter->ent; +struct trace_field *field = &entry->field; + +int ret; + + ret =trace_seq_printf (s, field->print.buf); +if (field->flags &&TRACE_FLAG_CONT ) +trace_seq_print_cont (s, iter); +trace_seq_printf (s,"\n" ); + +if (ret) +return 1 ; +return 0 ; +} + +static int trace_empty (struct trace_iterator *iter) {struct trace_array_cpu *data;
@@ -1961,6 +2096,9 @@ static int trace_empty(struct trace_iterator *iter)static int print_trace_line (struct trace_iterator *iter) { +if (iter->ent->type ==TRACE_MARK ) +return print_mark (iter); +if (iter->trace && iter->trace->print_line)return iter->trace->print_line (iter);
@@ -2918,6 +3056,49 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,return cnt; } +static int tracing_open_mark (struct inode *inode,struct file *filp) +{ +int ret; + + ret =tracing_open_generic (inode, filp); +if (ret) +return ret; + +if (current_trace == &no_tracer) +return -ENODEV ; + +return 0 ; +} + + +static ssize_t +tracing_mark_write (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *fpos) +{ +char *buf; + +if (cnt >TRACE_BUF_SIZE ) + cnt =TRACE_BUF_SIZE ; + + buf =kmalloc (cnt,GFP_KERNEL ); + +if (buf ==NULL ) +return -ENOMEM ; + +if (copy_from_user (buf, ubuf, cnt)) { +kfree (buf); +return -EFAULT ; + } + + cnt =tracing_mark (buf, cnt); +kfree (buf); + *fpos += cnt; + +return cnt; +} + + +static struct file_operations tracing_max_lat_fops = { .open = tracing_open_generic, .read = tracing_max_lat_read,
@@ -2949,6 +3130,11 @@ static struct file_operations tracing_entries_fops = { .write = tracing_entries_write, }; +static struct file_operations tracing_mark_fops = { + .open = tracing_open_mark, + .write = tracing_mark_write, +}; +#ifdef CONFIG_DYNAMIC_FTRACE static ssize_t
@@ -3066,6 +3252,13 @@ static __init void tracer_init_debugfs(void)pr_warning ("Could not create debugfs " "'trace_entries' entry\n" ); + entry =debugfs_create_file ("trace_marker" ,0220 , d_tracer, +NULL , &tracing_mark_fops); + +if (!entry) +pr_warning ("Could not create debugfs " +"'trace_marker' entry\n" ); +#ifdef CONFIG_DYNAMIC_FTRACE entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer, &ftrace_update_tot_cnt,
@@ -3079,77 +3272,6 @@ static __init void tracer_init_debugfs(void)#endif } -#define TRACE_BUF_SIZE 1024 -#define TRACE_PRINT_BUF_SIZE \ - (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) -#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field) - -int __ftrace_printk (unsigned long ip,const char *fmt, ...) -{ -struct trace_array *tr = &global_trace; -static DEFINE_SPINLOCK (trace_buf_lock); -static char trace_buf[TRACE_BUF_SIZE ]; -struct trace_array_cpu *data; -struct trace_entry *entry; -unsigned long flags; -long disabled; -va_list ap; -int cpu, len =0 , write, written =0 ; - -if (likely (!ftrace_function_enabled)) -return 0 ; - -local_irq_save (flags); - cpu =raw_smp_processor_id (); - data = tr->data[cpu]; - disabled =atomic_inc_return (&data->disabled); - -if (unlikely (disabled !=1 || !ftrace_function_enabled)) - goto out; - -spin_lock (&trace_buf_lock); -va_start (ap, fmt); - len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); -va_end (ap); - - len =min (len,TRACE_BUF_SIZE -1 ); - trace_buf[len] =0 ; - -__raw_spin_lock (&data->lock); - entry =tracing_get_trace_entry (tr, data); -tracing_generic_entry_update (entry, flags); - entry->type =TRACE_PRINT ; - entry->field.print.ip = ip; - - write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); - -memcpy (&entry->field.print.buf, trace_buf, write); - entry->field.print.buf[write] =0 ; - written = write; - -if (written != len) - entry->field.flags |=TRACE_FLAG_CONT ; - -while (written != len) { - entry =tracing_get_trace_entry (tr, data); - - entry->type =TRACE_CONT ; - write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); -memcpy (&entry->cont.buf, trace_buf+written, write); - entry->cont.buf[write] =0 ; - written += write; - } -__raw_spin_unlock (&data->lock); - -spin_unlock (&trace_buf_lock); - - out: -atomic_dec (&data->disabled); -local_irq_restore (flags); - -return len; -} -EXPORT_SYMBOL_GPL (__ftrace_printk);static int trace_panic_handler (struct notifier_block *this,unsigned long event,void *unused)
kernel/trace/trace.h +5 -0
@@ -14,6 +14,7 @@ enum trace_type {TRACE_CTX ,TRACE_WAKE ,TRACE_CONT , +TRACE_MARK ,TRACE_STACK ,TRACE_PRINT , TRACE_SPECIAL,
@@ -106,6 +107,10 @@ struct trace_entry { };#define TRACE_ENTRY_SIZE sizeof(struct trace_entry) +#define TRACE_BUF_SIZE 1024 +#define TRACE_PRINT_BUF_SIZE \ + (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) +#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field)/* * The CPU trace array - it consists of thousands of trace entries
Quoted 5 lines · Frédéric Weisbecker
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
It applies on last version of tip tree.
hmm ... have you looked at the (recently implemented) ftrace_printk() facility?
Ingo
2008/8/25 Ingo Molnar <[email protected]>:
Quoted 7 lines · Frédéric Weisbecker
Quoted 5 lines
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
Quoted 7 lines
Quoted 1 line
It applies on last version of tip tree.
hmm ... have you looked at the (recently implemented)
ftrace_printk()facility?Ingo
Yes but I didn't want to use ftrace_printk() because it needs the "ip" parameter. User messages doesn't need this. But I reuse a part of the code of ftrace_printk and I splitted ftrace_printk() in two parts for this purpose: __ftrace_printk() and trace_print().
I also reused the print_entry but with a new TRACE_MARK type to make the difference when it is time to send the entry to the pipe because user messages don't use ip.
Steven Rostedt
maintainerQuoted 16 lines · Fr?d?ric Weisbecker
2008/8/25 Ingo Molnar <[email protected]>:
Quoted 7 lines · Fr?d?ric Weisbecker
Quoted 5 lines
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
Quoted 7 lines
Quoted 1 line
It applies on last version of tip tree.
hmm ... have you looked at the (recently implemented)
ftrace_printk()facility?Ingo
Quoted 7 lines
Yes but I didn't want to use
ftrace_printk()because it needs the "ip" parameter. User messages doesn't need this. But I reuse a part of the code offtrace_printkand I splittedftrace_printk()in two parts for this purpose:__ftrace_printk()andtrace_print().
I also reused theprint_entrybut with a newTRACE_MARKtype to make the difference when it is time to send the entry to the pipe because user messages don't use ip.
Feel free to make TRACE_CONT work for you. I coupled it a little more than I wanted to with the ftrace print. If you can find a nice way to make TRACE_CONT a bit more generic, then feel free.
-- Steve
2008/8/25 Steven Rostedt <[email protected]>:
Quoted 8 lines
Feel free to make
TRACE_CONTwork for you. I coupled it a little more than I wanted to with the ftrace print. If you can find a nice way to makeTRACE_CONTa bit more generic, then feel free.-- Steve
Thanks.
But TRACE_CONT is not a problem. It is generic enough to contain parts of a TRACE_MARK message and that's why I use it in my patch.
2008/8/24 Frédéric Weisbecker <[email protected]>:
Quoted 343 lines
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
It applies on last version of tip tree.
Signed-off-by Frederic Weisbecker <[email protected]>--- kernel/trace/trace.c | 264 ++++++++++++++++++++++++++++++++++++-------------- kernel/trace/trace.h | 5 + 2 files changed, 198 insertions(+), 71 deletions(-)kernel/trace/trace.c +193
-71@@ -955,6 +955,121 @@ __trace_special(void *__tr, void *__data,trace_wake_up (); } +/* Add a message provided by the user (TRACE_MARK) or by __ftrace_printk */ + +void trace_print (char *buf,int len,struct trace_entry *tmp_ent, +struct trace_array *tr,struct trace_array_cpu *data, +unsigned long flags) +{ +struct trace_entry *entry; +int write, written =0 ; + +__raw_spin_lock (&data->lock); + entry =tracing_get_trace_entry (tr, data); +tracing_generic_entry_update (entry, flags); + entry->type = tmp_ent->type; + +if (entry->type ==TRACE_PRINT ) + entry->field.print.ip = tmp_ent->field.print.ip; + + write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); +memcpy (&entry->field.print.buf, buf, write); + entry->field.print.buf[write] =0 ; + + written = write; + +if (written != len) + entry->field.flags |=TRACE_FLAG_CONT ; + +while (written != len) { + entry =tracing_get_trace_entry (tr, data); + + entry->type =TRACE_CONT ; + write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); +memcpy (&entry->cont.buf, buf+written, write); + entry->cont.buf[write] =0 ; + written += write; + } +__raw_spin_unlock (&data->lock); +} + +/* Add a message provided by the user towards the tracing_mark file */ +int tracing_mark (char *buf,int size) +{ +struct trace_array *tr = &global_trace; +struct trace_array_cpu *data; +struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +int cpu; + +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 )) + goto out; + + size =min (size,TRACE_BUF_SIZE -1 ); + tmp_ent.type =TRACE_MARK ; + buf[size -1 ] =0 ; + +trace_print (buf, size, &tmp_ent, tr, data, flags); + +out: +atomic_dec (&data->disabled); +local_irq_restore (flags); +return size; +} + + +int __ftrace_printk (unsigned long ip,const char *fmt, ...) +{ +struct trace_array *tr = &global_trace; +static DEFINE_SPINLOCK (trace_buf_lock); +static char trace_buf[TRACE_BUF_SIZE ]; +struct trace_array_cpu *data; +struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +va_list ap; +int cpu, len =0 ; + +if (likely (!ftrace_function_enabled)) +return 0 ; + +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 || !ftrace_function_enabled)) + goto out; + + tmp_ent.type =TRACE_PRINT ; + tmp_ent.field.print.ip = ip; + +spin_lock (&trace_buf_lock); +va_start (ap, fmt); + len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); +va_end (ap); + + len =min (len,TRACE_BUF_SIZE -1 ); + trace_buf[len] =0 ; + +trace_print (trace_buf, len, &tmp_ent, tr, data, flags); + +spin_unlock (&trace_buf_lock); + + out: +atomic_dec (&data->disabled); +local_irq_restore (flags); + +return len; +} +EXPORT_SYMBOL_GPL (__ftrace_printk); + void tracing_sched_switch_trace(struct trace_array *tr, struct trace_array_cpu *data,@@ -1943,6 +2058,26 @@ static int print_bin_fmt(struct trace_iterator *iter)return 1 ; } +/* Add the user message on the pipe */ +static int print_mark (struct trace_iterator *iter) +{ +struct trace_seq *s = &iter->seq; +struct trace_entry *entry = iter->ent; +struct trace_field *field = &entry->field; + +int ret; + + ret =trace_seq_printf (s, field->print.buf); +if (field->flags &&TRACE_FLAG_CONT ) +trace_seq_print_cont (s, iter); +trace_seq_printf (s,"\n" ); + +if (ret) +return 1 ; +return 0 ; +} + +static int trace_empty (struct trace_iterator *iter) {struct trace_array_cpu *data;@@ -1961,6 +2096,9 @@ static int trace_empty(struct trace_iterator *iter)static int print_trace_line (struct trace_iterator *iter) { +if (iter->ent->type ==TRACE_MARK ) +return print_mark (iter); +if (iter->trace && iter->trace->print_line)return iter->trace->print_line (iter);@@ -2918,6 +3056,49 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,return cnt; } +static int tracing_open_mark (struct inode *inode,struct file *filp) +{ +int ret; + + ret =tracing_open_generic (inode, filp); +if (ret) +return ret; + +if (current_trace == &no_tracer) +return -ENODEV ; + +return 0 ; +} + + +static ssize_t +tracing_mark_write (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *fpos) +{ +char *buf; + +if (cnt >TRACE_BUF_SIZE ) + cnt =TRACE_BUF_SIZE ; + + buf =kmalloc (cnt,GFP_KERNEL ); + +if (buf ==NULL ) +return -ENOMEM ; + +if (copy_from_user (buf, ubuf, cnt)) { +kfree (buf); +return -EFAULT ; + } + + cnt =tracing_mark (buf, cnt); +kfree (buf); + *fpos += cnt; + +return cnt; +} + + +static struct file_operations tracing_max_lat_fops = { .open = tracing_open_generic, .read = tracing_max_lat_read,@@ -2949,6 +3130,11 @@ static struct file_operations tracing_entries_fops = { .write = tracing_entries_write, }; +static struct file_operations tracing_mark_fops = { + .open = tracing_open_mark, + .write = tracing_mark_write, +}; +#ifdef CONFIG_DYNAMIC_FTRACE static ssize_t@@ -3066,6 +3252,13 @@ static __init void tracer_init_debugfs(void)pr_warning ("Could not create debugfs " "'trace_entries' entry\n" ); + entry =debugfs_create_file ("trace_marker" ,0220 , d_tracer, +NULL , &tracing_mark_fops); + +if (!entry) +pr_warning ("Could not create debugfs " +"'trace_marker' entry\n" ); +#ifdef CONFIG_DYNAMIC_FTRACE entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer, &ftrace_update_tot_cnt,@@ -3079,77 +3272,6 @@ static __init void tracer_init_debugfs(void)#endif } -#define TRACE_BUF_SIZE 1024 -#define TRACE_PRINT_BUF_SIZE \ - (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) -#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field) - -int __ftrace_printk (unsigned long ip,const char *fmt, ...) -{ -struct trace_array *tr = &global_trace; -static DEFINE_SPINLOCK (trace_buf_lock); -static char trace_buf[TRACE_BUF_SIZE ]; -struct trace_array_cpu *data; -struct trace_entry *entry; -unsigned long flags; -long disabled; -va_list ap; -int cpu, len =0 , write, written =0 ; - -if (likely (!ftrace_function_enabled)) -return 0 ; - -local_irq_save (flags); - cpu =raw_smp_processor_id (); - data = tr->data[cpu]; - disabled =atomic_inc_return (&data->disabled); - -if (unlikely (disabled !=1 || !ftrace_function_enabled)) - goto out; - -spin_lock (&trace_buf_lock); -va_start (ap, fmt); - len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); -va_end (ap); - - len =min (len,TRACE_BUF_SIZE -1 ); - trace_buf[len] =0 ; - -__raw_spin_lock (&data->lock); - entry =tracing_get_trace_entry (tr, data); -tracing_generic_entry_update (entry, flags); - entry->type =TRACE_PRINT ; - entry->field.print.ip = ip; - - write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); - -memcpy (&entry->field.print.buf, trace_buf, write); - entry->field.print.buf[write] =0 ; - written = write; - -if (written != len) - entry->field.flags |=TRACE_FLAG_CONT ; - -while (written != len) { - entry =tracing_get_trace_entry (tr, data); - - entry->type =TRACE_CONT ; - write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); -memcpy (&entry->cont.buf, trace_buf+written, write); - entry->cont.buf[write] =0 ; - written += write; - } -__raw_spin_unlock (&data->lock); - -spin_unlock (&trace_buf_lock); - - out: -atomic_dec (&data->disabled); -local_irq_restore (flags); - -return len; -} -EXPORT_SYMBOL_GPL (__ftrace_printk);static int trace_panic_handler (struct notifier_block *this,unsigned long event,void *unused)kernel/trace/trace.h +1
-0@@ -14,6 +14,7 @@ enum trace_type {TRACE_CTX ,TRACE_WAKE ,TRACE_CONT , +TRACE_MARK ,TRACE_STACK ,TRACE_PRINT , TRACE_SPECIAL,
kernel/trace/trace.h struct trace_entry { · line 116
Quoted 10 lines
kernel/trace/trace.h +4
-0@@ -106,6 +107,10 @@ struct trace_entry { };#define TRACE_ENTRY_SIZE sizeof(struct trace_entry) +#define TRACE_BUF_SIZE 1024 +#define TRACE_PRINT_BUF_SIZE \ + (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) +#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field)/* * The CPU trace array - it consists of thousands of trace entries
Do you think I should modify something or use a way to make it better? (Added Pekka Paalanen in Cc since it concerns an idea from his mmiotrace's documentation)...
Nice to hear from you, Frédéric!
I have some comments in the following.
Quoted 80 lines · On Wed, 27 Aug 2008 10:59:33 +0100 "Frédéric Weisbecker" <[email protected]>…
2008/8/24 Frédéric Weisbecker <[email protected]>:
Quoted 79 lines
The documentation of mmiotrace describes an unimplemented feature which allows the user to write any comments on his trace by writing on a tracing/marker file. Here is an implementation of this idea.
It applies on last version of tip tree.
Signed-off-by Frederic Weisbecker <[email protected]>--- kernel/trace/trace.c | 264 ++++++++++++++++++++++++++++++++++++-------------- kernel/trace/trace.h | 5 + 2 files changed, 198 insertions(+), 71 deletions(-)kernel/trace/trace.c +59
-0@@ -955,6 +955,121 @@ __trace_special(void *__tr, void *__data,trace_wake_up (); } +/* Add a message provided by the user (TRACE_MARK) or by __ftrace_printk */ + +void trace_print (char *buf,int len,struct trace_entry *tmp_ent, +struct trace_array *tr,struct trace_array_cpu *data, +unsigned long flags) +{ +struct trace_entry *entry; +int write, written =0 ; + +__raw_spin_lock (&data->lock); + entry =tracing_get_trace_entry (tr, data); +tracing_generic_entry_update (entry, flags); + entry->type = tmp_ent->type; + +if (entry->type ==TRACE_PRINT ) + entry->field.print.ip = tmp_ent->field.print.ip; + + write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); +memcpy (&entry->field.print.buf, buf, write); + entry->field.print.buf[write] =0 ; + + written = write; + +if (written != len) + entry->field.flags |=TRACE_FLAG_CONT ; + +while (written != len) { + entry =tracing_get_trace_entry (tr, data); + + entry->type =TRACE_CONT ; + write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); +memcpy (&entry->cont.buf, buf+written, write); + entry->cont.buf[write] =0 ; + written += write; + } +__raw_spin_unlock (&data->lock); +} + +/* Add a message provided by the user towards the tracing_mark file */ +int tracing_mark (char *buf,int size) +{ +struct trace_array *tr = &global_trace; +struct trace_array_cpu *data; +struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +int cpu; + +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 )) + goto out; + + size =min (size,TRACE_BUF_SIZE -1 ); + tmp_ent.type =TRACE_MARK ; + buf[size -1 ] =0 ;
Quoted 8 lines
kernel/trace/trace.c __trace_special(void *__tr, void *__data, · line 1024
Quoted 8 lines
kernel/trace/trace.c +8
-0+ +trace_print (buf, size, &tmp_ent, tr, data, flags); + +out: +atomic_dec (&data->disabled); +local_irq_restore (flags); +return size; +}
IMHO we could just make ftrace_printk() work for all tracers. I doubt there will be need to be able to record nil bytes. The idea of a marker is to be a line of human readable text.
Quoted 6 lines
Quoted 6 lines
kernel/trace/trace.c +6
-0+int __ftrace_printk (unsigned long ip,const char *fmt, ...) +{ +struct trace_array *tr = &global_trace; +static DEFINE_SPINLOCK (trace_buf_lock); +static char trace_buf[TRACE_BUF_SIZE ]; +struct trace_array_cpu *data;
Quoted 8 lines
kernel/trace/trace.c __trace_special(void *__tr, void *__data, · line 1040
Quoted 8 lines
kernel/trace/trace.c +8
-0+struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +va_list ap; +int cpu, len =0 ; + +if (likely (!ftrace_function_enabled)) +return 0 ;
And that is the kind of check that makes current ftrace_printk() unusable. I think this restriction should be lifted and allow it to work on all tracers. I would also like to be able to have e.g. mmiotrace_marker(), which would have the same signature as ftrace_printk(), but is a no-op if mmiotrace is not active. So, we could have an __ftrace_vprintk() to make writing such wrappers easy. And the wrappers could be #ifdef'd away, if the corresponding tracer is not built.
I recall somewhere mentioning, that one shouldn't leave ftrace_printk's lying around in "final" code, so I'm not sure how people feel about this wrapping idea, especially when e.g. mmiotrace is hoped to be built-in by default. OTOH, I don't think in-tree drivers and stuff want to use them, so they would be mostly offered for out-of-tree modules (reverse-engineering) and developers (debugging). That makes me wonder if they would be accepted (as exported symbols).
Quoted 64 lines
Quoted 64 lines
kernel/trace/trace.c +52
-0+ +local_irq_save (flags); + cpu =raw_smp_processor_id (); + data = tr->data[cpu]; + disabled =atomic_inc_return (&data->disabled); + +if (unlikely (disabled !=1 || !ftrace_function_enabled)) + goto out; + + tmp_ent.type =TRACE_PRINT ; + tmp_ent.field.print.ip = ip; + +spin_lock (&trace_buf_lock); +va_start (ap, fmt); + len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); +va_end (ap); + + len =min (len,TRACE_BUF_SIZE -1 ); + trace_buf[len] =0 ; + +trace_print (trace_buf, len, &tmp_ent, tr, data, flags); + +spin_unlock (&trace_buf_lock); + + out: +atomic_dec (&data->disabled); +local_irq_restore (flags); + +return len; +} +EXPORT_SYMBOL_GPL (__ftrace_printk); + void tracing_sched_switch_trace(struct trace_array *tr, struct trace_array_cpu *data,@@ -1943,6 +2058,26 @@ static int print_bin_fmt(struct trace_iterator *iter)return 1 ; } +/* Add the user message on the pipe */ +static int print_mark (struct trace_iterator *iter) +{ +struct trace_seq *s = &iter->seq; +struct trace_entry *entry = iter->ent; +struct trace_field *field = &entry->field; + +int ret; + + ret =trace_seq_printf (s, field->print.buf); +if (field->flags &&TRACE_FLAG_CONT ) +trace_seq_print_cont (s, iter); +trace_seq_printf (s,"\n" ); + +if (ret) +return 1 ; +return 0 ; +} + +static int trace_empty (struct trace_iterator *iter) {struct trace_array_cpu *data;@@ -1961,6 +2096,9 @@ static int trace_empty(struct trace_iterator *iter)
Quoted 5 lines
kernel/trace/trace.c static int trace_empty(struct trace_iterator *iter) · line 2101
Quoted 5 lines
kernel/trace/trace.c +3
-0static int print_trace_line (struct trace_iterator *iter) { +if (iter->ent->type ==TRACE_MARK ) +return print_mark (iter); +
Please, put this call after the following...
Quoted 2 lines
kernel/trace/trace.c static int trace_empty(struct trace_iterator *iter) · line 2103
Quoted 2 lines
kernel/trace/trace.c +0
-0if (iter->trace && iter->trace->print_line)return iter->trace->print_line (iter);
..so that tracers may override it at will. Mmiotrace needs to replace newlines and nil characters, before printing it in its own style, i.e. prefixed with a tag and a timestamp, which are specified in the mmiotrace log format.
Quoted 153 lines
Quoted 153 lines
kernel/trace/trace.c +55
-71@@ -2918,6 +3056,49 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,return cnt; } +static int tracing_open_mark (struct inode *inode,struct file *filp) +{ +int ret; + + ret =tracing_open_generic (inode, filp); +if (ret) +return ret; + +if (current_trace == &no_tracer) +return -ENODEV ; + +return 0 ; +} + + +static ssize_t +tracing_mark_write (struct file *filp,const char __user *ubuf, +size_t cnt,loff_t *fpos) +{ +char *buf; + +if (cnt >TRACE_BUF_SIZE ) + cnt =TRACE_BUF_SIZE ; + + buf =kmalloc (cnt,GFP_KERNEL ); + +if (buf ==NULL ) +return -ENOMEM ; + +if (copy_from_user (buf, ubuf, cnt)) { +kfree (buf); +return -EFAULT ; + } + + cnt =tracing_mark (buf, cnt); +kfree (buf); + *fpos += cnt; + +return cnt; +} + + +static struct file_operations tracing_max_lat_fops = { .open = tracing_open_generic, .read = tracing_max_lat_read,@@ -2949,6 +3130,11 @@ static struct file_operations tracing_entries_fops = { .write = tracing_entries_write, }; +static struct file_operations tracing_mark_fops = { + .open = tracing_open_mark, + .write = tracing_mark_write, +}; +#ifdef CONFIG_DYNAMIC_FTRACE static ssize_t@@ -3066,6 +3252,13 @@ static __init void tracer_init_debugfs(void)pr_warning ("Could not create debugfs " "'trace_entries' entry\n" ); + entry =debugfs_create_file ("trace_marker" ,0220 , d_tracer, +NULL , &tracing_mark_fops); + +if (!entry) +pr_warning ("Could not create debugfs " +"'trace_marker' entry\n" ); +#ifdef CONFIG_DYNAMIC_FTRACE entry = debugfs_create_file("dyn_ftrace_total_info", 0444, d_tracer, &ftrace_update_tot_cnt,@@ -3079,77 +3272,6 @@ static __init void tracer_init_debugfs(void)#endif } -#define TRACE_BUF_SIZE 1024 -#define TRACE_PRINT_BUF_SIZE \ - (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) -#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field) - -int __ftrace_printk (unsigned long ip,const char *fmt, ...) -{ -struct trace_array *tr = &global_trace; -static DEFINE_SPINLOCK (trace_buf_lock); -static char trace_buf[TRACE_BUF_SIZE ]; -struct trace_array_cpu *data; -struct trace_entry *entry; -unsigned long flags; -long disabled; -va_list ap; -int cpu, len =0 , write, written =0 ; - -if (likely (!ftrace_function_enabled)) -return 0 ; - -local_irq_save (flags); - cpu =raw_smp_processor_id (); - data = tr->data[cpu]; - disabled =atomic_inc_return (&data->disabled); - -if (unlikely (disabled !=1 || !ftrace_function_enabled)) - goto out; - -spin_lock (&trace_buf_lock); -va_start (ap, fmt); - len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); -va_end (ap); - - len =min (len,TRACE_BUF_SIZE -1 ); - trace_buf[len] =0 ; - -__raw_spin_lock (&data->lock); - entry =tracing_get_trace_entry (tr, data); -tracing_generic_entry_update (entry, flags); - entry->type =TRACE_PRINT ; - entry->field.print.ip = ip; - - write =min (len, (int )(TRACE_PRINT_BUF_SIZE -1 )); - -memcpy (&entry->field.print.buf, trace_buf, write); - entry->field.print.buf[write] =0 ; - written = write; - -if (written != len) - entry->field.flags |=TRACE_FLAG_CONT ; - -while (written != len) { - entry =tracing_get_trace_entry (tr, data); - - entry->type =TRACE_CONT ; - write =min (len - written, (int )(TRACE_CONT_BUF_SIZE -1 )); -memcpy (&entry->cont.buf, trace_buf+written, write); - entry->cont.buf[write] =0 ; - written += write; - } -__raw_spin_unlock (&data->lock); - -spin_unlock (&trace_buf_lock); - - out: -atomic_dec (&data->disabled); -local_irq_restore (flags); - -return len; -} -EXPORT_SYMBOL_GPL (__ftrace_printk);
Quoted 13 lines
kernel/trace/trace.h enum trace_type { · line 19
Quoted 13 lines
kernel/trace/trace.c +0
-0static int trace_panic_handler (struct notifier_block *this,unsigned long event,void *unused)kernel/trace/trace.h +1
-0@@ -14,6 +14,7 @@ enum trace_type {TRACE_CTX ,TRACE_WAKE ,TRACE_CONT , +TRACE_MARK ,TRACE_STACK , TRACE_PRINT,
I think TRACE_MARK and TRACE_PRINT are equivalent, so we could stick to TRACE_PRINT.
Quoted 10 lines
Quoted 10 lines
kernel/trace/trace.h +4
-0TRACE_SPECIAL,@@ -106,6 +107,10 @@ struct trace_entry { };#define TRACE_ENTRY_SIZE sizeof(struct trace_entry) +#define TRACE_BUF_SIZE 1024 +#define TRACE_PRINT_BUF_SIZE \ + (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) +#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field)
Quoted 7 lines
kernel/trace/trace.h struct trace_entry { · line 116
Quoted 3 lines
kernel/trace/trace.h +0
-0/* * The CPU trace array - it consists of thousands of trace entries Do you think I should modify something or use a way to make it better? (Added Pekka Paalanen in Cc since it concerns an idea from his mmiotrace's documentation)...
Thanks for adding me, I've been brewing my own version of this stuff, but didn't yet solve the __ftrace_printk-is-unusable issue yet. I have the mmiotrace specific parts written for TRACE_PRINT, so we haven't really overlapped each other's work yet.
Ingo recently told me it would be good to have a generic debugfs file for adding markers to any tracer log, and this is basically what you did.
I didn't try the patch yet, or read it too carefully, but I should. Unfortunately I'm away the next weekend, so I hope to continue working on it the weekend after that.
Thanks,
pq
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Quoted 8 lines · Pekka Paalanen
Quoted 3 lines
Do you think I should modify something or use a way to make it better? (Added Pekka Paalanen in Cc since it concerns an idea from his mmiotrace's documentation)...
Thanks for adding me, I've been brewing my own version of this stuff, but didn't yet solve the __ftrace_printk-is-unusable issue yet. I have the mmiotrace specific parts written for
TRACE_PRINT, so we haven't really overlapped each other's work yet.
we can certainly include and test Frédéric's patch in tip/tracing/ftrace
- i'll wait for v2 as i guess he will implement the modifications suggested by you?
Ingo
2008/8/28 Ingo Molnar <[email protected]>:
Quoted 12 lines · Pekka Paalanen
Quoted 9 lines
Quoted 4 lines
Do you think I should modify something or use a way to make it better? (Added Pekka Paalanen in Cc since it concerns an idea from his mmiotrace's documentation)...
Thanks for adding me, I've been brewing my own version of this stuff, but didn't yet solve the __ftrace_printk-is-unusable issue yet. I have the mmiotrace specific parts written for
TRACE_PRINT, so we haven't really overlapped each other's work yet.
Quoted 5 lines
we can certainly include and test Frédéric's patch in tip/tracing/ftrace
- i'll wait for v2 as i guess he will implement the modifications suggested by you?Ingo
Ok I will send a new patch on the next days...
Hello Pekka,
2008/8/27 Pekka Paalanen <[email protected]>:
Quoted 19 lines
IMHO we could just make
ftrace_printk()work for all tracers. I doubt there will be need to be able to record nil bytes. The idea of a marker is to be a line of human readable text.Quoted 6 lines
Quoted 6 lines
kernel/trace/trace.c +6
-0+int __ftrace_printk (unsigned long ip,const char *fmt, ...) +{ +struct trace_array *tr = &global_trace; +static DEFINE_SPINLOCK (trace_buf_lock); +static char trace_buf[TRACE_BUF_SIZE ]; +struct trace_array_cpu *data;Quoted 8 lines
kernel/trace/trace.c __trace_special(void *__tr, void *__data, · line 1040
Quoted 8 lines
kernel/trace/trace.c +8
-0+struct trace_entry tmp_ent; +unsigned long flags; +long disabled; +va_list ap; +int cpu, len =0 ; + +if (likely (!ftrace_function_enabled)) +return 0 ;
Quoted 7 lines
And that is the kind of check that makes current
ftrace_printk()unusable. I think this restriction should be lifted and allow it to work on all tracers. I would also like to be able to have e.g.mmiotrace_marker(), which would have the same signature asftrace_printk(), but is a no-op if mmiotrace is not active. So, we could have an__ftrace_vprintk()to make writing such wrappers easy. And the wrappers could be #ifdef'd away, if the corresponding tracer is not built.
I like your idea of a ftrace_vprintk wrapper.
But actually I'm questioning about the fact that the tracing api itself is not generic enough.
At this time, a tracer has to put a function inside the tracing api when it wants to add an entry into the list.
See __trace_mmiotrace_rw() for example.
Just imagine if one wants to implement a tracer by using a simple module. The way seems to be simple at the beginning: you define your struct tracer, implement your functions and register your tracer. But the simple, single function that will add your entries has to be put in tracing api.
It's quite impossible without changing the trace.c file and so impossible without recompiling your kernel.
And if I make my own tracer and want to implement my handler for the marker messages, I will have to put my foo_trace_printk in trace.c and add it on the wrapper.
IMHO the choice of a wrapper is good but it should dynamically dispatch the message on a handler proposed by the tracer. I think about a new function pointer which could be called "mark" on the struct tracer.
And (always IMHO) I think that functions like __trace_mmiotrace_rw() shouldn't be located on trace.c but implemented on the appropriate tracer (in this example: trace_mmiotrace.c).
And for this purpose, functions like tracing_generic_entry_update() (or even more higher level function of entry adding) should be symbol's exported.
With such a new environment, building personal and quick tracers by using modules may be more appreciated if one has not to touch the tracing API or the whole running kernel.
Quoted 7 lines
I recall somewhere mentioning, that one shouldn't leave ftrace_printk's lying around in "final" code, so I'm not sure how people feel about this wrapping idea, especially when e.g. mmiotrace is hoped to be built-in by default. OTOH, I don't think in-tree drivers and stuff want to use them, so they would be mostly offered for out-of-tree modules (reverse-engineering) and developers (debugging). That makes me wonder if they would be accepted (as exported symbols).
Yes I think such a function should really be exported. For example using mmiotrace on a module and beeing able to signal the fact that we are entering the "foo" function seems to me very useful. It's important to know where we are in all these IO for debugging....
Quoted 8 lines
Quoted 5 lines
kernel/trace/trace.c static int trace_empty(struct trace_iterator *iter) · line 2101
Quoted 5 lines
static int
print_trace_line(struct trace_iterator *iter){kernel/trace/trace.c +3
-0+if (iter->ent->type ==TRACE_MARK ) +return print_mark (iter); +Please, put this call after the following...
Quoted 7 lines
Quoted 2 lines
Quoted 2 lines
if (iter->trace && iter->trace->print_line) return iter->trace->print_line(iter);..so that tracers may override it at will. Mmiotrace needs to replace newlines and nil characters, before printing it in its own style, i.e. prefixed with a tag and a timestamp, which are specified in the mmiotrace log format.
Perhaps the idea of an appropriate "mark" handler for each tracer could solve this...
Quoted 3 lines
I didn't try the patch yet, or read it too carefully, but I should. Unfortunately I'm away the next weekend, so I hope to continue working on it the weekend after that.
No problem.
Thanks!
Quoted 11 lines · On Thu, 28 Aug 2008 11:04:36 +0100 "Frédéric Weisbecker" <[email protected]>…
2008/8/27 Pekka Paalanen <[email protected]>:
Quoted 6 lines
tracers. I would also like to be able to have e.g.
mmiotrace_marker(), which would have the same signature asftrace_printk(), but is a no-op if mmiotrace is not active. So, we could have an__ftrace_vprintk()to make writing such wrappers easy. And the wrappers could be #ifdef'd away, if the corresponding tracer is not built.I like your idea of a
ftrace_vprintkwrapper.
But actually I'm questioning about the fact that the tracing api itself is not generic enough.
I think making it more modular would be nice, but I'm not really working on the generic parts.
Quoted 3 lines
And (always IMHO) I think that functions like
__trace_mmiotrace_rw()shouldn't be located ontrace.cbut implemented on the appropriate tracer (in this example:trace_mmiotrace.c).
I feel the same.
Quoted 8 lines
Quoted 7 lines
I recall somewhere mentioning, that one shouldn't leave ftrace_printk's lying around in "final" code, so I'm not sure how people feel about this wrapping idea, especially when e.g. mmiotrace is hoped to be built-in by default. OTOH, I don't think in-tree drivers and stuff want to use them, so they would be mostly offered for out-of-tree modules (reverse-engineering) and developers (debugging). That makes me wonder if they would be accepted (as exported symbols).
Quoted 4 lines
Yes I think such a function should really be exported. For example using mmiotrace on a module and beeing able to signal the fact that we are entering the "foo" function seems to me very useful. It's important to know where we are in all these IO for debugging....
Yes, but the atmosphere is that if there are no users in-tree, the feature gets kicked, out-of-tree users or no. That's the reason mmiotrace went in-tree in the first place. So, to get that stuff exported, we might need in-tree users, I believe.
Thanks.
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
2008/8/28 Pekka Paalanen <[email protected]>:
Quoted 4 lines
Yes, but the atmosphere is that if there are no users in-tree, the feature gets kicked, out-of-tree users or no. That's the reason mmiotrace went in-tree in the first place. So, to get that stuff exported, we might need in-tree users, I believe.
Perhaps it should be more discussed because it is an unsual case...
Ok so just a question before I start a new patch to correct the marker's file.
What is the best way to implement tracers's printk handlers? Do you think that these functions must be implemented in trace.c or is it more relevant to dispatch the message to
a function provided by the current tracer in its struct tracer operations? If such handler is not implemented, we just defaults the formatting like ftrace_printk does.
Thanks...
Quoted 1 line · On Thu, 4 Sep 2008 18:20:09 +0200 "Frédéric Weisbecker" <[email protected]>…
What is the best way to implement tracers's printk handlers?
Your last message had an idea I didn't think before (or I misunderstood you), that there could be an optional callback for inserting markers into the ring buffer. My first thought was to have the usual entry handler (print_line callback) to format marker text when it is taken from the ring buffer and read to user space.
Quoted 5 lines
Do you think that these functions must be implemented in
trace.cor is it more relevant to dispatch the message to
a function provided by the current tracer in its struct tracer operations? If such handler is not implemented, we just defaults the formatting likeftrace_printkdoes.
For the output formatting case, I'd prefer the print_line callback, it's just one more case for an entry type in there. Notice the difference between writing to ring buffer and reading to user.
The trick is, when does mmiotrace sanitize the marker text, when it comes from user space, the debugfs file. Either
a) have another callback for inserting messages into the ring buffer
b) have a customisable trace_seq_print_cont()
I think I'd favour b). When I tried to use trace_seq_print_cont(), I found it difficult to control the printing of \n at the end of message. So I would implement my own routine to handle also what trace_seq_print_cont() does, filtering the text while copying it to struct trace_seq. I'm not sure where this function should live. It could be useful to all tracers, that want "one line per marker entry" style output, so it could live in trace.c.
So my suggestion is to put the marker text unfiltered into the ring buffer, and filter it (if required) during read to user (print_line).
Cheers,
pq
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Steven Rostedt
maintainerQuoted 34 lines · Pekka Paalanen
Quoted 1 line · On Thu, 4 Sep 2008 18:20:09 +0200 "Fr?d?ric Weisbecker" <[email protected]>…
What is the best way to implement tracers's printk handlers?
Your last message had an idea I didn't think before (or I misunderstood you), that there could be an optional callback for inserting markers into the ring buffer. My first thought was to have the usual entry handler (
print_linecallback) to format marker text when it is taken from the ring buffer and read to user space.Quoted 5 lines
Do you think that these functions must be implemented in
trace.cor is it more relevant to dispatch the message to
a function provided by the current tracer in its struct tracer operations? If such handler is not implemented, we just defaults the formatting likeftrace_printkdoes.For the output formatting case, I'd prefer the
print_linecallback, it's just one more case for an entry type in there. Notice the difference between writing to ring buffer and reading to user.The trick is, when does mmiotrace sanitize the marker text, when it comes from user space, the debugfs file. Either
a) have another callback for inserting messages into the ring buffer
b) have a customisabletrace_seq_print_cont()I think I'd favour b). When I tried to use
trace_seq_print_cont(), I found it difficult to control the printing of \n at the end of message. So I would implement my own routine to handle also whattrace_seq_print_cont()does, filtering the text while copying it to structtrace_seq. I'm not sure where this function should live. It could be useful to all tracers, that want "one line per marker entry" style output, so it could live intrace.c.
Quoted 3 lines
So my suggestion is to put the marker text unfiltered into the ring buffer, and filter it (if required) during read to user (
print_line).
For logdev (my pet project from way back, and the latest ftrace is based on), I had a CUSTOM type. The API allowed to register a callback to a type, and it would associate that type to some number (descriptor) and pass that number back to you. Then you could use this number to write to the buffer using the CUSTOM type and registered number. On output, when a CUSTOM type is detected, it would read the custom.id (the number) and search for any registered callbacks to handle the entry.
This probably would not be too difficult to implement. Especially since it is already implemented in logdev.
(see http://rostedt.homelinux.com/logdev/)
-- Steve
2008/9/4 Steven Rostedt <[email protected]>:
Quoted 8 lines
For logdev (my pet project from way back, and the latest ftrace is based on), I had a CUSTOM type. The API allowed to register a callback to a type, and it would associate that type to some number (descriptor) and pass that number back to you. Then you could use this number to write to the buffer using the CUSTOM type and registered number. On output, when a CUSTOM type is detected, it would read the custom.id (the number) and search for any registered callbacks to handle the entry.
Quoted 5 lines
This probably would not be too difficult to implement. Especially since it is already implemented in logdev.
(see http://rostedt.homelinux.com/logdev/)-- Steve
Why not. It is a way for a tracer to handle output for any type of entries. But will this feature really be used for other special types than TRACE_PRINT? I'm not sure... If it is not the case, the Pekka's solution seems to me far more simple.
But actually I don't know the needs of others tracers...
Quoted 14 lines · On Sat, 6 Sep 2008 13:39:55 +0200 "Frédéric Weisbecker" <[email protected]>…
2008/9/4 Steven Rostedt <[email protected]>:
Quoted 12 lines
For logdev (my pet project from way back, and the latest ftrace is based on), I had a CUSTOM type. The API allowed to register a callback to a type, and it would associate that type to some number (descriptor) and pass that number back to you. Then you could use this number to write to the buffer using the CUSTOM type and registered number. On output, when a CUSTOM type is detected, it would read the custom.id (the number) and search for any registered callbacks to handle the entry.
This probably would not be too difficult to implement. Especially since it is already implemented in logdev.
(see http://rostedt.homelinux.com/logdev/)
Quoted 8 lines
Quoted 1 line
-- Steve
Why not. It is a way for a tracer to handle output for any type of entries. But will this feature really be used for other special types than
TRACE_PRINT? I'm not sure... If it is not the case, the Pekka's solution seems to me far more simple.But actually I don't know the needs of others tracers...
I never thought TRACE_PRINT would need anything more. At least I'm happy with the concept of TRACE_PRINT, it just needs some adjustments in the API to be nice to use.
True, I might some day want to add yet another entry type for mmiotrace, but I'm not planning that for now, and I could just add it like they are in the current framework. But the benefit of the CUSTOM type would be to allow modularized and out-of-tree tracers. And then, why keep the current predefined types, why not make everything a CUSTOM type? Just define a block size in the ring buffer and use TRACE_CONT to handle payload larger than the block.
Anyway, personally I'm satisfied with the current state of the framework and I can only talk for mmiotrace.
Cheers,
pq
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Tracing/ftrace: trouble with trace_entries and trace_pipe
In reply to Steven RostedtHi Steven and others,
first a minor bug: it seems the units of /debug/tracing/trace_entries is different for read and write. This is confusing for the users, since I can't say "if you have problems, double it". If I read from it something like 16422, then write back 16422, next I read 214. I can't recall the exact numbers, but the difference really is two orders of magnitude. I have 1 GB RAM in this box, so that shouldn't be an issue.
My other problem is with trace_pipe. It is again making 'cat' quit too early. The condition triggered is
if (!tracer_enabled && iter->pos) {
in tracing_read_pipe(), and it is followed by triggering
/* stop when tracing is finished */
if (trace_empty(iter)) {and then sret=0, so read returns 0 and 'cat' exits.
Now, I am trying my mmiotrace marker patches, but as far as I can tell, nothing I modified is the reason for this. I didn't yet explicitly test for it, though. I'll send these patches after I hear from Frederic.
The cat-quit problem is not a constant state. After boot, I could play with my markers and testmmiotrace without cat quitting. Then something happens, and cat starts the quitting behaviour, and won't get to normal by disabling and enabling mmiotrace.
I have a couple of wild guesses of what might be related:
- ring buffer wrap-around
- ring buffer overflow (at first try I hit these, the second try after putting debug-pr_info's in place I don't hit this)
- ring buffer resize (after playing with trace_entries, cat-quit problem was present, though it might have been present before)
After viewing the git history, I have some more guesses, mainly related to setting tracer_enabled to 0.
- commit 2b1bce1787700768cbc87c8509851c6f49d252dc
I don't see where tracer_enabled would be set to 1, when mmiotrace is enabled. It used to default to 1 and mmiotrace was happy.
- __tracing_open() sets it to 0 (not called for the pipe)
- tracing_release() sets it to 1
- tracing_ctrl_write() toggles it
- tracing_read_pipe() tests it
- tracer_alloc_buffers() uses it
And other tracers seem to use it a lot.
Mmiotrace does use the tracer::ctrl_update hook, and allow/disallow calls to __trace_mmiotrace_{rw,map}() via enabling/disabling the whole mmiotrace core. Is this not enough, or is it inappropriate?
It seems tracer_enabled is used by the trace framework itself to enable/disable... what? Hmm, maybe nothing I care about.
Should mmiotrace simply do
tracer_enabled = 1;
in mmio_trace_init()?
Should mmiotrace test tracer_enabled, and if so, when?
Thanks.
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Steven Rostedt
maintainerRe: Tracing/ftrace: trouble with trace_entries and trace_pipe
Quoted 8 lines · Pekka Paalanen
Hi Steven and others,
first a minor bug: it seems the units of /debug/tracing/trace_entries is different for read and write. This is confusing for the users, since I can't say "if you have problems, double it". If I read from it something like 16422, then write back 16422, next I read 214. I can't recall the exact numbers, but the difference really is two orders of magnitude. I have 1 GB RAM in this box, so that shouldn't be an issue.
You write to it the same number that you read from and it returned something different?? That is indeed a bug, since it should definitely detect that. Is this linux-tip? I'll have to play with it to make sure nothing broke it recently.
I just tried the latest mainline, and it seemed to work there.
Quoted 41 lines
My other problem is with
trace_pipe. It is again making 'cat' quit too early. The condition triggered isif (!tracer_enabled && iter->pos) { in tracing_read_pipe(), and it is followed by triggering /* stop when tracing is finished */ if (trace_empty(iter)) {and then sret=0, so read returns 0 and 'cat' exits.
Now, I am trying my mmiotrace marker patches, but as far as I can tell, nothing I modified is the reason for this. I didn't yet explicitly test for it, though. I'll send these patches after I hear from Frederic.
The cat-quit problem is not a constant state. After boot, I could play with my markers and testmmiotrace without cat quitting. Then something happens, and cat starts the quitting behaviour, and won't get to normal by disabling and enabling mmiotrace.
I have a couple of wild guesses of what might be related:
- ring buffer wrap-around
- ring buffer overflow (at first try I hit these, the second try after putting debug-pr_info's in place I don't hit this)
- ring buffer resize (after playing withtrace_entries, cat-quit problem was present, though it might have been present before)After viewing the git history, I have some more guesses, mainly related to setting
tracer_enabledto 0.
- commit2b1bce1787700768cbc87c8509851c6f49d252dc
I don't see wheretracer_enabledwould be set to 1, when mmiotrace is enabled. It used to default to 1 and mmiotrace was happy.
-__tracing_open()sets it to 0 (not called for the pipe)
-tracing_release()sets it to 1
-tracing_ctrl_write()toggles it
-tracing_read_pipe()tests it
-tracer_alloc_buffers()uses it
And other tracers seem to use it a lot.Mmiotrace does use the
tracer::ctrl_updatehook, and allow/disallow calls to __trace_mmiotrace_{rw,map}() via enabling/disabling the whole mmiotrace core. Is this not enough, or is it inappropriate?
Quoted 8 lines
It seems
tracer_enabledis used by the trace framework itself to enable/disable... what? Hmm, maybe nothing I care about.Should mmiotrace simply do
tracer_enabled = 1;in
mmio_trace_init()?Should mmiotrace test
tracer_enabled, and if so, when?
No, tracer_enabled is something that is internal to the tracer infrastructure.
if you read from either tracing/trace or tracing/latency_trace it will disable the tracer while you dump. But you should not be doing that. The trace_pipe should not disable that either.
-- Steve
Re: Tracing/ftrace: trouble with trace_entries and trace_pipe
Quoted 12 lines · On Mon, 15 Sep 2008 17:14:34 -0400 (EDT) Steven Rostedt <[email protected]>…
Quoted 8 lines · Pekka Paalanen
Hi Steven and others,
first a minor bug: it seems the units of /debug/tracing/trace_entries is different for read and write. This is confusing for the users, since I can't say "if you have problems, double it". If I read from it something like 16422, then write back 16422, next I read 214. I can't recall the exact numbers, but the difference really is two orders of magnitude. I have 1 GB RAM in this box, so that shouldn't be an issue.
Quoted 6 lines
You write to it the same number that you read from and it returned something different?? That is indeed a bug, since it should definitely detect that. Is this linux-tip? I'll have to play with it to make sure nothing broke it recently.
I just tried the latest mainline, and it seemed to work there.
Yes, it returned a very different number. This is Ingo's tip/master, sorry for not being explicit. Checked-out on Sunday.
Echoing the following numbers to trace_entries triggers it:
200, 64, 640, 16422, 16422, 16422, 164220...
so the ridiculously small number 64 does something bad. After 640, I read back something less than 200. Each following write increases that number by 46.
16422 is the default before writing anything.
That is even stranger than I thought. :-o
I was going to test the buffer overflow with mmiotrace.
Quoted 47 lines
Quoted 47 lines
My other problem is with
trace_pipe. It is again making 'cat' quit too early. The condition triggered isif (!tracer_enabled && iter->pos) { in tracing_read_pipe(), and it is followed by triggering /* stop when tracing is finished */ if (trace_empty(iter)) {and then sret=0, so read returns 0 and 'cat' exits.
Now, I am trying my mmiotrace marker patches, but as far as I can tell, nothing I modified is the reason for this. I didn't yet explicitly test for it, though. I'll send these patches after I hear from Frederic.
The cat-quit problem is not a constant state. After boot, I could play with my markers and testmmiotrace without cat quitting. Then something happens, and cat starts the quitting behaviour, and won't get to normal by disabling and enabling mmiotrace.
I have a couple of wild guesses of what might be related:
- ring buffer wrap-around
- ring buffer overflow (at first try I hit these, the second try after putting debug-pr_info's in place I don't hit this)
- ring buffer resize (after playing withtrace_entries, cat-quit problem was present, though it might have been present before)After viewing the git history, I have some more guesses, mainly related to setting
tracer_enabledto 0.
- commit2b1bce1787700768cbc87c8509851c6f49d252dc
I don't see wheretracer_enabledwould be set to 1, when mmiotrace is enabled. It used to default to 1 and mmiotrace was happy.
-__tracing_open()sets it to 0 (not called for the pipe)
-tracing_release()sets it to 1
-tracing_ctrl_write()toggles it
-tracing_read_pipe()tests it
-tracer_alloc_buffers()uses it
And other tracers seem to use it a lot.Mmiotrace does use the
tracer::ctrl_updatehook, and allow/disallow calls to __trace_mmiotrace_{rw,map}() via enabling/disabling the whole mmiotrace core. Is this not enough, or is it inappropriate?It seems
tracer_enabledis used by the trace framework itself to enable/disable... what? Hmm, maybe nothing I care about.Should mmiotrace simply do
tracer_enabled = 1;in
mmio_trace_init()?
Quoted 8 lines
Quoted 1 line
Should mmiotrace test
tracer_enabled, and if so, when?No,
tracer_enabledis something that is internal to the tracer infrastructure.if you read from either tracing/trace or tracing/latency_trace it will disable the tracer while you dump. But you should not be doing that. The
trace_pipeshould not disable that either.
Ok, so the problem is probably the commit I mentioned. It makes the no_tracer tracer to set tracer_enabled to 0, and I can't find where it would be set to 1 for mmiotrace. And this interferes with tracing_read_pipe(), making it quit when iter->pos is non-zero. See no_trace_init() in trace.c. According to this, the cat-quit occurs when the buffer gets empty after first data, but this isn't totally in agreement with what I recall from my experiments. And it does happen also on other times than injecting markers.
So either it is wrong to check tracer_enabled in tracing_read_pipe(), or no_trace_init() should not touch it.
Steven, what do you think?
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Re: Tracing/ftrace: trouble with trace_entries and trace_pipe
2008/9/16 Pekka Paalanen <[email protected]>:
Quoted 11 lines
Ok, so the problem is probably the commit I mentioned. It makes the
no_tracertracer to settracer_enabledto 0, and I can't find where it would be set to 1 for mmiotrace. And this interferes withtracing_read_pipe(), making it quit wheniter->posis non-zero. Seeno_trace_init()intrace.c. According to this, the cat-quit occurs when the buffer gets empty after first data, but this isn't totally in agreement with what I recall from my experiments. And it does happen also on other times than injecting markers.So either it is wrong to check
tracer_enabledintracing_read_pipe(), orno_trace_init()should not touch it.
Indeed that could be the problem.None_tracer is chosen as the default tracer when the tracer engine loads. But actually no_trace_init is not called at this time.
But if you set another tracer and reset current_tracer to none, you will call no_trace_init. Since tracer_enabled is not reset to 1 with other tracer's init functions, the problem occurs when you choose one more time another tracer.
I think that mmiotrace receives a smaller flow of entries (depends on the debugged module) whereas sched_switch or function's tracer, as an example, are continuously fed and never enter the "while (trace_empty(iter))" block. That's why I only see this bug in mmiotrace.
Perhaps it would be a good idea to reenable tracer_enabled on tracing_set_trace_write() just before calling the init callback of the tracer chosen.
Re: Tracing/ftrace: trouble with trace_entries and trace_pipe
Quoted 13 lines · On Wed, 17 Sep 2008 14:41:29 +0200 "Frédéric Weisbecker" <[email protected]>…
2008/9/16 Pekka Paalanen <[email protected]>:
Quoted 11 lines
Ok, so the problem is probably the commit I mentioned. It makes the
no_tracertracer to settracer_enabledto 0, and I can't find where it would be set to 1 for mmiotrace. And this interferes withtracing_read_pipe(), making it quit wheniter->posis non-zero. Seeno_trace_init()intrace.c. According to this, the cat-quit occurs when the buffer gets empty after first data, but this isn't totally in agreement with what I recall from my experiments. And it does happen also on other times than injecting markers.So either it is wrong to check
tracer_enabledintracing_read_pipe(), orno_trace_init()should not touch it.
Quoted 8 lines
Indeed that could be the problem.
None_traceris chosen as the default tracer when the tracer engine loads. But actuallyno_trace_initis not called at this time.But if you set another tracer and reset
current_tracerto none, you will callno_trace_init. Sincetracer_enabledis not reset to 1 with other tracer's init functions, the problem occurs when you choose one more time another tracer.
Ah, this would explain the "non-deterministic" behaviour I saw.
Quoted 5 lines
I think that mmiotrace receives a smaller flow of entries (depends on the debugged module) whereas
sched_switchor function's tracer, as an example, are continuously fed and never enter the "while (trace_empty(iter))" block. That's why I only see this bug in mmiotrace.
Mmiotrace does see times, when there are a small number of events coming, even when tracing a graphics driver. Sounds plausible.
Quoted 3 lines
Perhaps it would be a good idea to reenable
tracer_enabledontracing_set_trace_write()just before calling the init callback of the tracer chosen.
That's a third option, yes.
Steven, what is the correct fix?
Frederic, thank you very much for testing this!
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
PATCH 1/7 x86 mmiotrace: fix a rare memory leak.
In reply to Steven RostedtQuoted 1 line
From
da74191de5e5a3c0adee0604757d19b2faf8ec79Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sat, 23 Aug 2008 14:32:22 +0300
Subject: [PATCH] x86 mmiotrace: fix a rare memory leak.
--- arch/x86/mm/mmio-mod.c | 4 +++- 1 files changed, 3 insertions(+), 1 deletions(-)
arch/x86/mm/mmio-mod.c +3 -1
@@ -307,8 +307,10 @@ static void ioremap_trace_core(resource_size_t offset, unsigned long size, map.map_id = trace->id;spin_lock_irq (&trace_lock); -if (!is_enabled ()) +if (!is_enabled ()) { +kfree (trace); goto not_enabled; + }mmio_trace_mapping (&map);list_add_tail (&trace->list, &trace_list);
Signature · 1 line
1.5.6.4
PATCH 2/7 ftrace: move mmiotrace functions out of trace.c.
Quoted 1 line
From
743cab2763d3e8d9f4d3b82a02fcdc5ad8a13c04Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 16:53:05 +0300
Subject: [PATCH] ftrace: move mmiotrace functions out of trace.c.
Moves the mmiotrace specific functions from trace.c to trace_mmiotrace.c. Functions trace_wake_up(), tracing_get_trace_entry(), and tracing_generic_entry_update() are therefore made available outside trace.c.
--- kernel/trace/trace.c | 46 +-------------------------------------- kernel/trace/trace.h | 15 +++++------- kernel/trace/trace_mmiotrace.c | 42 ++++++++++++++++++++++++++++++++++++ 3 files changed, 50 insertions(+), 53 deletions(-)
kernel/trace/trace.c +2 -44
@@ -785,7 +785,7 @@ trace_next_page(struct trace_array_cpu *data, void *addr)return page_address (page); } -static inline struct trace_entry * +struct trace_entry *tracing_get_trace_entry (struct trace_array *tr,struct trace_array_cpu *data) {unsigned long idx, idx_next;
@@ -821,7 +821,7 @@ tracing_get_trace_entry(struct trace_array *tr, struct trace_array_cpu *data)return entry; } -static inline void +void tracing_generic_entry_update (struct trace_entry *entry,unsigned long flags) {struct task_struct *tsk = current;
@@ -865,48 +865,6 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,trace_function (tr, data, ip, parent_ip, flags); } -#ifdef CONFIG_MMIOTRACE -void __trace_mmiotrace_rw (struct trace_array *tr,struct trace_array_cpu *data, -struct mmiotrace_rw *rw) -{ -struct trace_entry *entry; -unsigned long irq_flags; - -raw_local_irq_save (irq_flags); -__raw_spin_lock (&data->lock); - - entry =tracing_get_trace_entry (tr, data); -tracing_generic_entry_update (entry,0 ); - entry->type =TRACE_MMIO_RW ; - entry->field.mmiorw = *rw; - -__raw_spin_unlock (&data->lock); -raw_local_irq_restore (irq_flags); - -trace_wake_up (); -} - -void __trace_mmiotrace_map (struct trace_array *tr,struct trace_array_cpu *data, -struct mmiotrace_map *map) -{ -struct trace_entry *entry; -unsigned long irq_flags; - -raw_local_irq_save (irq_flags); -__raw_spin_lock (&data->lock); - - entry =tracing_get_trace_entry (tr, data); -tracing_generic_entry_update (entry,0 ); - entry->type =TRACE_MMIO_MAP ; - entry->field.mmiomap = *map; - -__raw_spin_unlock (&data->lock); -raw_local_irq_restore (irq_flags); - -trace_wake_up (); -} -#endif - void __trace_stack(struct trace_array *tr, struct trace_array_cpu *data, unsigned long flags,
kernel/trace/trace.h +6 -9
@@ -213,11 +213,17 @@ struct trace_iterator {long idx; }; +void trace_wake_up (void );void tracing_reset (struct trace_array_cpu *data);int tracing_open_generic (struct inode *inode,struct file *filp);struct dentry *tracing_init_dentry (void );void init_tracer_sysprof_debugfs (struct dentry *d_tracer); +struct trace_entry *tracing_get_trace_entry (struct trace_array *tr, +struct trace_array_cpu *data); +void tracing_generic_entry_update (struct trace_entry *entry, +unsigned long flags); + void ftrace(struct trace_array *tr, struct trace_array_cpu *data, unsigned long ip,
@@ -291,15 +297,6 @@ extern unsigned long ftrace_update_tot_cnt;extern int DYN_FTRACE_TEST_NAME (void );#endif -#ifdef CONFIG_MMIOTRACE -extern void __trace_mmiotrace_rw (struct trace_array *tr, -struct trace_array_cpu *data, -struct mmiotrace_rw *rw); -extern void __trace_mmiotrace_map (struct trace_array *tr, -struct trace_array_cpu *data, -struct mmiotrace_map *map); -#endif -#ifdef CONFIG_FTRACE_STARTUP_TEST #ifdef CONFIG_FTRACE extern int trace_selftest_startup_function(struct tracer *trace,
kernel/trace/trace_mmiotrace.c +42 -0
54 lines not on this page · raw message
Signature · 1 line
1.5.6.4
PATCH 3/7 ftrace: add trace_vprintk()
In reply to Pekka PaalanenQuoted 1 line
From
5579d3e6471201524697d1cc32fb37f1a4f70f95Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 17:27:05 +0300
Subject: [PATCH] ftrace: add trace_vprintk()
trace_vprintk() for easier implementation of tracer specific *_printk functions. Add check check for no_tracer, and implement __ftrace_printk() as a wrapper.
--- kernel/trace/trace.c | 24 ++++++++++++++++++------ kernel/trace/trace.h | 1 + 2 files changed, 19 insertions(+), 6 deletions(-)
kernel/trace/trace.c +18 -6
@@ -3054,7 +3054,7 @@ static __init void tracer_init_debugfs(void) (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf))#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field) -int __ftrace_printk (unsigned long ip,const char *fmt, ...) +int trace_vprintk (unsigned long ip,const char *fmt,va_list args) {static DEFINE_SPINLOCK (trace_buf_lock);static char trace_buf[TRACE_BUF_SIZE ];
@@ -3064,10 +3064,9 @@ int __ftrace_printk(unsigned long ip, const char *fmt, ...)struct trace_entry *entry;unsigned long flags;long disabled; -va_list ap;int cpu, len =0 , write, written =0 ; -if (!(trace_flags &TRACE_ITER_PRINTK ) || !tr->ctrl || tracing_disabled) +if (current_trace == &no_tracer || !tr->ctrl || tracing_disabled)return 0 ;local_irq_save (flags);
@@ -3079,9 +3078,7 @@ int __ftrace_printk(unsigned long ip, const char *fmt, ...) goto out;spin_lock (&trace_buf_lock); -va_start (ap, fmt); - len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, ap); -va_end (ap); + len =vsnprintf (trace_buf,TRACE_BUF_SIZE , fmt, args); len =min (len,TRACE_BUF_SIZE -1 ); trace_buf[len] =0 ;
@@ -3120,6 +3117,21 @@ int __ftrace_printk(unsigned long ip, const char *fmt, ...)return len; } +EXPORT_SYMBOL_GPL (trace_vprintk); + +int __ftrace_printk (unsigned long ip,const char *fmt, ...) +{ +int ret; +va_list ap; + +if (!(trace_flags &TRACE_ITER_PRINTK )) +return 0 ; + +va_start (ap, fmt); + ret =trace_vprintk (ip, fmt, ap); +va_end (ap); +return ret; +}EXPORT_SYMBOL_GPL (__ftrace_printk); static int trace_panic_handler(struct notifier_block *this,
kernel/trace/trace.h +1 -0
@@ -333,6 +333,7 @@ extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...);extern ssize_t trace_seq_to_user (struct trace_seq *s,char __user *ubuf,size_t cnt);extern long ns2usecs (cycle_t nsec); +extern int trace_vprintk (unsigned long ip,const char *fmt,va_list args);extern unsigned long trace_flags;
Signature · 1 line
1.5.6.4
Re: [PATCH 3/7] ftrace: add trace_vprintk()
Quoted 10 lines · Pekka Paalanen
From
5579d3e6471201524697d1cc32fb37f1a4f70f95Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 17:27:05 +0300
Subject: [PATCH] ftrace: addtrace_vprintk()
trace_vprintk()for easier implementation of tracer specific*_printkfunctions. Add check check forno_tracer, and implement__ftrace_printk()as a wrapper.Signed-off-by Pekka Paalanen <[email protected]>
Nice!
-- Steve
Re: [PATCH 3/7] ftrace: add trace_vprintk()
Quoted 13 lines · Steven Rostedt
Quoted 9 lines · Pekka Paalanen
From
5579d3e6471201524697d1cc32fb37f1a4f70f95Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 17:27:05 +0300
Subject: [PATCH] ftrace: addtrace_vprintk()
trace_vprintk()for easier implementation of tracer specific*_printkfunctions. Add check check forno_tracer, and implement__ftrace_printk()as a wrapper.
Quoted 5 lines
Quoted 1 line
Signed-off-by Pekka Paalanen <[email protected]>Nice!
Acked-by Steven Rostedt <[email protected]>
nice - i've picked up Pekka's patches into tip/tracing/ftrace:
f2e1ec3: ftrace: inject markers via trace_marker file 574a7a7: mmiotrace: remove left-over marker cruft
fb87810: mmiotrace: handle TRACE_PRINT entries
eaa4f4e: x86 mmiotrace: implement mmiotrace_printk()
d77a3b8: ftrace: add trace_vprintk()
809fff6: ftrace: move mmiotrace functions out of trace.c
bc94fff: x86 mmiotrace: fix a rare memory leak
and added your ack to all of them. Thanks,
Ingo
PATCH 4/7 x86 mmiotrace: implement mmiotrace_printk().
In reply to Pekka PaalanenQuoted 1 line
From
ca4db25e22b79fd77f4a7c6bb812e605379840a0Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 18:37:46 +0300
Subject: [PATCH] x86 mmiotrace: implement mmiotrace_printk().
Offer mmiotrace users a function to inject markers from inside the kernel. This depends on the trace_vprintk() patch.
--- arch/x86/mm/mmio-mod.c | 19 ++++++++++++++++++- arch/x86/mm/testmmiotrace.c | 4 ++++ include/linux/mmiotrace.h | 17 +++++++++++++++-- kernel/trace/trace_mmiotrace.c | 5 +++++ 4 files changed, 42 insertions(+), 3 deletions(-)
arch/x86/mm/mmio-mod.c +18 -1
@@ -75,7 +75,7 @@ static LIST_HEAD(trace_list); /* struct remap_trace */* and trace_lock. * - Routines depending on is_enabled() must take trace_lock. * - trace_list users must hold trace_lock. -* - is_enabled() guarantees that mmio_trace_record is allowed. +* - is_enabled() guarantees that mmio_trace_{rw,mapping} are allowed. * - pre/post callbacks assume the effect of is_enabled() being true. */
@@ -379,6 +379,23 @@ void mmiotrace_iounmap(volatile void __iomem *addr)iounmap_trace_core (addr); } +int mmiotrace_printk (const char *fmt, ...) +{ +int ret =0 ; +va_list args; +unsigned long flags; +va_start (args, fmt); + +spin_lock_irqsave (&trace_lock, flags); +if (is_enabled ()) + ret =mmio_trace_printk (fmt, args); +spin_unlock_irqrestore (&trace_lock, flags); + +va_end (args); +return ret; +} +EXPORT_SYMBOL (mmiotrace_printk); +static void clear_trace_list (void ) {struct remap_trace *trace;
arch/x86/mm/testmmiotrace.c +4 -0
@@ -3,6 +3,7 @@*/ #include <linux/module.h> #include <linux/io.h> +#include <linux/mmiotrace.h> #define MODULE_NAME "testmmiotrace"
@@ -13,6 +14,7 @@ MODULE_PARM_DESC(mmio_address, "Start address of the mapping of 16 kB.");static void do_write_test (void __iomem *p) {unsigned int i; +mmiotrace_printk ("Write test.\n" );for (i =0 ; i <256 ; i++)iowrite8 (i, p + i);for (i =1024 ; i < (5 *1024 ); i +=2 )
@@ -24,6 +26,7 @@ static void do_write_test(void __iomem *p)static void do_read_test (void __iomem *p) {unsigned int i; +mmiotrace_printk ("Read test.\n" );for (i =0 ; i <256 ; i++)ioread8 (p + i);for (i =1024 ; i < (5 *1024 ); i +=2 )
@@ -39,6 +42,7 @@ static void do_test(void)pr_err (MODULE_NAME ": could not ioremap, aborting.\n" );return ; } +mmiotrace_printk ("ioremap returned %p.\n" , p);do_write_test (p);do_read_test (p);iounmap (p);
include/linux/mmiotrace.h +15 -2
@@ -34,11 +34,15 @@ extern void unregister_kmmio_probe(struct kmmio_probe *p);/* Called from page fault handler. */ extern int kmmio_handler (struct pt_regs *regs,unsigned long addr); -/* Called from ioremap.c */ #ifdef CONFIG_MMIOTRACE +/* Called from ioremap.c */ extern void mmiotrace_ioremap (resource_size_t offset,unsigned long size,void __iomem *addr);extern void mmiotrace_iounmap (volatile void __iomem *addr); + +/* For anyone to insert markers. Remember trailing newline. */ +extern int mmiotrace_printk (const char *fmt, ...) + __attribute__ ((format (printf,1 ,2 )));#else static inline void mmiotrace_ioremap (resource_size_t offset,unsigned long size,void __iomem *addr)
@@ -48,7 +52,15 @@ static inline void mmiotrace_ioremap(resource_size_t offset,static inline void mmiotrace_iounmap (volatile void __iomem *addr) { } -#endif /* CONFIG_MMIOTRACE_HOOKS */ + +static inline int mmiotrace_printk (const char *fmt, ...) + __attribute__ ((format (printf,1 ,0 ))); + +static inline int mmiotrace_printk (const char *fmt, ...) +{ +return 0 ; +} +#endif /* CONFIG_MMIOTRACE */ enum mm_io_opcode {MMIO_READ =0x1 ,/* struct mmiotrace_rw */
@@ -81,5 +93,6 @@ extern void enable_mmiotrace(void);extern void disable_mmiotrace (void );extern void mmio_trace_rw (struct mmiotrace_rw *rw);extern void mmio_trace_mapping (struct mmiotrace_map *map); +extern int mmio_trace_printk (const char *fmt,va_list args);#endif /* MMIOTRACE_H */
kernel/trace/trace_mmiotrace.c +5 -0
@@ -335,3 +335,8 @@ void mmio_trace_mapping(struct mmiotrace_map *map)__trace_mmiotrace_map (tr, data, map);preempt_enable (); } + +int mmio_trace_printk (const char *fmt,va_list args) +{ +return trace_vprintk (0 , fmt, args); +}
Signature · 1 line
1.5.6.4
PATCH 5/7 mmiotrace: handle TRACE_PRINT entries.
In reply to Pekka PaalanenQuoted 1 line
From
6a458e250857907e16cb16799392fccbfd5f0f4aMon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 17 Aug 2008 18:15:13 +0300
Subject: [PATCH] mmiotrace: handle TRACE_PRINT entries.
Also make trace_seq_print_cont() non-static, and add a newline if the seq buffer can't hold all data.
--- kernel/trace/trace.c | 31 +++++++++++-------------------- kernel/trace/trace.h | 19 +++++++++++++++++++ kernel/trace/trace_mmiotrace.c | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 20 deletions(-)
kernel/trace/trace.c +11 -20
@@ -200,23 +200,6 @@ unsigned long nsecs_to_usecs(unsigned long nsecs) }/* -* trace_flag_type is an enumeration that holds different -* states when a trace occurs. These are: -* IRQS_OFF - interrupts were disabled -* NEED_RESCED - reschedule is requested -* HARDIRQ - inside an interrupt handler -* SOFTIRQ - inside a softirq handler -* CONT - multiple entries hold the trace item -*/ -enum trace_flag_type { -TRACE_FLAG_IRQS_OFF =0x01 , -TRACE_FLAG_NEED_RESCHED =0x02 , -TRACE_FLAG_HARDIRQ =0x04 , -TRACE_FLAG_SOFTIRQ =0x08 , -TRACE_FLAG_CONT =0x10 , -}; - -/* * TRACE_ITER_SYM_MASK masks the options in trace_flags that * control the output of kernel symbols. */
@@ -1517,12 +1500,16 @@ lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs,static const char state_to_char[] =TASK_STATE_TO_CHAR_STR ; -static void -trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter) +/* +* The message is supposed to contain an ending newline. +* If the printing stops prematurely, try to add a newline of our own. +*/ +void trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter) {struct trace_array *tr = iter->tr;struct trace_array_cpu *data = tr->data[iter->cpu];struct trace_entry *ent; +bool ok = true; ent =trace_entry_idx (tr, data, iter, iter->cpu);if (!ent || ent->type !=TRACE_CONT ) {
@@ -1531,10 +1518,14 @@ trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter) }do { -trace_seq_printf (s,"%s" , ent->cont.buf); +if (ok) + ok = (trace_seq_printf (s,"%s" , ent->cont.buf) >0 );__trace_iterator_increment (iter, iter->cpu); ent =trace_entry_idx (tr, data, iter, iter->cpu); }while (ent && ent->type ==TRACE_CONT ); + +if (!ok) +trace_seq_putc (s,'\n' ); } static int
kernel/trace/trace.h +19 -0
@@ -72,6 +72,23 @@ struct print_entry { };/* +* trace_flag_type is an enumeration that holds different +* states when a trace occurs. These are: +* IRQS_OFF - interrupts were disabled +* NEED_RESCED - reschedule is requested +* HARDIRQ - inside an interrupt handler +* SOFTIRQ - inside a softirq handler +* CONT - multiple entries hold the trace item +*/ +enum trace_flag_type { +TRACE_FLAG_IRQS_OFF =0x01 , +TRACE_FLAG_NEED_RESCHED =0x02 , +TRACE_FLAG_HARDIRQ =0x04 , +TRACE_FLAG_SOFTIRQ =0x08 , +TRACE_FLAG_CONT =0x10 , +}; + +/* * The trace field - the most basic unit of tracing. This is what * is printed in the end as a single line in the trace output, such as: *
@@ -330,6 +347,8 @@ extern int trace_selftest_startup_sysprof(struct tracer *trace,extern void *head_page (struct trace_array_cpu *data);extern int trace_seq_printf (struct trace_seq *s,const char *fmt, ...); +extern void trace_seq_print_cont (struct trace_seq *s, +struct trace_iterator *iter);extern ssize_t trace_seq_to_user (struct trace_seq *s,char __user *ubuf,size_t cnt);extern long ns2usecs (cycle_t nsec);
kernel/trace/trace_mmiotrace.c +23 -0
@@ -245,6 +245,27 @@ static int mmio_print_map(struct trace_iterator *iter)return 0 ; } +static int mmio_print_mark (struct trace_iterator *iter) +{ +struct trace_entry *entry = iter->ent; +const char *msg = entry->field.print.buf; +struct trace_seq *s = &iter->seq; +unsigned long long t =ns2usecs (entry->field.t); +unsigned long usec_rem =do_div (t,1000000ULL ); +unsigned secs = (unsigned long )t; +int ret; + +/* The trailing newline must be in the message. */ + ret =trace_seq_printf (s,"MARK %lu.%06lu %s" , secs, usec_rem, msg); +if (!ret) +return 0 ; + +if (entry->field.flags &TRACE_FLAG_CONT ) +trace_seq_print_cont (s, iter); + +return 1 ; +} +/* return 0 to abort printing without consuming current entry in pipe mode */ static int mmio_print_line (struct trace_iterator *iter) {
@@ -253,6 +274,8 @@ static int mmio_print_line(struct trace_iterator *iter)return mmio_print_rw (iter);case TRACE_MMIO_MAP :return mmio_print_map (iter); +case TRACE_PRINT : +return mmio_print_mark (iter);default :return 1 ;/* ignore unknown entries */ }
Signature · 1 line
1.5.6.4
Steven Rostedt
maintainerRe: [PATCH 5/7] mmiotrace: handle TRACE_PRINT entries.
Quoted 49 lines · Pekka Paalanen
From
6a458e250857907e16cb16799392fccbfd5f0f4aMon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 17 Aug 2008 18:15:13 +0300
Subject: [PATCH] mmiotrace: handleTRACE_PRINTentries.Also make
trace_seq_print_cont()non-static, and add a newline if the seq buffer can't hold all data.Signed-off-by Pekka Paalanen <[email protected]>--- kernel/trace/trace.c | 31 +++++++++++-------------------- kernel/trace/trace.h | 19 +++++++++++++++++++ kernel/trace/trace_mmiotrace.c | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 20 deletions(-)kernel/trace/trace.c +0
-19@@ -200,23 +200,6 @@ unsigned long nsecs_to_usecs(unsigned long nsecs) }/* -* trace_flag_type is an enumeration that holds different -* states when a trace occurs. These are: -* IRQS_OFF - interrupts were disabled -* NEED_RESCED - reschedule is requested -* HARDIRQ - inside an interrupt handler -* SOFTIRQ - inside a softirq handler -* CONT - multiple entries hold the trace item -*/ -enum trace_flag_type { -TRACE_FLAG_IRQS_OFF =0x01 , -TRACE_FLAG_NEED_RESCHED =0x02 , -TRACE_FLAG_HARDIRQ =0x04 , -TRACE_FLAG_SOFTIRQ =0x08 , -TRACE_FLAG_CONT =0x10 , -}; - -/* * TRACE_ITER_SYM_MASK masks the options in trace_flags that * control the output of kernel symbols. */ @@ -1517,12 +1500,16 @@ lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs,static const char state_to_char[] =TASK_STATE_TO_CHAR_STR ; -static void -trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter)
kernel/trace/trace.c lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs, · line 1512
Quoted 10 lines
kernel/trace/trace.c +6
-0+/* +* The message is supposed to contain an ending newline. +* If the printing stops prematurely, try to add a newline of our own. +*/ +void trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter) {struct trace_array *tr = iter->tr;struct trace_array_cpu *data = tr->data[iter->cpu];struct trace_entry *ent; +bool ok = true;
hmm, since when did the kernel have type bool?
Quoted 8 lines
kernel/trace/trace.c +0
-1ent =trace_entry_idx (tr, data, iter, iter->cpu);if (!ent || ent->type !=TRACE_CONT ) {@@ -1531,10 +1518,14 @@ trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter) } do { - trace_seq_printf(s, "%s", ent->cont.buf);
kernel/trace/trace.c trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter) · line 1530
Quoted 10 lines
kernel/trace/trace.c +5
-0+if (ok) + ok = (trace_seq_printf (s,"%s" , ent->cont.buf) >0 );__trace_iterator_increment (iter, iter->cpu); ent =trace_entry_idx (tr, data, iter, iter->cpu); }while (ent && ent->type ==TRACE_CONT ); + +if (!ok) +trace_seq_putc (s,'\n' ); }
-- Steve
Re: [PATCH 5/7] mmiotrace: handle TRACE_PRINT entries.
Quoted 21 lines · On Tue, 16 Sep 2008 16:11:20 -0400 (EDT) Steven Rostedt <[email protected]>…
Quoted 19 lines · Pekka Paalanen
From
6a458e250857907e16cb16799392fccbfd5f0f4aMon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 17 Aug 2008 18:15:13 +0300
Subject: [PATCH] mmiotrace: handleTRACE_PRINTentries.Also make
trace_seq_print_cont()non-static, and add a newline if the seq buffer can't hold all data.Signed-off-by Pekka Paalanen <[email protected]>--- kernel/trace/trace.c | 31 +++++++++++-------------------- kernel/trace/trace.h | 19 +++++++++++++++++++ kernel/trace/trace_mmiotrace.c | 23 +++++++++++++++++++++++ 3 files changed, 53 insertions(+), 20 deletions(-)kernel/trace/trace.c +0
-0
...
Quoted 4 lines
Quoted 4 lines
kernel/trace/trace.c +0
-0@@ -1517,12 +1500,16 @@ lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs,static const char state_to_char[] =TASK_STATE_TO_CHAR_STR ;
Quoted 14 lines
kernel/trace/trace.c lat_print_timestamp(struct trace_seq *s, unsigned long long abs_usecs, · line 1512
Quoted 12 lines
kernel/trace/trace.c +6
-2-static void -trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter) +/* +* The message is supposed to contain an ending newline. +* If the printing stops prematurely, try to add a newline of our own. +*/ +void trace_seq_print_cont (struct trace_seq *s,struct trace_iterator *iter) {struct trace_array *tr = iter->tr;struct trace_array_cpu *data = tr->data[iter->cpu];struct trace_entry *ent; +bool ok = true;hmm, since when did the kernel have type bool?
Good question. It seems to be used a lot. :-)
commit 6e21828743247270d09a86756a0c11702500dbfb
Author: Richard Knutsson <[email protected]> Date: Sat Sep 30 23:27:11 2006 -0700
[PATCH] Generic boolean
This patch defines:
* a generic boolean-type, named 'bool'
* aliases to 0 and 1, named 'false' and 'true'
Removing colliding definitions of 'bool', 'false' and 'true'.
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
PATCH 6/7 mmiotrace: remove left-over marker cruft.
In reply to Pekka PaalanenQuoted 1 line
From
abd3cadc69143804cf4b0cf1d6fcadda5daad903Mon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 20:50:55 +0300
Subject: [PATCH] mmiotrace: remove left-over marker cruft.
--- arch/x86/mm/mmio-mod.c | 64 --------------------------------------------- include/linux/mmiotrace.h | 3 +- 2 files changed, 1 insertions(+), 66 deletions(-)
arch/x86/mm/mmio-mod.c +0 -64
@@ -56,13 +56,6 @@ struct remap_trace { static DEFINE_PER_CPU(struct trap_reason, pf_reason); static DEFINE_PER_CPU(struct mmiotrace_rw, cpu_trace); -#if 0 /* XXX: no way gather this info anymore */ -/* Access to this is not per-cpu. */ -static DEFINE_PER_CPU(atomic_t, dropped); -#endif - -static struct dentry *marker_file; -static DEFINE_MUTEX (mmiotrace_mutex);static DEFINE_SPINLOCK (trace_lock);static atomic_t mmiotrace_enabled;
@@ -97,44 +90,6 @@ static bool is_enabled(void)return atomic_read (&mmiotrace_enabled); } -#if 0 /* XXX: needs rewrite */ -/* -* Write callback for the debugfs entry: -* Read a marker and write it to the mmio trace log -*/ -static ssize_t write_marker (struct file *file,const char __user *buffer, -size_t count,loff_t *ppos) -{ -char *event =NULL ; -struct mm_io_header *headp; -ssize_t len = (count >65535 ) ?65535 : count; - - event =kzalloc (sizeof (*headp) + len,GFP_KERNEL ); -if (!event) -return -ENOMEM ; - - headp = (struct mm_io_header *)event; - headp->type =MMIO_MAGIC | (MMIO_MARKER <<MMIO_OPCODE_SHIFT ); - headp->data_len = len; - -if (copy_from_user (event +sizeof (*headp), buffer, len)) { -kfree (event); -return -EFAULT ; - } - -spin_lock_irq (&trace_lock); -#if 0 /* XXX: convert this to use tracing */ -if (is_enabled ()) -relay_write (chan, event,sizeof (*headp) + len); - else -#endif - len = -EINVAL ; -spin_unlock_irq (&trace_lock); -kfree (event); -return len; -} -#endif -static void print_pte (unsigned long address) {unsigned int level;
@@ -481,26 +436,12 @@ static void leave_uniprocessor(void) }#endif -#if 0 /* XXX: out of order */ -static struct file_operations fops_marker = { - .owner =THIS_MODULE , - .write = write_marker -}; -#endif -void enable_mmiotrace (void ) {mutex_lock (&mmiotrace_mutex);if (is_enabled ()) goto out; -#if 0 /* XXX: tracing does not support text entries */ - marker_file =debugfs_create_file ("marker" ,0660 , dir,NULL , - &fops_marker); -if (!marker_file) -pr_err (NAME "marker file creation failed.\n" ); -#endif -if (nommiotrace)pr_info (NAME "MMIO tracing disabled.\n" );enter_uniprocessor ();
@@ -525,11 +466,6 @@ void disable_mmiotrace(void)clear_trace_list ();/* guarantees: no more kmmio callbacks */ leave_uniprocessor (); -if (marker_file) { -debugfs_remove (marker_file); - marker_file =NULL ; - } -pr_info (NAME "disabled.\n" ); out:mutex_unlock (&mmiotrace_mutex);
include/linux/mmiotrace.h +1 -2
@@ -67,8 +67,7 @@ enum mm_io_opcode {MMIO_WRITE =0x2 ,/* struct mmiotrace_rw */ MMIO_PROBE =0x3 ,/* struct mmiotrace_map */ MMIO_UNPROBE =0x4 ,/* struct mmiotrace_map */ -MMIO_MARKER =0x5 ,/* raw char data */ - MMIO_UNKNOWN_OP = 0x6, /* struct mmiotrace_rw */ + MMIO_UNKNOWN_OP = 0x5, /* struct mmiotrace_rw */ }; struct mmiotrace_rw {
Signature · 1 line
1.5.6.4
PATCH 7/7 ftrace: inject markers via trace_marker file.
In reply to Pekka PaalanenQuoted 1 line
From
9be308e4ea3af69cebb29930757d6457f762866dMon Sep 17 00:00:00 2001
From: Pekka Paalanen <[email protected]>
Date: Sun, 14 Sep 2008 22:34:35 +0300
Subject: [PATCH] ftrace: inject markers via trace_marker file.
MIME-Version: 1.0
Content-Type: text/plain; charset=utf-8
Content-Transfer-Encoding: 8bit
Allow a user to inject a marker (TRACE_PRINT entry) into the trace ring buffer. The related file operations are derived from code by Frédéric Weisbecker <[email protected]>.
--- Documentation/tracers/mmiotrace.txt | 5 +- kernel/trace/trace.c | 76 ++++++++++++++++++++++++++++++++-- kernel/trace/trace.h | 4 ++ 3 files changed, 77 insertions(+), 8 deletions(-)
Documentation/tracers/mmiotrace.txt +2 -3
@@ -36,7 +36,7 @@ $ mount -t debugfs debugfs /debug $ echo mmiotrace > /debug/tracing/current_tracer $ cat /debug/tracing/trace_pipe > mydump.txt & Start X or whatever. -$ echo "X is up" > /debug/tracing/marker +$ echo "X is up" > /debug/tracing/trace_marker $ echo none > /debug/tracing/current_tracer Check for lost events.
@@ -59,9 +59,8 @@ The 'cat' process should stay running (sleeping) in the background. Load the driver you want to trace and use it. Mmiotrace will only catch MMIO accesses to areas that are ioremapped while mmiotrace is active. -[Unimplemented feature:] During tracing you can place comments (markers) into the trace by -$ echo "X is up" > /debug/tracing/marker +$ echo "X is up" > /debug/tracing/trace_marker This makes it easier to see which part of the (huge) trace corresponds to which action. It is recommended to place descriptive markers about what you do.
kernel/trace/trace.c +71 -5
100 lines not on this page · raw message
kernel/trace/trace.h +4 -0
@@ -124,6 +124,10 @@ struct trace_entry { };#define TRACE_ENTRY_SIZE sizeof(struct trace_entry) +#define TRACE_BUF_SIZE 1024 +#define TRACE_PRINT_BUF_SIZE \ + (sizeof(struct trace_field) - offsetof(struct trace_field, print.buf)) +#define TRACE_CONT_BUF_SIZE sizeof(struct trace_field)/* * The CPU trace array - it consists of thousands of trace entries
Signature · 1 line
1.5.6.4
Re: Tracing/ftrace: trouble with trace_entries and trace_pipe
In reply to Pekka Paalanen2008/9/15 Pekka Paalanen <[email protected]>:
Quoted 40 lines
My other problem is with
trace_pipe. It is again making 'cat' quit too early. The condition triggered isif (!tracer_enabled && iter->pos) { in tracing_read_pipe(), and it is followed by triggering /* stop when tracing is finished */ if (trace_empty(iter)) {and then sret=0, so read returns 0 and 'cat' exits.
Now, I am trying my mmiotrace marker patches, but as far as I can tell, nothing I modified is the reason for this. I didn't yet explicitly test for it, though. I'll send these patches after I hear from Frederic.
The cat-quit problem is not a constant state. After boot, I could play with my markers and testmmiotrace without cat quitting. Then something happens, and cat starts the quitting behaviour, and won't get to normal by disabling and enabling mmiotrace.
I have a couple of wild guesses of what might be related:
- ring buffer wrap-around
- ring buffer overflow (at first try I hit these, the second try after putting debug-pr_info's in place I don't hit this)
- ring buffer resize (after playing withtrace_entries, cat-quit problem was present, though it might have been present before)After viewing the git history, I have some more guesses, mainly related to setting
tracer_enabledto 0.
- commit2b1bce1787700768cbc87c8509851c6f49d252dc
I don't see wheretracer_enabledwould be set to 1, when mmiotrace is enabled. It used to default to 1 and mmiotrace was happy.
-__tracing_open()sets it to 0 (not called for the pipe)
-tracing_release()sets it to 1
-tracing_ctrl_write()toggles it
-tracing_read_pipe()tests it
-tracer_alloc_buffers()uses it
And other tracers seem to use it a lot.Mmiotrace does use the
tracer::ctrl_updatehook, and allow/disallow calls to __trace_mmiotrace_{rw,map}() via enabling/disabling the whole mmiotrace core. Is this not enough, or is it inappropriate?
Quoted 8 lines
It seems
tracer_enabledis used by the trace framework itself to enable/disable... what? Hmm, maybe nothing I care about.Should mmiotrace simply do
tracer_enabled = 1;in
mmio_trace_init()?Should mmiotrace test
tracer_enabled, and if so, when?
As I said to you, I met the same bug of this early quit of the pipe. But I should give here more details.
This bug occurs with -tip (a version pulled 2 days ago so trace.c didn't change).
I never saw it with other tracers than mmiotrace. I had no problem with sched_switch or function tracer.
It happened when I was writing the tracer marker. So I'm not sure if the origin is here. If I'm not wrong it happened whithout adding mark messages too.
Can you tell me if your pipe quits when you add a mark or if this bug occurs on other cases too?
I will try to reproduce the bug this evening.
Steven,
is there a logic behind trace_seq_print_cont() printing the terminating newline only, when there actually is no TRACE_CONT entry?
Hmm, wait a minute, I don't understand how this thing works at all.
Let's take for instance print_lat_fmt() which is the first user of trace_seq_print_cont(). Now, print_lat_fmt() does
struct trace_entry *entry = iter->ent;
and uses 'entry'. Let's assume it is of type TRACE_PRINT. It does
case TRACE_PRINT: seq_print_ip_sym(s, field->print.ip, sym_flags); trace_seq_printf(s, ": %s", field->print.buf); if (field->flags & TRACE_FLAG_CONT) trace_seq_print_cont(s, iter); break;
Ok, it prints the beginning of the message, and if there should be continuation blocks, it calls trace_seq_print_cont(), defined as follows:
static voidtrace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
{
struct trace_array *tr = iter->tr;
struct trace_array_cpu *data = tr->data[iter->cpu];
struct trace_entry *ent;
ent = trace_entry_idx(tr, data, iter, iter->cpu);
if (!ent || ent->type != TRACE_CONT) {
trace_seq_putc(s, '\n');
return;
}
do {
trace_seq_printf(s, "%s", ent->cont.buf);
__trace_iterator_increment(iter, iter->cpu);
ent = trace_entry_idx(tr, data, iter, iter->cpu);
} while (ent && ent->type == TRACE_CONT);
}Here it uses trace_entry_idx() to get 'ent'. What's the difference to iter->ent? I don't understand how trace_entry_idx() works, but looking at how it is used, it must return the pointer to the *next* entry in the ring buffer. So I don't understand the name of the function, and I don't see a call to __trace_iterator_increment(), which is confusing.
If contrary to the assumption, 'ent' is not a continuation, it prints the terminating newline. This is an exceptional case, as the original entry was marked as having continuation entries.
The normal case then is to execute the do-while, until it hits a non-continuation entry. Here it does *not* print the terminating newline.
Steven, could you explain what is going on here?
Thanks.
Quoted 9 lines · On Thu, 4 Sep 2008 20:30:58 +0300 Pekka Paalanen <[email protected]> wrote:
b) have a customisable
trace_seq_print_cont()I think I'd favour b). When I tried to use
trace_seq_print_cont(), I found it difficult to control the printing of \n at the end of message. So I would implement my own routine to handle also whattrace_seq_print_cont()does, filtering the text while copying it to structtrace_seq. I'm not sure where this function should live. It could be useful to all tracers, that want "one line per marker entry" style output, so it could live intrace.c.
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/
Steven Rostedt
maintainerQuoted 4 lines · Pekka Paalanen
Steven,
is there a logic behind
trace_seq_print_cont()printing the terminating newline only, when there actually is noTRACE_CONTentry?
Actually, that case is more of an anomaly than the correct. It means that somehow the print statement wanted to continue, but did not. This means that the print statement probably did not finish the line, and that we should do a newline to make sure the next entry starts on a new line.
Quoted 2 lines
Hmm, wait a minute, I don't understand how this thing works at all.
Heh, I guess I need to add more comments :-/
Quoted 5 lines
Let's take for instance
print_lat_fmt()which is the first user oftrace_seq_print_cont(). Now,print_lat_fmt()doesstruct trace_entry *entry = iter->ent;
iter->ent is the start of the entry to print. It is not necessarily the current entry in the iteration buffer.
Quoted 25 lines
and uses 'entry'. Let's assume it is of type
TRACE_PRINT. It doescase TRACE_PRINT: seq_print_ip_sym(s, field->print.ip, sym_flags); trace_seq_printf(s, ": %s", field->print.buf); if (field->flags & TRACE_FLAG_CONT) trace_seq_print_cont(s, iter); break;Ok, it prints the beginning of the message, and if there should be continuation blocks, it calls
trace_seq_print_cont(), defined as follows:static void
trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter){ struct trace_array *tr = iter->tr; struct trace_array_cpu *data = tr->data[iter->cpu]; struct trace_entry *ent; ent = trace_entry_idx(tr, data, iter, iter->cpu); if (!ent || ent->type != TRACE_CONT) { trace_seq_putc(s, '\n'); return;
Quoted 8 lines
}
do {
trace_seq_printf(s, "%s", ent->cont.buf);
__trace_iterator_increment(iter, iter->cpu);
ent = trace_entry_idx(tr, data, iter, iter->cpu);
} while (ent && ent->type == TRACE_CONT);
}Because we do a merge sort of the entries in each CPU buffer, after we get the next entry to print, we increment that iteration buffer. This means that trace_entry_idx() will return the next entry field after we got the iter->ent. This is also why we use iter->ent instead of just calling trace_entry_idx. This keeps the merge sort simpler.
Quoted 6 lines
Here it uses
trace_entry_idx()to get 'ent'. What's the difference toiter->ent? I don't understand howtrace_entry_idx()works, but looking at how it is used, it must return the pointer to the *next* entry in the ring buffer. So I don't understand the name of the function, and I don't see a call to__trace_iterator_increment(), which is confusing.
iter->ent is the entry to be used in the "show" function. When we found that entry, we incremented the buffer to get it ready for the next merge sort.
When we get to show, iter->ent is the entry to print, and if we use iter_entry_idx() that will point to the next entry in that buffer that will be used next time. I also did this to make it easier for the latency format be able to calculate the notations (like the '!').
Quoted 4 lines
If contrary to the assumption, 'ent' is not a continuation, it prints the terminating newline. This is an exceptional case, as the original entry was marked as having continuation entries.
Right, this is somehow an entry was flagged as continue, but it did not. It is probably a bug in the code, and instead of writing a strange format, where the next entry continued on the same line, I chose to let the entry go onto the next line.
Quoted 3 lines
The normal case then is to execute the do-while, until it hits a non-continuation entry. Here it does *not* print the terminating newline.
Correct. The reason is that the ftrace_printk() call should have contained its own new line. I could also add a check (and probably will) to see if the printk did end with a newline, and add one if it did not.
Quoted 2 lines
Steven, could you explain what is going on here?
Just did ;-)
Hope it helps,
-- Steve
Quoted 5 lines · On Sun, 7 Sep 2008 13:29:40 -0400 (EDT) Steven Rostedt <[email protected]>…
Quoted 2 lines · Pekka Paalanen
Steven,
Quoted 8 lines
Quoted 2 lines
is there a logic behind
trace_seq_print_cont()printing the terminating newline only, when there actually is noTRACE_CONTentry?Actually, that case is more of an anomaly than the correct. It means that somehow the print statement wanted to continue, but did not. This means that the print statement probably did not finish the line, and that we should do a newline to make sure the next entry starts on a new line.
Oh, I never thought it from that point of view.
Quoted 20 lines
Quoted 11 lines
static void
trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter){ struct trace_array *tr = iter->tr; struct trace_array_cpu *data = tr->data[iter->cpu]; struct trace_entry *ent; ent = trace_entry_idx(tr, data, iter, iter->cpu); if (!ent || ent->type != TRACE_CONT) { trace_seq_putc(s, '\n'); return;Quoted 8 lines
} do { trace_seq_printf(s, "%s", ent->cont.buf); __trace_iterator_increment(iter, iter->cpu); ent = trace_entry_idx(tr, data, iter, iter->cpu); } while (ent && ent->type == TRACE_CONT); }
Quoted 5 lines
Because we do a merge sort of the entries in each CPU buffer, after we get the next entry to print, we increment that iteration buffer. This means that
trace_entry_idx()will return the next entry field after we got theiter->ent. This is also why we useiter->entinstead of just callingtrace_entry_idx. This keeps the merge sort simpler.
Yes, I forgot the per-cpu buffers. When merging you want the first one wrt. timestamp, and when continuing you want the next on that cpu's buffer.
Quoted 24 lines
Quoted 5 lines
Here it uses
trace_entry_idx()to get 'ent'. What's the difference toiter->ent? I don't understand howtrace_entry_idx()works, but looking at how it is used, it must return the pointer to the *next* entry in the ring buffer. So I don't understand the name of the function, and I don't see a call to__trace_iterator_increment(), which is confusing.
iter->entis the entry to be used in the "show" function. When we found that entry, we incremented the buffer to get it ready for the next merge sort.When we get to show,
iter->entis the entry to print, and if we useiter_entry_idx()that will point to the next entry in that buffer that will be used next time. I also did this to make it easier for the latency format be able to calculate the notations (like the '!').Quoted 3 lines
If contrary to the assumption, 'ent' is not a continuation, it prints the terminating newline. This is an exceptional case, as the original entry was marked as having continuation entries.
Right, this is somehow an entry was flagged as continue, but it did not. It is probably a bug in the code, and instead of writing a strange format, where the next entry continued on the same line, I chose to let the entry go onto the next line.
Quoted 6 lines
Quoted 2 lines
The normal case then is to execute the do-while, until it hits a non-continuation entry. Here it does *not* print the terminating newline.
Correct. The reason is that the
ftrace_printk()call should have contained its own new line. I could also add a check (and probably will) to see if the printk did end with a newline, and add one if it did not.
My first idea was to filter out all newlines from messages, making a message a single line, and then force a newline, but now I realize that would be an exception to the printk convention. Maybe I should just start a new line in the output, when I get a newline :-) Although that probably means my version of trace_seq_print_cont() must live in trace.c, which IMHO is over-crowded already.
But then there's a small chance the whole output of a single TRACE_PRINT entry might not fit into one trace_seq ever, since each line in mmiotrace has a prologue. Oh well, can't win always, I'll just drop what doesn't fit into output.
Hmm, it already does that, doesn't it, if the output does not fit into trace_seq buffer. There might be a corner case...
Quoted 5 lines
Quoted 1 line
Steven, could you explain what is going on here?
Just did ;-)
Hope it helps,
Oh yes, thank you very much :-)
btw. How do you feel about moving the #ifdef CONFIG_MMIOTRACE functions from trace.c to trace_mmiotrace.c and unstatifying all the functions they need? Seems some of them are inline, and the spinlock stuff just looks so... raw :-)
Signature · 2 lines
Pekka Paalanen http://www.iki.fi/pq/