diff options
author | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-05-12 12:15:34 -0400 |
---|---|---|
committer | Arnaldo Carvalho de Melo <acme@redhat.com> | 2012-05-12 12:15:34 -0400 |
commit | 7a997fe4019f556a81530d3a737d817a2b0d622f (patch) | |
tree | c924fdfc826a52755f1c2662a831dc82d3f94330 /tools/perf/util | |
parent | a43712c4720c8df4bad7d3760c67086168553b05 (diff) |
perf annotate: Augment lock instruction output
It just chops off the 'lock' and uses the ins__find, etc machinery to
call instruction specific parsers/beautifiers.
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-4913ba2dzakz5rivgumosqbh@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
Diffstat (limited to 'tools/perf/util')
-rw-r--r-- | tools/perf/util/annotate.c | 127 | ||||
-rw-r--r-- | tools/perf/util/annotate.h | 16 |
2 files changed, 109 insertions, 34 deletions
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c index a6109dc3a81e..1dce09874d93 100644 --- a/tools/perf/util/annotate.c +++ b/tools/perf/util/annotate.c | |||
@@ -18,6 +18,9 @@ | |||
18 | 18 | ||
19 | const char *disassembler_style; | 19 | const char *disassembler_style; |
20 | 20 | ||
21 | static struct ins *ins__find(const char *name); | ||
22 | static int disasm_line__parse(char *line, char **namep, char **rawp); | ||
23 | |||
21 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, | 24 | static int ins__raw_scnprintf(struct ins *ins, char *bf, size_t size, |
22 | struct ins_operands *ops) | 25 | struct ins_operands *ops) |
23 | { | 26 | { |
@@ -147,6 +150,53 @@ static int comment__symbol(char *raw, char *comment, u64 *addrp, char **namep) | |||
147 | return 0; | 150 | return 0; |
148 | } | 151 | } |
149 | 152 | ||
153 | static int lock__parse(struct ins_operands *ops) | ||
154 | { | ||
155 | char *name; | ||
156 | |||
157 | ops->locked.ops = zalloc(sizeof(*ops->locked.ops)); | ||
158 | if (ops->locked.ops == NULL) | ||
159 | return 0; | ||
160 | |||
161 | if (disasm_line__parse(ops->raw, &name, &ops->locked.ops->raw) < 0) | ||
162 | goto out_free_ops; | ||
163 | |||
164 | ops->locked.ins = ins__find(name); | ||
165 | if (ops->locked.ins == NULL) | ||
166 | goto out_free_ops; | ||
167 | |||
168 | if (!ops->locked.ins->ops) | ||
169 | return 0; | ||
170 | |||
171 | if (ops->locked.ins->ops->parse) | ||
172 | ops->locked.ins->ops->parse(ops->locked.ops); | ||
173 | |||
174 | return 0; | ||
175 | |||
176 | out_free_ops: | ||
177 | free(ops->locked.ops); | ||
178 | ops->locked.ops = NULL; | ||
179 | return 0; | ||
180 | } | ||
181 | |||
182 | static int lock__scnprintf(struct ins *ins, char *bf, size_t size, | ||
183 | struct ins_operands *ops) | ||
184 | { | ||
185 | int printed; | ||
186 | |||
187 | if (ops->locked.ins == NULL) | ||
188 | return ins__raw_scnprintf(ins, bf, size, ops); | ||
189 | |||
190 | printed = scnprintf(bf, size, "%-6.6s ", ins->name); | ||
191 | return printed + ins__scnprintf(ops->locked.ins, bf + printed, | ||
192 | size - printed, ops->locked.ops); | ||
193 | } | ||
194 | |||
195 | static struct ins_ops lock_ops = { | ||
196 | .parse = lock__parse, | ||
197 | .scnprintf = lock__scnprintf, | ||
198 | }; | ||
199 | |||
150 | static int mov__parse(struct ins_operands *ops) | 200 | static int mov__parse(struct ins_operands *ops) |
151 | { | 201 | { |
152 | char *s = strchr(ops->raw, ','), *target, *comment, prev; | 202 | char *s = strchr(ops->raw, ','), *target, *comment, prev; |
@@ -265,6 +315,7 @@ static struct ins instructions[] = { | |||
265 | { .name = "addq", .ops = &mov_ops, }, | 315 | { .name = "addq", .ops = &mov_ops, }, |
266 | { .name = "addw", .ops = &mov_ops, }, | 316 | { .name = "addw", .ops = &mov_ops, }, |
267 | { .name = "and", .ops = &mov_ops, }, | 317 | { .name = "and", .ops = &mov_ops, }, |
318 | { .name = "bts", .ops = &mov_ops, }, | ||
268 | { .name = "call", .ops = &call_ops, }, | 319 | { .name = "call", .ops = &call_ops, }, |
269 | { .name = "callq", .ops = &call_ops, }, | 320 | { .name = "callq", .ops = &call_ops, }, |
270 | { .name = "cmp", .ops = &mov_ops, }, | 321 | { .name = "cmp", .ops = &mov_ops, }, |
@@ -314,6 +365,7 @@ static struct ins instructions[] = { | |||
314 | { .name = "js", .ops = &jump_ops, }, | 365 | { .name = "js", .ops = &jump_ops, }, |
315 | { .name = "jz", .ops = &jump_ops, }, | 366 | { .name = "jz", .ops = &jump_ops, }, |
316 | { .name = "lea", .ops = &mov_ops, }, | 367 | { .name = "lea", .ops = &mov_ops, }, |
368 | { .name = "lock", .ops = &lock_ops, }, | ||
317 | { .name = "mov", .ops = &mov_ops, }, | 369 | { .name = "mov", .ops = &mov_ops, }, |
318 | { .name = "movb", .ops = &mov_ops, }, | 370 | { .name = "movb", .ops = &mov_ops, }, |
319 | { .name = "movdqa",.ops = &mov_ops, }, | 371 | { .name = "movdqa",.ops = &mov_ops, }, |
@@ -330,6 +382,7 @@ static struct ins instructions[] = { | |||
330 | { .name = "test", .ops = &mov_ops, }, | 382 | { .name = "test", .ops = &mov_ops, }, |
331 | { .name = "testb", .ops = &mov_ops, }, | 383 | { .name = "testb", .ops = &mov_ops, }, |
332 | { .name = "testl", .ops = &mov_ops, }, | 384 | { .name = "testl", .ops = &mov_ops, }, |
385 | { .name = "xadd", .ops = &mov_ops, }, | ||
333 | }; | 386 | }; |
334 | 387 | ||
335 | static int ins__cmp(const void *name, const void *insp) | 388 | static int ins__cmp(const void *name, const void *insp) |
@@ -420,6 +473,44 @@ static void disasm_line__init_ins(struct disasm_line *dl) | |||
420 | dl->ins->ops->parse(&dl->ops); | 473 | dl->ins->ops->parse(&dl->ops); |
421 | } | 474 | } |
422 | 475 | ||
476 | static int disasm_line__parse(char *line, char **namep, char **rawp) | ||
477 | { | ||
478 | char *name = line, tmp; | ||
479 | |||
480 | while (isspace(name[0])) | ||
481 | ++name; | ||
482 | |||
483 | if (name[0] == '\0') | ||
484 | return -1; | ||
485 | |||
486 | *rawp = name + 1; | ||
487 | |||
488 | while ((*rawp)[0] != '\0' && !isspace((*rawp)[0])) | ||
489 | ++*rawp; | ||
490 | |||
491 | tmp = (*rawp)[0]; | ||
492 | (*rawp)[0] = '\0'; | ||
493 | *namep = strdup(name); | ||
494 | |||
495 | if (*namep == NULL) | ||
496 | goto out_free_name; | ||
497 | |||
498 | (*rawp)[0] = tmp; | ||
499 | |||
500 | if ((*rawp)[0] != '\0') { | ||
501 | (*rawp)++; | ||
502 | while (isspace((*rawp)[0])) | ||
503 | ++(*rawp); | ||
504 | } | ||
505 | |||
506 | return 0; | ||
507 | |||
508 | out_free_name: | ||
509 | free(*namep); | ||
510 | *namep = NULL; | ||
511 | return -1; | ||
512 | } | ||
513 | |||
423 | static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) | 514 | static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize) |
424 | { | 515 | { |
425 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); | 516 | struct disasm_line *dl = zalloc(sizeof(*dl) + privsize); |
@@ -431,35 +522,9 @@ static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privs | |||
431 | goto out_delete; | 522 | goto out_delete; |
432 | 523 | ||
433 | if (offset != -1) { | 524 | if (offset != -1) { |
434 | char *name = dl->line, tmp; | 525 | if (disasm_line__parse(dl->line, &dl->name, &dl->ops.raw) < 0) |
435 | |||
436 | while (isspace(name[0])) | ||
437 | ++name; | ||
438 | |||
439 | if (name[0] == '\0') | ||
440 | goto out_delete; | ||
441 | |||
442 | dl->ops.raw = name + 1; | ||
443 | |||
444 | while (dl->ops.raw[0] != '\0' && | ||
445 | !isspace(dl->ops.raw[0])) | ||
446 | ++dl->ops.raw; | ||
447 | |||
448 | tmp = dl->ops.raw[0]; | ||
449 | dl->ops.raw[0] = '\0'; | ||
450 | dl->name = strdup(name); | ||
451 | |||
452 | if (dl->name == NULL) | ||
453 | goto out_free_line; | 526 | goto out_free_line; |
454 | 527 | ||
455 | dl->ops.raw[0] = tmp; | ||
456 | |||
457 | if (dl->ops.raw[0] != '\0') { | ||
458 | dl->ops.raw++; | ||
459 | while (isspace(dl->ops.raw[0])) | ||
460 | ++dl->ops.raw; | ||
461 | } | ||
462 | |||
463 | disasm_line__init_ins(dl); | 528 | disasm_line__init_ins(dl); |
464 | } | 529 | } |
465 | } | 530 | } |
@@ -477,8 +542,12 @@ void disasm_line__free(struct disasm_line *dl) | |||
477 | { | 542 | { |
478 | free(dl->line); | 543 | free(dl->line); |
479 | free(dl->name); | 544 | free(dl->name); |
480 | free(dl->ops.source.raw); | 545 | if (dl->ins && dl->ins->ops == &lock_ops) { |
481 | free(dl->ops.source.name); | 546 | free(dl->ops.locked.ops); |
547 | } else { | ||
548 | free(dl->ops.source.raw); | ||
549 | free(dl->ops.source.name); | ||
550 | } | ||
482 | free(dl->ops.target.raw); | 551 | free(dl->ops.target.raw); |
483 | free(dl->ops.target.name); | 552 | free(dl->ops.target.name); |
484 | free(dl); | 553 | free(dl); |
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h index 066d31d696df..b79d3260647c 100644 --- a/tools/perf/util/annotate.h +++ b/tools/perf/util/annotate.h | |||
@@ -18,11 +18,17 @@ struct ins_operands { | |||
18 | u64 addr; | 18 | u64 addr; |
19 | u64 offset; | 19 | u64 offset; |
20 | } target; | 20 | } target; |
21 | struct { | 21 | union { |
22 | char *raw; | 22 | struct { |
23 | char *name; | 23 | char *raw; |
24 | u64 addr; | 24 | char *name; |
25 | } source; | 25 | u64 addr; |
26 | } source; | ||
27 | struct { | ||
28 | struct ins *ins; | ||
29 | struct ins_operands *ops; | ||
30 | } locked; | ||
31 | }; | ||
26 | }; | 32 | }; |
27 | 33 | ||
28 | struct ins_ops { | 34 | struct ins_ops { |