diff options
Diffstat (limited to 'kernel/trace/trace_functions_graph.c')
| -rw-r--r-- | kernel/trace/trace_functions_graph.c | 168 |
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 | ||
| 23 | static struct tracer_opt trace_opts[] = { | 24 | static 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 | ||
| 33 | static struct tracer_flags tracer_flags = { | 36 | static 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 | |||
| 112 | static enum print_line_t | ||
| 113 | print_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 */ |
| 109 | static int verif_pid(struct trace_seq *s, pid_t pid, int cpu) | 155 | static enum print_line_t |
| 156 | verif_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 | ||
| 172 | static inline int | 235 | static enum print_line_t |
| 173 | print_graph_duration(unsigned long long duration, struct trace_seq *s) | 236 | print_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 */ |
