aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace/trace_functions_graph.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
-rw-r--r--kernel/trace/trace_functions_graph.c168
1 files changed, 142 insertions, 26 deletions
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 894b50bca313..c66578f2fdc2 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -19,6 +19,7 @@
19#define TRACE_GRAPH_PRINT_OVERRUN 0x1 19#define TRACE_GRAPH_PRINT_OVERRUN 0x1
20#define TRACE_GRAPH_PRINT_CPU 0x2 20#define TRACE_GRAPH_PRINT_CPU 0x2
21#define TRACE_GRAPH_PRINT_OVERHEAD 0x4 21#define TRACE_GRAPH_PRINT_OVERHEAD 0x4
22#define TRACE_GRAPH_PRINT_PROC 0x8
22 23
23static struct tracer_opt trace_opts[] = { 24static struct tracer_opt trace_opts[] = {
24 /* Display overruns ? */ 25 /* Display overruns ? */
@@ -27,11 +28,13 @@ static struct tracer_opt trace_opts[] = {
27 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) }, 28 { TRACER_OPT(funcgraph-cpu, TRACE_GRAPH_PRINT_CPU) },
28 /* Display Overhead ? */ 29 /* Display Overhead ? */
29 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) }, 30 { TRACER_OPT(funcgraph-overhead, TRACE_GRAPH_PRINT_OVERHEAD) },
31 /* Display proc name/pid */
32 { TRACER_OPT(funcgraph-proc, TRACE_GRAPH_PRINT_PROC) },
30 { } /* Empty entry */ 33 { } /* Empty entry */
31}; 34};
32 35
33static struct tracer_flags tracer_flags = { 36static struct tracer_flags tracer_flags = {
34 /* Don't display overruns by default */ 37 /* Don't display overruns and proc by default */
35 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD, 38 .val = TRACE_GRAPH_PRINT_CPU | TRACE_GRAPH_PRINT_OVERHEAD,
36 .opts = trace_opts 39 .opts = trace_opts
37}; 40};
@@ -104,23 +107,63 @@ print_graph_cpu(struct trace_seq *s, int cpu)
104 return TRACE_TYPE_HANDLED; 107 return TRACE_TYPE_HANDLED;
105} 108}
106 109
110#define TRACE_GRAPH_PROCINFO_LENGTH 14
111
112static enum print_line_t
113print_graph_proc(struct trace_seq *s, pid_t pid)
114{
115 int i;
116 int ret;
117 int len;
118 char comm[8];
119 int spaces = 0;
120 /* sign + log10(MAX_INT) + '\0' */
121 char pid_str[11];
122
123 strncpy(comm, trace_find_cmdline(pid), 7);
124 comm[7] = '\0';
125 sprintf(pid_str, "%d", pid);
126
127 /* 1 stands for the "-" character */
128 len = strlen(comm) + strlen(pid_str) + 1;
129
130 if (len < TRACE_GRAPH_PROCINFO_LENGTH)
131 spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
132
133 /* First spaces to align center */
134 for (i = 0; i < spaces / 2; i++) {
135 ret = trace_seq_printf(s, " ");
136 if (!ret)
137 return TRACE_TYPE_PARTIAL_LINE;
138 }
139
140 ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
141 if (!ret)
142 return TRACE_TYPE_PARTIAL_LINE;
143
144 /* Last spaces to align center */
145 for (i = 0; i < spaces - (spaces / 2); i++) {
146 ret = trace_seq_printf(s, " ");
147 if (!ret)
148 return TRACE_TYPE_PARTIAL_LINE;
149 }
150 return TRACE_TYPE_HANDLED;
151}
152
107 153
108/* If the pid changed since the last trace, output this event */ 154/* If the pid changed since the last trace, output this event */
109static int verif_pid(struct trace_seq *s, pid_t pid, int cpu) 155static enum print_line_t
156verif_pid(struct trace_seq *s, pid_t pid, int cpu)
110{ 157{
111 char *comm, *prev_comm;
112 pid_t prev_pid; 158 pid_t prev_pid;
113 int ret; 159 int ret;
114 160
115 if (last_pid[cpu] != -1 && last_pid[cpu] == pid) 161 if (last_pid[cpu] != -1 && last_pid[cpu] == pid)
116 return 1; 162 return TRACE_TYPE_HANDLED;
117 163
118 prev_pid = last_pid[cpu]; 164 prev_pid = last_pid[cpu];
119 last_pid[cpu] = pid; 165 last_pid[cpu] = pid;
120 166
121 comm = trace_find_cmdline(pid);
122 prev_comm = trace_find_cmdline(prev_pid);
123
124/* 167/*
125 * Context-switch trace line: 168 * Context-switch trace line:
126 169
@@ -130,11 +173,31 @@ static int verif_pid(struct trace_seq *s, pid_t pid, int cpu)
130 173
131 */ 174 */
132 ret = trace_seq_printf(s, 175 ret = trace_seq_printf(s,
133 " ------------------------------------------\n"); 176 "\n ------------------------------------------\n |");
134 ret += trace_seq_printf(s, " | %d) %s-%d => %s-%d\n", 177 if (!ret)
135 cpu, prev_comm, prev_pid, comm, pid); 178 TRACE_TYPE_PARTIAL_LINE;
136 ret += trace_seq_printf(s, 179
137 " ------------------------------------------\n\n"); 180 ret = print_graph_cpu(s, cpu);
181 if (ret == TRACE_TYPE_PARTIAL_LINE)
182 TRACE_TYPE_PARTIAL_LINE;
183
184 ret = print_graph_proc(s, prev_pid);
185 if (ret == TRACE_TYPE_PARTIAL_LINE)
186 TRACE_TYPE_PARTIAL_LINE;
187
188 ret = trace_seq_printf(s, " => ");
189 if (!ret)
190 TRACE_TYPE_PARTIAL_LINE;
191
192 ret = print_graph_proc(s, pid);
193 if (ret == TRACE_TYPE_PARTIAL_LINE)
194 TRACE_TYPE_PARTIAL_LINE;
195
196 ret = trace_seq_printf(s,
197 "\n ------------------------------------------\n\n");
198 if (!ret)
199 TRACE_TYPE_PARTIAL_LINE;
200
138 return ret; 201 return ret;
139} 202}
140 203
@@ -169,11 +232,50 @@ trace_branch_is_leaf(struct trace_iterator *iter,
169} 232}
170 233
171 234
172static inline int 235static enum print_line_t
173print_graph_duration(unsigned long long duration, struct trace_seq *s) 236print_graph_duration(unsigned long long duration, struct trace_seq *s)
174{ 237{
175 unsigned long nsecs_rem = do_div(duration, 1000); 238 unsigned long nsecs_rem = do_div(duration, 1000);
176 return trace_seq_printf(s, "%4llu.%3lu us | ", duration, nsecs_rem); 239 /* log10(ULONG_MAX) + '\0' */
240 char msecs_str[21];
241 char nsecs_str[5];
242 int ret, len;
243 int i;
244
245 sprintf(msecs_str, "%lu", (unsigned long) duration);
246
247 /* Print msecs */
248 ret = trace_seq_printf(s, msecs_str);
249 if (!ret)
250 return TRACE_TYPE_PARTIAL_LINE;
251
252 len = strlen(msecs_str);
253
254 /* Print nsecs (we don't want to exceed 7 numbers) */
255 if (len < 7) {
256 snprintf(nsecs_str, 8 - len, "%03lu", nsecs_rem);
257 ret = trace_seq_printf(s, ".%s", nsecs_str);
258 if (!ret)
259 return TRACE_TYPE_PARTIAL_LINE;
260 len += strlen(nsecs_str);
261 }
262
263 ret = trace_seq_printf(s, " us ");
264 if (!ret)
265 return TRACE_TYPE_PARTIAL_LINE;
266
267 /* Print remaining spaces to fit the row's width */
268 for (i = len; i < 7; i++) {
269 ret = trace_seq_printf(s, " ");
270 if (!ret)
271 return TRACE_TYPE_PARTIAL_LINE;
272 }
273
274 ret = trace_seq_printf(s, "| ");
275 if (!ret)
276 return TRACE_TYPE_PARTIAL_LINE;
277 return TRACE_TYPE_HANDLED;
278
177} 279}
178 280
179/* Signal a overhead of time execution to the output */ 281/* Signal a overhead of time execution to the output */
@@ -210,10 +312,6 @@ print_graph_entry_leaf(struct trace_iterator *iter,
210 call = &entry->graph_ent; 312 call = &entry->graph_ent;
211 duration = graph_ret->rettime - graph_ret->calltime; 313 duration = graph_ret->rettime - graph_ret->calltime;
212 314
213 /* Must not exceed 8 characters: 9999.999 us */
214 if (duration > 10000000ULL)
215 duration = 9999999ULL;
216
217 /* Overhead */ 315 /* Overhead */
218 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) { 316 if (tracer_flags.val & TRACE_GRAPH_PRINT_OVERHEAD) {
219 ret = print_graph_overhead(duration, s); 317 ret = print_graph_overhead(duration, s);
@@ -223,7 +321,7 @@ print_graph_entry_leaf(struct trace_iterator *iter,
223 321
224 /* Duration */ 322 /* Duration */
225 ret = print_graph_duration(duration, s); 323 ret = print_graph_duration(duration, s);
226 if (!ret) 324 if (ret == TRACE_TYPE_PARTIAL_LINE)
227 return TRACE_TYPE_PARTIAL_LINE; 325 return TRACE_TYPE_PARTIAL_LINE;
228 326
229 /* Function */ 327 /* Function */
@@ -288,12 +386,23 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
288 struct trace_entry *ent = iter->ent; 386 struct trace_entry *ent = iter->ent;
289 387
290 /* Pid */ 388 /* Pid */
291 if (!verif_pid(s, ent->pid, cpu)) 389 if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
292 return TRACE_TYPE_PARTIAL_LINE; 390 return TRACE_TYPE_PARTIAL_LINE;
293 391
294 /* Cpu */ 392 /* Cpu */
295 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { 393 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
296 ret = print_graph_cpu(s, cpu); 394 ret = print_graph_cpu(s, cpu);
395 if (ret == TRACE_TYPE_PARTIAL_LINE)
396 return TRACE_TYPE_PARTIAL_LINE;
397 }
398
399 /* Proc */
400 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
401 ret = print_graph_proc(s, ent->pid);
402 if (ret == TRACE_TYPE_PARTIAL_LINE)
403 return TRACE_TYPE_PARTIAL_LINE;
404
405 ret = trace_seq_printf(s, " | ");
297 if (!ret) 406 if (!ret)
298 return TRACE_TYPE_PARTIAL_LINE; 407 return TRACE_TYPE_PARTIAL_LINE;
299 } 408 }
@@ -313,17 +422,24 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
313 int ret; 422 int ret;
314 unsigned long long duration = trace->rettime - trace->calltime; 423 unsigned long long duration = trace->rettime - trace->calltime;
315 424
316 /* Must not exceed 8 characters: xxxx.yyy us */
317 if (duration > 10000000ULL)
318 duration = 9999999ULL;
319
320 /* Pid */ 425 /* Pid */
321 if (!verif_pid(s, ent->pid, cpu)) 426 if (verif_pid(s, ent->pid, cpu) == TRACE_TYPE_PARTIAL_LINE)
322 return TRACE_TYPE_PARTIAL_LINE; 427 return TRACE_TYPE_PARTIAL_LINE;
323 428
324 /* Cpu */ 429 /* Cpu */
325 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) { 430 if (tracer_flags.val & TRACE_GRAPH_PRINT_CPU) {
326 ret = print_graph_cpu(s, cpu); 431 ret = print_graph_cpu(s, cpu);
432 if (ret == TRACE_TYPE_PARTIAL_LINE)
433 return TRACE_TYPE_PARTIAL_LINE;
434 }
435
436 /* Proc */
437 if (tracer_flags.val & TRACE_GRAPH_PRINT_PROC) {
438 ret = print_graph_proc(s, ent->pid);
439 if (ret == TRACE_TYPE_PARTIAL_LINE)
440 return TRACE_TYPE_PARTIAL_LINE;
441
442 ret = trace_seq_printf(s, " | ");
327 if (!ret) 443 if (!ret)
328 return TRACE_TYPE_PARTIAL_LINE; 444 return TRACE_TYPE_PARTIAL_LINE;
329 } 445 }
@@ -337,7 +453,7 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
337 453
338 /* Duration */ 454 /* Duration */
339 ret = print_graph_duration(duration, s); 455 ret = print_graph_duration(duration, s);
340 if (!ret) 456 if (ret == TRACE_TYPE_PARTIAL_LINE)
341 return TRACE_TYPE_PARTIAL_LINE; 457 return TRACE_TYPE_PARTIAL_LINE;
342 458
343 /* Closing brace */ 459 /* Closing brace */