diff options
Diffstat (limited to 'tools')
-rw-r--r-- | tools/perf/builtin-annotate.c | 135 | ||||
-rw-r--r-- | tools/perf/builtin-top.c | 2 | ||||
-rw-r--r-- | tools/perf/util/event.c | 4 | ||||
-rw-r--r-- | tools/perf/util/probe-event.c | 3 | ||||
-rw-r--r-- | tools/perf/util/thread.c | 34 |
5 files changed, 148 insertions, 30 deletions
diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c index e47dd1587e3..5ec5de99587 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) return 0; } -static int parse_line(FILE *file, struct hist_entry *he, u64 len) +struct objdump_line { + struct list_head node; + s64 offset; + char *line; +}; + +static struct objdump_line *objdump_line__new(s64 offset, char *line) +{ + struct objdump_line *self = malloc(sizeof(*self)); + + if (self != NULL) { + self->offset = offset; + self->line = line; + } + + return self; +} + +static void objdump_line__free(struct objdump_line *self) +{ + free(self->line); + free(self); +} + +static void objdump__add_line(struct list_head *head, struct objdump_line *line) +{ + list_add_tail(&line->node, head); +} + +static struct objdump_line *objdump__get_next_ip_line(struct list_head *head, + struct objdump_line *pos) +{ + list_for_each_entry_continue(pos, head, node) + if (pos->offset >= 0) + return pos; + + return NULL; +} + +static int parse_line(FILE *file, struct hist_entry *he, + struct list_head *head) { struct symbol *sym = he->sym; + struct objdump_line *objdump_line; char *line = NULL, *tmp, *tmp2; - static const char *prev_line; - static const char *prev_color; - unsigned int offset; size_t line_len; - u64 start; - s64 line_ip; - int ret; + s64 line_ip, offset = -1; char *c; if (getline(&line, &line_len, file) < 0) return -1; + if (!line) return -1; @@ -168,8 +205,6 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) *c = 0; line_ip = -1; - offset = 0; - ret = -2; /* * Strip leading spaces: @@ -190,9 +225,30 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) line_ip = -1; } - start = map__rip_2objdump(he->map, sym->start); - if (line_ip != -1) { + u64 start = map__rip_2objdump(he->map, sym->start); + offset = line_ip - start; + } + + objdump_line = objdump_line__new(offset, line); + if (objdump_line == NULL) { + free(line); + return -1; + } + objdump__add_line(head, objdump_line); + + return 0; +} + +static int objdump_line__print(struct objdump_line *self, + struct list_head *head, + struct hist_entry *he, u64 len) +{ + struct symbol *sym = he->sym; + static const char *prev_line; + static const char *prev_color; + + if (self->offset != -1) { const char *path = NULL; unsigned int hits = 0; double percent = 0.0; @@ -200,15 +256,22 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) struct sym_priv *priv = symbol__priv(sym); struct sym_ext *sym_ext = priv->ext; struct sym_hist *h = priv->hist; + s64 offset = self->offset; + struct objdump_line *next = objdump__get_next_ip_line(head, self); + + while (offset < (s64)len && + (next == NULL || offset < next->offset)) { + if (sym_ext) { + if (path == NULL) + path = sym_ext[offset].path; + percent += sym_ext[offset].percent; + } else + hits += h->ip[offset]; + + ++offset; + } - offset = line_ip - start; - if (offset < len) - hits = h->ip[offset]; - - if (offset < len && sym_ext) { - path = sym_ext[offset].path; - percent = sym_ext[offset].percent; - } else if (h->sum) + if (sym_ext == NULL && h->sum) percent = 100.0 * hits / h->sum; color = get_percent_color(percent); @@ -229,12 +292,12 @@ static int parse_line(FILE *file, struct hist_entry *he, u64 len) color_fprintf(stdout, color, " %7.2f", percent); printf(" : "); - color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); + color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", self->line); } else { - if (!*line) + if (!*self->line) printf(" :\n"); else - printf(" : %s\n", line); + printf(" : %s\n", self->line); } return 0; @@ -360,6 +423,20 @@ static void print_summary(const char *filename) } } +static void hist_entry__print_hits(struct hist_entry *self) +{ + struct symbol *sym = self->sym; + struct sym_priv *priv = symbol__priv(sym); + struct sym_hist *h = priv->hist; + u64 len = sym->end - sym->start, offset; + + for (offset = 0; offset < len; ++offset) + if (h->ip[offset] != 0) + printf("%*Lx: %Lu\n", BITS_PER_LONG / 2, + sym->start + offset, h->ip[offset]); + printf("%*s: %Lu\n", BITS_PER_LONG / 2, "h->sum", h->sum); +} + static void annotate_sym(struct hist_entry *he) { struct map *map = he->map; @@ -369,6 +446,8 @@ static void annotate_sym(struct hist_entry *he) u64 len; char command[PATH_MAX*2]; FILE *file; + LIST_HEAD(head); + struct objdump_line *pos, *n; if (!filename) return; @@ -410,11 +489,21 @@ static void annotate_sym(struct hist_entry *he) return; while (!feof(file)) { - if (parse_line(file, he, len) < 0) + if (parse_line(file, he, &head) < 0) break; } pclose(file); + + if (verbose) + hist_entry__print_hits(he); + + list_for_each_entry_safe(pos, n, &head, node) { + objdump_line__print(pos, &head, he, len); + list_del(&pos->node); + objdump_line__free(pos); + } + if (print_line) free_source_line(he, len); } diff --git a/tools/perf/builtin-top.c b/tools/perf/builtin-top.c index c6706984b7b..31f2e597800 100644 --- a/tools/perf/builtin-top.c +++ b/tools/perf/builtin-top.c @@ -706,7 +706,7 @@ static void print_mapped_keys(void) fprintf(stdout, "\t[w] toggle display weighted/count[E]r. \t(%d)\n", display_weighted ? 1 : 0); fprintf(stdout, - "\t[K] hide kernel_symbols symbols. \t(%s)\n", + "\t[K] hide kernel_symbols symbols. \t(%s)\n", hide_kernel_symbols ? "yes" : "no"); fprintf(stdout, "\t[U] hide user symbols. \t(%s)\n", diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c index 9eb7005bc6d..705ec63548b 100644 --- a/tools/perf/util/event.c +++ b/tools/perf/util/event.c @@ -442,10 +442,10 @@ void thread__find_addr_map(struct thread *self, al->thread = self; al->addr = addr; - if (cpumode & PERF_RECORD_MISC_KERNEL) { + if (cpumode == PERF_RECORD_MISC_KERNEL) { al->level = 'k'; mg = &session->kmaps; - } else if (cpumode & PERF_RECORD_MISC_USER) + } else if (cpumode == PERF_RECORD_MISC_USER) al->level = '.'; else { al->level = 'H'; diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c index fa156f008e0..c971e81e9cb 100644 --- a/tools/perf/util/probe-event.c +++ b/tools/perf/util/probe-event.c @@ -320,6 +320,7 @@ int synthesize_perf_probe_point(struct probe_point *pp) int ret; pp->probes[0] = buf = zalloc(MAX_CMDLEN); + pp->found = 1; if (!buf) die("Failed to allocate memory by zalloc."); if (pp->offset) { @@ -342,6 +343,7 @@ int synthesize_perf_probe_point(struct probe_point *pp) error: free(pp->probes[0]); pp->probes[0] = NULL; + pp->found = 0; } return ret; } @@ -507,6 +509,7 @@ void show_perf_probe_events(void) setup_pager(); + memset(&pp, 0, sizeof(pp)); fd = open_kprobe_events(O_RDONLY, 0); rawlist = get_trace_kprobe_event_rawlist(fd); close(fd); diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c index c090654cb6c..21b92162282 100644 --- a/tools/perf/util/thread.c +++ b/tools/perf/util/thread.c @@ -31,15 +31,41 @@ static struct thread *thread__new(pid_t pid) return self; } +static void map_groups__flush(struct map_groups *self) +{ + int type; + + for (type = 0; type < MAP__NR_TYPES; type++) { + struct rb_root *root = &self->maps[type]; + struct rb_node *next = rb_first(root); + + while (next) { + struct map *pos = rb_entry(next, struct map, rb_node); + next = rb_next(&pos->rb_node); + rb_erase(&pos->rb_node, root); + /* + * We may have references to this map, for + * instance in some hist_entry instances, so + * just move them to a separate list. + */ + list_add_tail(&pos->node, &self->removed_maps[pos->type]); + } + } +} + int thread__set_comm(struct thread *self, const char *comm) { + int err; + if (self->comm) free(self->comm); self->comm = strdup(comm); - if (self->comm == NULL) - return -ENOMEM; - self->comm_set = true; - return 0; + err = self->comm == NULL ? -ENOMEM : 0; + if (!err) { + self->comm_set = true; + map_groups__flush(&self->mg); + } + return err; } int thread__comm_len(struct thread *self) |