Merge branches 'tracing/profiling', 'tracing/options' and 'tracing/urgent' into tracing/core
This commit is contained in:
@@ -43,6 +43,20 @@
|
||||
unsigned long __read_mostly tracing_max_latency = (cycle_t)ULONG_MAX;
|
||||
unsigned long __read_mostly tracing_thresh;
|
||||
|
||||
/* For tracers that don't implement custom flags */
|
||||
static struct tracer_opt dummy_tracer_opt[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
static struct tracer_flags dummy_tracer_flags = {
|
||||
.val = 0,
|
||||
.opts = dummy_tracer_opt
|
||||
};
|
||||
|
||||
static int dummy_set_flag(u32 old_flags, u32 bit, int set)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Kill all tracing for good (never come back).
|
||||
@@ -537,6 +551,14 @@ int register_tracer(struct tracer *type)
|
||||
}
|
||||
}
|
||||
|
||||
if (!type->set_flag)
|
||||
type->set_flag = &dummy_set_flag;
|
||||
if (!type->flags)
|
||||
type->flags = &dummy_tracer_flags;
|
||||
else
|
||||
if (!type->flags->opts)
|
||||
type->flags->opts = dummy_tracer_opt;
|
||||
|
||||
#ifdef CONFIG_FTRACE_STARTUP_TEST
|
||||
if (type->selftest) {
|
||||
struct tracer *saved_tracer = current_trace;
|
||||
@@ -840,6 +862,7 @@ static void __trace_function_return(struct trace_array *tr,
|
||||
entry->parent_ip = trace->ret;
|
||||
entry->rettime = trace->rettime;
|
||||
entry->calltime = trace->calltime;
|
||||
entry->overrun = trace->overrun;
|
||||
ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
|
||||
}
|
||||
#endif
|
||||
@@ -2436,10 +2459,13 @@ static ssize_t
|
||||
tracing_trace_options_read(struct file *filp, char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
{
|
||||
int i;
|
||||
char *buf;
|
||||
int r = 0;
|
||||
int len = 0;
|
||||
int i;
|
||||
u32 tracer_flags = current_trace->flags->val;
|
||||
struct tracer_opt *trace_opts = current_trace->flags->opts;
|
||||
|
||||
|
||||
/* calulate max size */
|
||||
for (i = 0; trace_options[i]; i++) {
|
||||
@@ -2447,6 +2473,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
|
||||
len += 3; /* "no" and space */
|
||||
}
|
||||
|
||||
/*
|
||||
* Increase the size with names of options specific
|
||||
* of the current tracer.
|
||||
*/
|
||||
for (i = 0; trace_opts[i].name; i++) {
|
||||
len += strlen(trace_opts[i].name);
|
||||
len += 3; /* "no" and space */
|
||||
}
|
||||
|
||||
/* +2 for \n and \0 */
|
||||
buf = kmalloc(len + 2, GFP_KERNEL);
|
||||
if (!buf)
|
||||
@@ -2459,6 +2494,15 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
|
||||
r += sprintf(buf + r, "no%s ", trace_options[i]);
|
||||
}
|
||||
|
||||
for (i = 0; trace_opts[i].name; i++) {
|
||||
if (tracer_flags & trace_opts[i].bit)
|
||||
r += sprintf(buf + r, "%s ",
|
||||
trace_opts[i].name);
|
||||
else
|
||||
r += sprintf(buf + r, "no%s ",
|
||||
trace_opts[i].name);
|
||||
}
|
||||
|
||||
r += sprintf(buf + r, "\n");
|
||||
WARN_ON(r >= len + 2);
|
||||
|
||||
@@ -2469,6 +2513,40 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Try to assign a tracer specific option */
|
||||
static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
|
||||
{
|
||||
struct tracer_flags *trace_flags = trace->flags;
|
||||
struct tracer_opt *opts = NULL;
|
||||
int ret = 0, i = 0;
|
||||
int len;
|
||||
|
||||
for (i = 0; trace_flags->opts[i].name; i++) {
|
||||
opts = &trace_flags->opts[i];
|
||||
len = strlen(opts->name);
|
||||
|
||||
if (strncmp(cmp, opts->name, len) == 0) {
|
||||
ret = trace->set_flag(trace_flags->val,
|
||||
opts->bit, !neg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Not found */
|
||||
if (!trace_flags->opts[i].name)
|
||||
return -EINVAL;
|
||||
|
||||
/* Refused to handle */
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (neg)
|
||||
trace_flags->val &= ~opts->bit;
|
||||
else
|
||||
trace_flags->val |= opts->bit;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
||||
size_t cnt, loff_t *ppos)
|
||||
@@ -2476,6 +2554,7 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
||||
char buf[64];
|
||||
char *cmp = buf;
|
||||
int neg = 0;
|
||||
int ret;
|
||||
int i;
|
||||
|
||||
if (cnt >= sizeof(buf))
|
||||
@@ -2502,11 +2581,13 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* If no option could be set, return an error:
|
||||
*/
|
||||
if (!trace_options[i])
|
||||
return -EINVAL;
|
||||
|
||||
/* If no option could be set, test the specific tracer options */
|
||||
if (!trace_options[i]) {
|
||||
ret = set_tracer_option(current_trace, cmp, neg);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
filp->f_pos += cnt;
|
||||
|
||||
|
@@ -60,6 +60,7 @@ struct ftrace_ret_entry {
|
||||
unsigned long parent_ip;
|
||||
unsigned long long calltime;
|
||||
unsigned long long rettime;
|
||||
unsigned long overrun;
|
||||
};
|
||||
extern struct tracer boot_tracer;
|
||||
|
||||
@@ -259,6 +260,29 @@ enum print_line_t {
|
||||
TRACE_TYPE_UNHANDLED = 2 /* Relay to other output functions */
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* An option specific to a tracer. This is a boolean value.
|
||||
* The bit is the bit index that sets its value on the
|
||||
* flags value in struct tracer_flags.
|
||||
*/
|
||||
struct tracer_opt {
|
||||
const char *name; /* Will appear on the trace_options file */
|
||||
u32 bit; /* Mask assigned in val field in tracer_flags */
|
||||
};
|
||||
|
||||
/*
|
||||
* The set of specific options for a tracer. Your tracer
|
||||
* have to set the initial value of the flags val.
|
||||
*/
|
||||
struct tracer_flags {
|
||||
u32 val;
|
||||
struct tracer_opt *opts;
|
||||
};
|
||||
|
||||
/* Makes more easy to define a tracer opt */
|
||||
#define TRACER_OPT(s, b) .name = #s, .bit = b
|
||||
|
||||
/*
|
||||
* A specific tracer, represented by methods that operate on a trace array:
|
||||
*/
|
||||
@@ -280,8 +304,11 @@ struct tracer {
|
||||
struct trace_array *tr);
|
||||
#endif
|
||||
enum print_line_t (*print_line)(struct trace_iterator *iter);
|
||||
/* If you handled the flag setting, return 0 */
|
||||
int (*set_flag)(u32 old_flags, u32 bit, int set);
|
||||
struct tracer *next;
|
||||
int print_max;
|
||||
struct tracer_flags *flags;
|
||||
};
|
||||
|
||||
struct trace_seq {
|
||||
|
@@ -14,6 +14,19 @@
|
||||
#include "trace.h"
|
||||
|
||||
|
||||
#define TRACE_RETURN_PRINT_OVERRUN 0x1
|
||||
static struct tracer_opt trace_opts[] = {
|
||||
/* Display overruns or not */
|
||||
{ TRACER_OPT(overrun, TRACE_RETURN_PRINT_OVERRUN) },
|
||||
{ } /* Empty entry */
|
||||
};
|
||||
|
||||
static struct tracer_flags tracer_flags = {
|
||||
.val = 0, /* Don't display overruns by default */
|
||||
.opts = trace_opts
|
||||
};
|
||||
|
||||
|
||||
static int return_trace_init(struct trace_array *tr)
|
||||
{
|
||||
int cpu;
|
||||
@@ -42,26 +55,39 @@ print_return_function(struct trace_iterator *iter)
|
||||
ret = trace_seq_printf(s, "%pF -> ", (void *)field->parent_ip);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
ret = seq_print_ip_sym(s, field->ip,
|
||||
trace_flags & TRACE_ITER_SYM_MASK);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
ret = trace_seq_printf(s, " (%llu ns)\n",
|
||||
|
||||
ret = trace_seq_printf(s, " (%llu ns)",
|
||||
field->rettime - field->calltime);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
else
|
||||
return TRACE_TYPE_HANDLED;
|
||||
|
||||
if (tracer_flags.val & TRACE_RETURN_PRINT_OVERRUN) {
|
||||
ret = trace_seq_printf(s, " (Overruns: %lu)",
|
||||
field->overrun);
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
}
|
||||
|
||||
ret = trace_seq_printf(s, "\n");
|
||||
if (!ret)
|
||||
return TRACE_TYPE_PARTIAL_LINE;
|
||||
|
||||
return TRACE_TYPE_HANDLED;
|
||||
}
|
||||
return TRACE_TYPE_UNHANDLED;
|
||||
}
|
||||
|
||||
static struct tracer return_trace __read_mostly =
|
||||
{
|
||||
static struct tracer return_trace __read_mostly = {
|
||||
.name = "return",
|
||||
.init = return_trace_init,
|
||||
.reset = return_trace_reset,
|
||||
.print_line = print_return_function
|
||||
.print_line = print_return_function,
|
||||
.flags = &tracer_flags,
|
||||
};
|
||||
|
||||
static __init int init_return_trace(void)
|
||||
|
@@ -12,6 +12,27 @@
|
||||
|
||||
#include "trace.h"
|
||||
|
||||
/* Our two options */
|
||||
enum {
|
||||
TRACE_NOP_OPT_ACCEPT = 0x1,
|
||||
TRACE_NOP_OPT_REFUSE = 0x2
|
||||
};
|
||||
|
||||
/* Options for the tracer (see trace_options file) */
|
||||
static struct tracer_opt nop_opts[] = {
|
||||
/* Option that will be accepted by set_flag callback */
|
||||
{ TRACER_OPT(test_nop_accept, TRACE_NOP_OPT_ACCEPT) },
|
||||
/* Option that will be refused by set_flag callback */
|
||||
{ TRACER_OPT(test_nop_refuse, TRACE_NOP_OPT_REFUSE) },
|
||||
{ } /* Always set a last empty entry */
|
||||
};
|
||||
|
||||
static struct tracer_flags nop_flags = {
|
||||
/* You can check your flags value here when you want. */
|
||||
.val = 0, /* By default: all flags disabled */
|
||||
.opts = nop_opts
|
||||
};
|
||||
|
||||
static struct trace_array *ctx_trace;
|
||||
|
||||
static void start_nop_trace(struct trace_array *tr)
|
||||
@@ -41,6 +62,35 @@ static void nop_trace_reset(struct trace_array *tr)
|
||||
stop_nop_trace(tr);
|
||||
}
|
||||
|
||||
/* It only serves as a signal handler and a callback to
|
||||
* accept or refuse tthe setting of a flag.
|
||||
* If you don't implement it, then the flag setting will be
|
||||
* automatically accepted.
|
||||
*/
|
||||
static int nop_set_flag(u32 old_flags, u32 bit, int set)
|
||||
{
|
||||
/*
|
||||
* Note that you don't need to update nop_flags.val yourself.
|
||||
* The tracing Api will do it automatically if you return 0
|
||||
*/
|
||||
if (bit == TRACE_NOP_OPT_ACCEPT) {
|
||||
printk(KERN_DEBUG "nop_test_accept flag set to %d: we accept."
|
||||
" Now cat trace_options to see the result\n",
|
||||
set);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (bit == TRACE_NOP_OPT_REFUSE) {
|
||||
printk(KERN_DEBUG "nop_test_refuse flag set to %d: we refuse."
|
||||
"Now cat trace_options to see the result\n",
|
||||
set);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
struct tracer nop_trace __read_mostly =
|
||||
{
|
||||
.name = "nop",
|
||||
@@ -49,5 +99,7 @@ struct tracer nop_trace __read_mostly =
|
||||
#ifdef CONFIG_FTRACE_SELFTEST
|
||||
.selftest = trace_selftest_startup_nop,
|
||||
#endif
|
||||
.flags = &nop_flags,
|
||||
.set_flag = nop_set_flag
|
||||
};
|
||||
|
||||
|
@@ -180,11 +180,16 @@ static struct file_operations stack_max_size_fops = {
|
||||
static void *
|
||||
t_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
{
|
||||
long i = (long)m->private;
|
||||
long i;
|
||||
|
||||
(*pos)++;
|
||||
|
||||
i++;
|
||||
if (v == SEQ_START_TOKEN)
|
||||
i = 0;
|
||||
else {
|
||||
i = *(long *)v;
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i >= max_stack_trace.nr_entries ||
|
||||
stack_dump_trace[i] == ULONG_MAX)
|
||||
@@ -197,12 +202,15 @@ t_next(struct seq_file *m, void *v, loff_t *pos)
|
||||
|
||||
static void *t_start(struct seq_file *m, loff_t *pos)
|
||||
{
|
||||
void *t = &m->private;
|
||||
void *t = SEQ_START_TOKEN;
|
||||
loff_t l = 0;
|
||||
|
||||
local_irq_disable();
|
||||
__raw_spin_lock(&max_stack_lock);
|
||||
|
||||
if (*pos == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
for (; t && l < *pos; t = t_next(m, t, &l))
|
||||
;
|
||||
|
||||
@@ -231,10 +239,10 @@ static int trace_lookup_stack(struct seq_file *m, long i)
|
||||
|
||||
static int t_show(struct seq_file *m, void *v)
|
||||
{
|
||||
long i = *(long *)v;
|
||||
long i;
|
||||
int size;
|
||||
|
||||
if (i < 0) {
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
seq_printf(m, " Depth Size Location"
|
||||
" (%d entries)\n"
|
||||
" ----- ---- --------\n",
|
||||
@@ -242,6 +250,8 @@ static int t_show(struct seq_file *m, void *v)
|
||||
return 0;
|
||||
}
|
||||
|
||||
i = *(long *)v;
|
||||
|
||||
if (i >= max_stack_trace.nr_entries ||
|
||||
stack_dump_trace[i] == ULONG_MAX)
|
||||
return 0;
|
||||
@@ -271,10 +281,6 @@ static int stack_trace_open(struct inode *inode, struct file *file)
|
||||
int ret;
|
||||
|
||||
ret = seq_open(file, &stack_trace_seq_ops);
|
||||
if (!ret) {
|
||||
struct seq_file *m = file->private_data;
|
||||
m->private = (void *)-1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
Reference in New Issue
Block a user