diff options
Diffstat (limited to 'tools/perf/builtin-annotate.c')
| -rw-r--r-- | tools/perf/builtin-annotate.c | 135 |
1 files changed, 112 insertions, 23 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e47dd1587e39..5ec5de995872 100644 --- a/tools/perf/builtin-annotate.c +++ b/tools/perf/builtin-annotate.c | |||
| @@ -145,21 +145,58 @@ static int process_sample_event(event_t *event, struct perf_session *session) | |||
| 145 | return 0; | 145 | return 0; |
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | static int parse_line(FILE *file, struct hist_entry *he, u64 len) | 148 | struct objdump_line { |
| 149 | struct list_head node; | ||
| 150 | s64 offset; | ||
| 151 | char *line; | ||
| 152 | }; | ||
| 153 | |||
| 154 | static struct objdump_line *objdump_line__new(s64 offset, char *line) | ||
| 155 | { | ||
| 156 | struct objdump_line *self = malloc(sizeof(*self)); | ||
| 157 | |||
| 158 | if (self != NULL) { | ||
| 159 | self->offset = offset; | ||
| 160 | self->line = line; | ||
| 161 | } | ||
| 162 | |||
| 163 | return self; | ||
| 164 | } | ||
| 165 | |||
| 166 | static void objdump_line__free(struct objdump_line *self) | ||
| 167 | { | ||
| 168 | free(self->line); | ||
| 169 | free(self); | ||
| 170 | } | ||
| 171 | |||
| 172 | static void objdump__add_line(struct list_head *head, struct objdump_line *line) | ||
| 173 | { | ||
| 174 | list_add_tail(&line->node, head); | ||
| 175 | } | ||
| 176 | |||
| 177 | static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, | ||
| 178 | struct objdump_line *pos) | ||
| 179 | { | ||
| 180 | list_for_each_entry_continue(pos, head, node) | ||
| 181 | if (pos->offset >= 0) | ||
| 182 | return pos; | ||
| 183 | |||
| 184 | return NULL; | ||
| 185 | } | ||
| 186 | |||
| 187 | static int parse_line(FILE *file, struct hist_entry *he, | ||
| 188 | struct list_head *head) | ||
| 149 | { | 189 | { |
| 150 | struct symbol *sym = he->sym; | 190 | struct symbol *sym = he->sym; |
| 191 | struct objdump_line *objdump_line; | ||
| 151 | char *line = NULL, *tmp, *tmp2; | 192 | char *line = NULL, *tmp, *tmp2; |
| 152 | static const char *prev_line; | ||
| 153 | static const char *prev_color; | ||
| 154 | unsigned int offset; | ||
| 155 | size_t line_len; | 193 | size_t line_len; |
| 156 | u64 start; | 194 | s64 line_ip, offset = -1; |
| 157 | s64 line_ip; | ||
| 158 | int ret; | ||
| 159 | char *c; | 195 | char *c; |
| 160 | 196 | ||
| 161 | if (getline(&line, &line_len, file) < 0) | 197 | if (getline(&line, &line_len, file) < 0) |
| 162 | return -1; | 198 | return -1; |
| 199 | |||
| 163 | if (!line) | 200 | if (!line) |
| 164 | return -1; | 201 | return -1; |
| 165 | 202 | ||
| @@ -168,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
| 168 | *c = 0; | 205 | *c = 0; |
| 169 | 206 | ||
| 170 | line_ip = -1; | 207 | line_ip = -1; |
| 171 | offset = 0; | ||
| 172 | ret = -2; | ||
| 173 | 208 | ||
| 174 | /* | 209 | /* |
| 175 | * Strip leading spaces: | 210 | * Strip leading spaces: |
| @@ -190,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
| 190 | line_ip = -1; | 225 | line_ip = -1; |
| 191 | } | 226 | } |
| 192 | 227 | ||
| 193 | start = map__rip_2objdump(he->map, sym->start); | ||
| 194 | |||
| 195 | if (line_ip != -1) { | 228 | if (line_ip != -1) { |
| 229 | u64 start = map__rip_2objdump(he->map, sym->start); | ||
| 230 | offset = line_ip - start; | ||
| 231 | } | ||
| 232 | |||
| 233 | objdump_line = objdump_line__new(offset, line); | ||
| 234 | if (objdump_line == NULL) { | ||
| 235 | free(line); | ||
| 236 | return -1; | ||
| 237 | } | ||
| 238 | objdump__add_line(head, objdump_line); | ||
| 239 | |||
| 240 | return 0; | ||
| 241 | } | ||
| 242 | |||
| 243 | static int objdump_line__print(struct objdump_line *self, | ||
| 244 | struct list_head *head, | ||
| 245 | struct hist_entry *he, u64 len) | ||
| 246 | { | ||
| 247 | struct symbol *sym = he->sym; | ||
| 248 | static const char *prev_line; | ||
| 249 | static const char *prev_color; | ||
| 250 | |||
| 251 | if (self->offset != -1) { | ||
| 196 | const char *path = NULL; | 252 | const char *path = NULL; |
| 197 | unsigned int hits = 0; | 253 | unsigned int hits = 0; |
| 198 | double percent = 0.0; | 254 | double percent = 0.0; |
| @@ -200,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
| 200 | struct sym_priv *priv = symbol__priv(sym); | 256 | struct sym_priv *priv = symbol__priv(sym); |
| 201 | struct sym_ext *sym_ext = priv->ext; | 257 | struct sym_ext *sym_ext = priv->ext; |
| 202 | struct sym_hist *h = priv->hist; | 258 | struct sym_hist *h = priv->hist; |
| 259 | s64 offset = self->offset; | ||
| 260 | struct objdump_line *next = objdump__get_next_ip_line(head, self); | ||
| 261 | |||
| 262 | while (offset < (s64)len && | ||
| 263 | (next == NULL || offset < next->offset)) { | ||
| 264 | if (sym_ext) { | ||
| 265 | if (path == NULL) | ||
| 266 | path = sym_ext[offset].path; | ||
| 267 | percent += sym_ext[offset].percent; | ||
| 268 | } else | ||
| 269 | hits += h->ip[offset]; | ||
| 270 | |||
| 271 | ++offset; | ||
| 272 | } | ||
| 203 | 273 | ||
| 204 | offset = line_ip - start; | 274 | if (sym_ext == NULL && h->sum) |
| 205 | if (offset < len) | ||
| 206 | hits = h->ip[offset]; | ||
| 207 | |||
| 208 | if (offset < len && sym_ext) { | ||
| 209 | path = sym_ext[offset].path; | ||
| 210 | percent = sym_ext[offset].percent; | ||
| 211 | } else if (h->sum) | ||
| 212 | percent = 100.0 * hits / h->sum; | 275 | percent = 100.0 * hits / h->sum; |
| 213 | 276 | ||
| 214 | color = get_percent_color(percent); | 277 | color = get_percent_color(percent); |
| @@ -229,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) | |||
| 229 | 292 | ||
| 230 | color_fprintf(stdout, color, " %7.2f", percent); | 293 | color_fprintf(stdout, color, " %7.2f", percent); |
| 231 | printf(" : "); | 294 | printf(" : "); |
| 232 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); | 295 | color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); |
| 233 | } else { | 296 | } else { |
| 234 | if (!*line) | 297 | if (!*self->line) |
| 235 | printf(" :\n"); | 298 | printf(" :\n"); |
| 236 | else | 299 | else |
| 237 | printf(" : %s\n", line); | 300 | printf(" : %s\n", self->line); |
| 238 | } | 301 | } |
| 239 | 302 | ||
| 240 | return 0; | 303 | return 0; |
| @@ -360,6 +423,20 @@ static void print_summary(const char *filename) | |||
| 360 | } | 423 | } |
| 361 | } | 424 | } |
| 362 | 425 | ||
| 426 | static void hist_entry__print_hits(struct hist_entry *self) | ||
| 427 | { | ||
| 428 | struct symbol *sym = self->sym; | ||
| 429 | struct sym_priv *priv = symbol__priv(sym); | ||
| 430 | struct sym_hist *h = priv->hist; | ||
| 431 | u64 len = sym->end - sym->start, offset; | ||
| 432 | |||
| 433 | for (offset = 0; offset < len; ++offset) | ||
| 434 | if (h->ip[offset] != 0) | ||
| 435 | printf("%*Lx: %Lu\n", BITS_PER_LONG / 2, | ||
| 436 | sym->start + offset, h->ip[offset]); | ||
| 437 | printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); | ||
| 438 | } | ||
| 439 | |||
| 363 | static void annotate_sym(struct hist_entry *he) | 440 | static void annotate_sym(struct hist_entry *he) |
| 364 | { | 441 | { |
| 365 | struct map *map = he->map; | 442 | struct map *map = he->map; |
| @@ -369,6 +446,8 @@ static void annotate_sym(struct hist_entry *he) | |||
| 369 | u64 len; | 446 | u64 len; |
| 370 | char command[PATH_MAX*2]; | 447 | char command[PATH_MAX*2]; |
| 371 | FILE *file; | 448 | FILE *file; |
| 449 | LIST_HEAD(head); | ||
| 450 | struct objdump_line *pos, *n; | ||
| 372 | 451 | ||
| 373 | if (!filename) | 452 | if (!filename) |
| 374 | return; | 453 | return; |
| @@ -410,11 +489,21 @@ static void annotate_sym(struct hist_entry *he) | |||
| 410 | return; | 489 | return; |
| 411 | 490 | ||
| 412 | while (!feof(file)) { | 491 | while (!feof(file)) { |
| 413 | if (parse_line(file, he, len) < 0) | 492 | if (parse_line(file, he, &head) < 0) |
| 414 | break; | 493 | break; |
| 415 | } | 494 | } |
| 416 | 495 | ||
| 417 | pclose(file); | 496 | pclose(file); |
| 497 | |||
| 498 | if (verbose) | ||
| 499 | hist_entry__print_hits(he); | ||
| 500 | |||
| 501 | list_for_each_entry_safe(pos, n, &head, node) { | ||
| 502 | objdump_line__print(pos, &head, he, len); | ||
| 503 | list_del(&pos->node); | ||
| 504 | objdump_line__free(pos); | ||
| 505 | } | ||
| 506 | |||
| 418 | if (print_line) | 507 | if (print_line) |
| 419 | free_source_line(he, len); | 508 | free_source_line(he, len); |
| 420 | } | 509 | } |
