提交 5ce1b1ed 编写于 作者: I Ingo Molnar

Merge branches 'tracing/ftrace' and 'tracing/function-graph-tracer' into tracing/core

/* /*
* *
* Function graph tracer. * Function graph tracer.
* Copyright (c) 2008 Frederic Weisbecker <fweisbec@gmail.com> * Copyright (c) 2008-2009 Frederic Weisbecker <fweisbec@gmail.com>
* Mostly borrowed from function tracer which * Mostly borrowed from function tracer which
* is Copyright (c) Steven Rostedt <srostedt@redhat.com> * is Copyright (c) Steven Rostedt <srostedt@redhat.com>
* *
...@@ -21,9 +21,11 @@ ...@@ -21,9 +21,11 @@
#define TRACE_GRAPH_PRINT_CPU 0x2 #define TRACE_GRAPH_PRINT_CPU 0x2
#define TRACE_GRAPH_PRINT_OVERHEAD 0x4 #define TRACE_GRAPH_PRINT_OVERHEAD 0x4
#define TRACE_GRAPH_PRINT_PROC 0x8 #define TRACE_GRAPH_PRINT_PROC 0x8
#define TRACE_GRAPH_PRINT_DURATION 0x10
#define TRACE_GRAPH_PRINT_ABS_TIME 0X20
static struct tracer_opt trace_opts[] = { static struct tracer_opt trace_opts[] = {
/* Display overruns ? */ /* Display overruns? (for self-debug purpose) */
{ TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) }, { TRACER_OPT(funcgraph-overrun, TRACE_GRAPH_PRINT_OVERRUN) },
/* Display CPU ? */ /* Display CPU ? */
{ TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) }, { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
...@@ -31,17 +33,22 @@ static struct tracer_opt trace_opts[] = { ...@@ -31,17 +33,22 @@ static struct tracer_opt trace_opts[] = {
{ TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) }, { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
/* Display proc name/pid */ /* Display proc name/pid */
{ TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) }, { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
/* Display duration of execution */
{ TRACER_OPT(funcgraph-duration, TRACE_GRAPH_PRINT_DURATION) },
/* Display absolute time of an entry */
{ TRACER_OPT(funcgraph-abstime, TRACE_GRAPH_PRINT_ABS_TIME) },
{ } /* Empty entry */ { } /* Empty entry */
}; };
static struct tracer_flags tracer_flags = { static struct tracer_flags tracer_flags = {
/* Don't display overruns and proc by default */ /* Don't display overruns and proc by default */
.val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD, .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD |
TRACE_GRAPH_PRINT_DURATION,
.opts = trace_opts .opts = trace_opts
}; };
/* pid on the last trace processed */ /* pid on the last trace processed */
static pid_t last_pid[NR_CPUS] = { [0 ... NR_CPUS-1] = -1 };
static int graph_trace_init(struct trace_array *tr) static int graph_trace_init(struct trace_array *tr)
{ {
...@@ -154,17 +161,25 @@ print_graph_proc(struct trace_seq *s, pid_t pid) ...@@ -154,17 +161,25 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
/* If the pid changed since the last trace, output this event */ /* If the pid changed since the last trace, output this event */
static enum print_line_t static enum print_line_t
verif_pid(struct trace_seq *s, pid_t pid, int cpu) verif_pid(struct trace_seq *s, pid_t pid, int cpu, pid_t *last_pids_cpu)
{ {
pid_t prev_pid; pid_t prev_pid;
pid_t *last_pid;
int ret; int ret;
if (last_pid[cpu] != -1 && last_pid[cpu] == pid) if (!last_pids_cpu)
return TRACE_TYPE_HANDLED;
last_pid = per_cpu_ptr(last_pids_cpu, cpu);
if (*last_pid == pid)
return TRACE_TYPE_HANDLED; return TRACE_TYPE_HANDLED;
prev_pid = last_pid[cpu]; prev_pid = *last_pid;
last_pid[cpu] = pid; *last_pid = pid;
if (prev_pid == -1)
return TRACE_TYPE_HANDLED;
/* /*
* Context-switch trace line: * Context-switch trace line:
...@@ -232,9 +247,34 @@ trace_branch_is_leaf(struct trace_iterator *iter, ...@@ -232,9 +247,34 @@ trace_branch_is_leaf(struct trace_iterator *iter,
return true; return true;
} }
/* Signal a overhead of time execution to the output */
static int
print_graph_overhead(unsigned long long duration, struct trace_seq *s)
{
/* If duration disappear, we don't need anything */
if (!(tracer_flags.val & TRACE_GRAPH_PRINT_DURATION))
return 1;
/* Non nested entry or return */
if (duration == -1)
return trace_seq_printf(s, " ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
/* Duration exceeded 100 msecs */
if (duration > 100000ULL)
return trace_seq_printf(s, "! ");
/* Duration exceeded 10 msecs */
if (duration > 10000ULL)
return trace_seq_printf(s, "+ ");
}
return trace_seq_printf(s, " ");
}
static enum print_line_t static enum print_line_t
print_graph_irq(struct trace_seq *s, unsigned long addr, print_graph_irq(struct trace_seq *s, unsigned long addr,
enum trace_type type, int cpu, pid_t pid) enum trace_type type, int cpu, pid_t pid)
{ {
int ret; int ret;
...@@ -242,35 +282,40 @@ print_graph_irq(struct trace_seq *s, unsigned long addr, ...@@ -242,35 +282,40 @@ print_graph_irq(struct trace_seq *s, unsigned long addr,
addr >= (unsigned long)__irqentry_text_end) addr >= (unsigned long)__irqentry_text_end)
return TRACE_TYPE_UNHANDLED; return TRACE_TYPE_UNHANDLED;
if (type == TRACE_GRAPH_ENT) { /* Cpu */
ret = trace_seq_printf(s, "==========> | "); if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
} else { ret = print_graph_cpu(s, cpu);
/* Cpu */ if (ret == TRACE_TYPE_PARTIAL_LINE)
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { return TRACE_TYPE_PARTIAL_LINE;
ret = print_graph_cpu(s, cpu); }
if (ret == TRACE_TYPE_PARTIAL_LINE) /* Proc */
return TRACE_TYPE_PARTIAL_LINE; if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
} ret = print_graph_proc(s, pid);
/* Proc */ if (ret == TRACE_TYPE_PARTIAL_LINE)
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) { return TRACE_TYPE_PARTIAL_LINE;
ret = print_graph_proc(s, pid); ret = trace_seq_printf(s, " | ");
if (ret == TRACE_TYPE_PARTIAL_LINE) if (!ret)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
}
ret = trace_seq_printf(s, " | "); /* No overhead */
if (!ret) ret = print_graph_overhead(-1, s);
return TRACE_TYPE_PARTIAL_LINE; if (!ret)
} return TRACE_TYPE_PARTIAL_LINE;
/* No overhead */ if (type == TRACE_GRAPH_ENT)
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { ret = trace_seq_printf(s, "==========>");
ret = trace_seq_printf(s, " "); else
if (!ret) ret = trace_seq_printf(s, "<==========");
return TRACE_TYPE_PARTIAL_LINE;
} if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
/* Don't close the duration column if haven't one */
if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)
trace_seq_printf(s, " |");
ret = trace_seq_printf(s, "\n");
ret = trace_seq_printf(s, "<========== |\n");
}
if (!ret) if (!ret)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_HANDLED; return TRACE_TYPE_HANDLED;
...@@ -289,7 +334,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s) ...@@ -289,7 +334,7 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s)
sprintf(msecs_str, "%lu", (unsigned long) duration); sprintf(msecs_str, "%lu", (unsigned long) duration);
/* Print msecs */ /* Print msecs */
ret = trace_seq_printf(s, msecs_str); ret = trace_seq_printf(s, "%s", msecs_str);
if (!ret) if (!ret)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
...@@ -322,19 +367,15 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s) ...@@ -322,19 +367,15 @@ print_graph_duration(unsigned long long duration, struct trace_seq *s)
} }
/* Signal a overhead of time execution to the output */ static int print_graph_abs_time(u64 t, struct trace_seq *s)
static int
print_graph_overhead(unsigned long long duration, struct trace_seq *s)
{ {
/* Duration exceeded 100 msecs */ unsigned long usecs_rem;
if (duration > 100000ULL)
return trace_seq_printf(s, "! ");
/* Duration exceeded 10 msecs */ usecs_rem = do_div(t, 1000000000);
if (duration > 10000ULL) usecs_rem /= 1000;
return trace_seq_printf(s, "+ ");
return trace_seq_printf(s, " "); return trace_seq_printf(s, "%5lu.%06lu | ",
(unsigned long)t, usecs_rem);
} }
/* Case of a leaf function on its call entry */ /* Case of a leaf function on its call entry */
...@@ -357,16 +398,16 @@ print_graph_entry_leaf(struct trace_iterator *iter, ...@@ -357,16 +398,16 @@ print_graph_entry_leaf(struct trace_iterator *iter,
duration = graph_ret->rettime - graph_ret->calltime; duration = graph_ret->rettime - graph_ret->calltime;
/* Overhead */ /* Overhead */
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { ret = print_graph_overhead(duration, s);
ret = print_graph_overhead(duration, s); if (!ret)
if (!ret) return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_PARTIAL_LINE;
}
/* Duration */ /* Duration */
ret = print_graph_duration(duration, s); if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) {
if (ret == TRACE_TYPE_PARTIAL_LINE) ret = print_graph_duration(duration, s);
return TRACE_TYPE_PARTIAL_LINE; if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
}
/* Function */ /* Function */
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
...@@ -395,25 +436,17 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, ...@@ -395,25 +436,17 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
struct ftrace_graph_ent *call = &entry->graph_ent; struct ftrace_graph_ent *call = &entry->graph_ent;
/* No overhead */ /* No overhead */
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { ret = print_graph_overhead(-1, s);
ret = trace_seq_printf(s, " "); if (!ret)
if (!ret) return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_PARTIAL_LINE;
}
/* Interrupt */ /* No time */
ret = print_graph_irq(s, call->func, TRACE_GRAPH_ENT, cpu, pid); if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) {
if (ret == TRACE_TYPE_UNHANDLED) {
/* No time */
ret = trace_seq_printf(s, " | "); ret = trace_seq_printf(s, " | ");
if (!ret) if (!ret)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
} else {
if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
} }
/* Function */ /* Function */
for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) { for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
ret = trace_seq_printf(s, " "); ret = trace_seq_printf(s, " ");
...@@ -434,15 +467,30 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry, ...@@ -434,15 +467,30 @@ print_graph_entry_nested(struct ftrace_graph_ent_entry *entry,
static enum print_line_t static enum print_line_t
print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
struct trace_iterator *iter, int cpu) struct trace_iterator *iter)
{ {
int ret; int ret;
int cpu = iter->cpu;
pid_t *last_entry = iter->private;
struct trace_entry *ent = iter->ent; struct trace_entry *ent = iter->ent;
struct ftrace_graph_ent *call = &field->graph_ent;
/* Pid */ /* Pid */
if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE) if (verif_pid(s, ent->pid, cpu, last_entry) == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
/* Interrupt */
ret = print_graph_irq(s, call->func, TRACE_GRAPH_ENT, cpu, ent->pid);
if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
/* Absolute time */
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) {
ret = print_graph_abs_time(iter->ts, s);
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
}
/* Cpu */ /* Cpu */
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
ret = print_graph_cpu(s, cpu); ret = print_graph_cpu(s, cpu);
...@@ -470,16 +518,25 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s, ...@@ -470,16 +518,25 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
static enum print_line_t static enum print_line_t
print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
struct trace_entry *ent, int cpu) struct trace_entry *ent, struct trace_iterator *iter)
{ {
int i; int i;
int ret; int ret;
int cpu = iter->cpu;
pid_t *last_pid = iter->private;
unsigned long long duration = trace->rettime - trace->calltime; unsigned long long duration = trace->rettime - trace->calltime;
/* Pid */ /* Pid */
if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE) if (verif_pid(s, ent->pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
/* Absolute time */
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) {
ret = print_graph_abs_time(iter->ts, s);
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
}
/* Cpu */ /* Cpu */
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
ret = print_graph_cpu(s, cpu); ret = print_graph_cpu(s, cpu);
...@@ -499,16 +556,16 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s, ...@@ -499,16 +556,16 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
} }
/* Overhead */ /* Overhead */
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { ret = print_graph_overhead(duration, s);
ret = print_graph_overhead(duration, s); if (!ret)
if (!ret) return TRACE_TYPE_PARTIAL_LINE;
return TRACE_TYPE_PARTIAL_LINE;
}
/* Duration */ /* Duration */
ret = print_graph_duration(duration, s); if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) {
if (ret == TRACE_TYPE_PARTIAL_LINE) ret = print_graph_duration(duration, s);
return TRACE_TYPE_PARTIAL_LINE; if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE;
}
/* Closing brace */ /* Closing brace */
for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) { for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
...@@ -542,14 +599,23 @@ print_graph_comment(struct print_entry *trace, struct trace_seq *s, ...@@ -542,14 +599,23 @@ print_graph_comment(struct print_entry *trace, struct trace_seq *s,
{ {
int i; int i;
int ret; int ret;
int cpu = iter->cpu;
pid_t *last_pid = iter->private;
/* Absolute time */
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME) {
ret = print_graph_abs_time(iter->ts, s);
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
}
/* Pid */ /* Pid */
if (verif_pid(s, ent->pid, iter->cpu) == TRACE_TYPE_PARTIAL_LINE) if (verif_pid(s, ent->pid, cpu, last_pid) == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
/* Cpu */ /* Cpu */
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
ret = print_graph_cpu(s, iter->cpu); ret = print_graph_cpu(s, cpu);
if (ret == TRACE_TYPE_PARTIAL_LINE) if (ret == TRACE_TYPE_PARTIAL_LINE)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
} }
...@@ -566,17 +632,17 @@ print_graph_comment(struct print_entry *trace, struct trace_seq *s, ...@@ -566,17 +632,17 @@ print_graph_comment(struct print_entry *trace, struct trace_seq *s,
} }
/* No overhead */ /* No overhead */
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { ret = print_graph_overhead(-1, s);
ret = trace_seq_printf(s, " "); if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
/* No time */
if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION) {
ret = trace_seq_printf(s, " | ");
if (!ret) if (!ret)
return TRACE_TYPE_PARTIAL_LINE; return TRACE_TYPE_PARTIAL_LINE;
} }
/* No time */
ret = trace_seq_printf(s, " | ");
if (!ret)
return TRACE_TYPE_PARTIAL_LINE;
/* Indentation */ /* Indentation */
if (trace->depth > 0) if (trace->depth > 0)
for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) { for (i = 0; i < (trace->depth + 1) * TRACE_GRAPH_INDENT; i++) {
...@@ -614,13 +680,12 @@ print_graph_function(struct trace_iterator *iter) ...@@ -614,13 +680,12 @@ print_graph_function(struct trace_iterator *iter)
case TRACE_GRAPH_ENT: { case TRACE_GRAPH_ENT: {
struct ftrace_graph_ent_entry *field; struct ftrace_graph_ent_entry *field;
trace_assign_type(field, entry); trace_assign_type(field, entry);
return print_graph_entry(field, s, iter, return print_graph_entry(field, s, iter);
iter->cpu);
} }
case TRACE_GRAPH_RET: { case TRACE_GRAPH_RET: {
struct ftrace_graph_ret_entry *field; struct ftrace_graph_ret_entry *field;
trace_assign_type(field, entry); trace_assign_type(field, entry);
return print_graph_return(&field->ret, s, entry, iter->cpu); return print_graph_return(&field->ret, s, entry, iter);
} }
case TRACE_PRINT: { case TRACE_PRINT: {
struct print_entry *field; struct print_entry *field;
...@@ -636,28 +701,55 @@ static void print_graph_headers(struct seq_file *s) ...@@ -636,28 +701,55 @@ static void print_graph_headers(struct seq_file *s)
{ {
/* 1st line */ /* 1st line */
seq_printf(s, "# "); seq_printf(s, "# ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME)
seq_printf(s, " TIME ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
seq_printf(s, "CPU "); seq_printf(s, "CPU");
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
seq_printf(s, "TASK/PID "); seq_printf(s, " TASK/PID ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)
seq_printf(s, "OVERHEAD/"); seq_printf(s, " DURATION ");
seq_printf(s, "DURATION FUNCTION CALLS\n"); seq_printf(s, " FUNCTION CALLS\n");
/* 2nd line */ /* 2nd line */
seq_printf(s, "# "); seq_printf(s, "# ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_ABS_TIME)
seq_printf(s, " | ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU)
seq_printf(s, "| "); seq_printf(s, "| ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC)
seq_printf(s, "| | "); seq_printf(s, " | | ");
if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { if (tracer_flags.val & TRACE_GRAPH_PRINT_DURATION)
seq_printf(s, "| "); seq_printf(s, " | | ");
seq_printf(s, "| | | | |\n"); seq_printf(s, " | | | |\n");
} else
seq_printf(s, " | | | | |\n");
} }
static void graph_trace_open(struct trace_iterator *iter)
{
/* pid on the last trace processed */
pid_t *last_pid = alloc_percpu(pid_t);
int cpu;
if (!last_pid)
pr_warning("function graph tracer: not enough memory\n");
else
for_each_possible_cpu(cpu) {
pid_t *pid = per_cpu_ptr(last_pid, cpu);
*pid = -1;
}
iter->private = last_pid;
}
static void graph_trace_close(struct trace_iterator *iter)
{
percpu_free(iter->private);
}
static struct tracer graph_trace __read_mostly = { static struct tracer graph_trace __read_mostly = {
.name = "function_graph", .name = "function_graph",
.open = graph_trace_open,
.close = graph_trace_close,
.init = graph_trace_init, .init = graph_trace_init,
.reset = graph_trace_reset, .reset = graph_trace_reset,
.print_line = print_graph_function, .print_line = print_graph_function,
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册