tracing: Add trace_clock=<clock> kernel parameter

Being able to change the trace clock at boot can be advantageous if
you need a better source of when things happen across CPUs. The default
trace clock is the fastest, but it uses local clocks which may not be
synced across CPUs and it does not let you know when events took place
with respect to events on other CPUs.

The global trace clock can help in this case, and if you do not care
about timings, the counter "clock" is the best, as that is just a  simple
atomic counter that is incremented for every event.

Usage is to add "trace_clock=counter" on the kernel command line. You
can replace counter with "global" or any of the clocks listed in
/sys/kernel/debug/tracing/trace_clock

Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Thomas Gleixner <tglx@linutronix.de>
Appreciated-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
Steven Rostedt 2014-02-10 23:38:46 -05:00
parent 43fe98913c
commit e1e232ca6b

View File

@ -181,6 +181,17 @@ static int __init set_trace_boot_options(char *str)
} }
__setup("trace_options=", set_trace_boot_options); __setup("trace_options=", set_trace_boot_options);
static char trace_boot_clock_buf[MAX_TRACER_SIZE] __initdata;
static char *trace_boot_clock __initdata;
static int __init set_trace_boot_clock(char *str)
{
strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE);
trace_boot_clock = trace_boot_clock_buf;
return 0;
}
__setup("trace_clock=", set_trace_boot_clock);
unsigned long long ns2usecs(cycle_t nsec) unsigned long long ns2usecs(cycle_t nsec)
{ {
@ -4746,25 +4757,10 @@ static int tracing_clock_show(struct seq_file *m, void *v)
return 0; return 0;
} }
static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, static int tracing_set_clock(struct trace_array *tr, const char *clockstr)
size_t cnt, loff_t *fpos)
{ {
struct seq_file *m = filp->private_data;
struct trace_array *tr = m->private;
char buf[64];
const char *clockstr;
int i; int i;
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(&buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = 0;
clockstr = strstrip(buf);
for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) { for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) {
if (strcmp(trace_clocks[i].name, clockstr) == 0) if (strcmp(trace_clocks[i].name, clockstr) == 0)
break; break;
@ -4792,6 +4788,32 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
mutex_unlock(&trace_types_lock); mutex_unlock(&trace_types_lock);
return 0;
}
static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
size_t cnt, loff_t *fpos)
{
struct seq_file *m = filp->private_data;
struct trace_array *tr = m->private;
char buf[64];
const char *clockstr;
int ret;
if (cnt >= sizeof(buf))
return -EINVAL;
if (copy_from_user(&buf, ubuf, cnt))
return -EFAULT;
buf[cnt] = 0;
clockstr = strstrip(buf);
ret = tracing_set_clock(tr, clockstr);
if (ret)
return ret;
*fpos += cnt; *fpos += cnt;
return cnt; return cnt;
@ -6574,6 +6596,13 @@ __init static int tracer_alloc_buffers(void)
trace_init_cmdlines(); trace_init_cmdlines();
if (trace_boot_clock) {
ret = tracing_set_clock(&global_trace, trace_boot_clock);
if (ret < 0)
pr_warning("Trace clock %s not defined, going back to default\n",
trace_boot_clock);
}
/* /*
* register_tracer() might reference current_trace, so it * register_tracer() might reference current_trace, so it
* needs to be set before we register anything. This is * needs to be set before we register anything. This is