static int sym__alloc_hist(struct symbol *self) { struct sym_priv *priv = symbol__priv(self); const int size = (sizeof(*priv->hist) + (self->end - self->start) * sizeof(u64)); priv->hist = zalloc(size); return priv->hist == NULL ? -1 : 0; }
/* Get the filename:line for the colored entries */ static void get_source_line(struct hist_entry *he, int len, const char *filename) { struct symbol *sym = he->sym; u64 start; int i; char cmd[PATH_MAX * 2]; struct sym_ext *sym_ext; struct sym_priv *priv = symbol__priv(sym); struct sym_hist *h = priv->hist; if (!h->sum) return; sym_ext = priv->ext = calloc(len, sizeof(struct sym_ext)); if (!priv->ext) return; start = he->map->unmap_ip(he->map, sym->start); for (i = 0; i < len; i++) { char *path = NULL; size_t line_len; u64 offset; FILE *fp; sym_ext[i].percent = 100.0 * h->ip[i] / h->sum; if (sym_ext[i].percent <= 0.5) continue; offset = start + i; sprintf(cmd, "addr2line -e %s %016llx", filename, offset); fp = popen(cmd, "r"); if (!fp) continue; if (getline(&path, &line_len, fp) < 0 || !line_len) goto next; sym_ext[i].path = malloc(sizeof(char) * line_len + 1); if (!sym_ext[i].path) goto next; strcpy(sym_ext[i].path, path); insert_source_line(&sym_ext[i]); next: pclose(fp); } }
static void free_source_line(struct hist_entry *he, int len) { struct sym_priv *priv = symbol__priv(he->sym); struct sym_ext *sym_ext = priv->ext; int i; if (!sym_ext) return; for (i = 0; i < len; i++) free(sym_ext[i].path); free(sym_ext); priv->ext = NULL; root_sym_ext = RB_ROOT; }
/* * collect histogram counts */ static int annotate__hist_hit(struct hist_entry *he, u64 ip) { unsigned int sym_size, offset; struct symbol *sym = he->sym; struct sym_priv *priv; struct sym_hist *h; he->count++; if (!sym || !he->map) return 0; priv = symbol__priv(sym); if (priv->hist == NULL && sym__alloc_hist(sym) < 0) return -ENOMEM; sym_size = sym->end - sym->start; offset = ip - sym->start; if (verbose) fprintf(stderr, "%s: ip=%Lx\n", __func__, he->map->unmap_ip(he->map, ip)); if (offset >= sym_size) return 0; h = priv->hist; h->sum++; h->ip[offset]++; if (verbose >= 3) printf("%p %s: count++ [ip: %p, %08Lx] => %Ld\n", (void *)(unsigned long)he->sym->start, he->sym->name, (void *)(unsigned long)ip, ip - he->sym->start, h->ip[offset]); return 0; }
static void perf_session__find_annotations(struct perf_session *self) { struct rb_node *nd; for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) { struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node); struct sym_priv *priv; if (he->sym == NULL) continue; priv = symbol__priv(he->sym); if (priv->hist == NULL) continue; annotate_sym(he); /* * Since we have a hist_entry per IP for the same symbol, free * he->sym->hist to signal we already processed this symbol. */ free(priv->hist); priv->hist = NULL; } }
#include "util/cache.h" #include "util/debug.h" #include "util/debugfs.h" #include "util/evlist.h" #include "util/parse-options.h" #include "util/parse-events.h" #include "util/symbol.h" #include "util/thread_map.h" /* XXX There's no support for HW_BREAKPOINT in RHEL6 yet. #include "../../include/linux/hw_breakpoint.h" */ static int vmlinux_matches_kallsyms_filter(struct map *map __used, struct symbol *sym) { bool *visited = symbol__priv(sym); *visited = true; return 0; } static int test__vmlinux_matches_kallsyms(void) { int err = -1; struct rb_node *nd; struct symbol *sym; struct map *kallsyms_map, *vmlinux_map; struct machine kallsyms, vmlinux; enum map_type type = MAP__FUNCTION; long page_size = sysconf(_SC_PAGE_SIZE); struct ref_reloc_sym ref_reloc_sym = { .name = "_stext", };
static int parse_line(FILE *file, struct hist_entry *he, u64 len) { struct symbol *sym = he->sym; 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; char *c; if (getline(&line, &line_len, file) < 0) return -1; if (!line) return -1; c = strchr(line, '\n'); if (c) *c = 0; line_ip = -1; offset = 0; ret = -2; /* * Strip leading spaces: */ tmp = line; while (*tmp) { if (*tmp != ' ') break; tmp++; } if (*tmp) { /* * Parse hexa addresses followed by ':' */ line_ip = strtoull(tmp, &tmp2, 16); if (*tmp2 != ':') line_ip = -1; } start = he->map->unmap_ip(he->map, sym->start); if (line_ip != -1) { const char *path = NULL; unsigned int hits = 0; double percent = 0.0; const char *color; struct sym_priv *priv = symbol__priv(sym); struct sym_ext *sym_ext = priv->ext; struct sym_hist *h = priv->hist; 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) percent = 100.0 * hits / h->sum; color = get_percent_color(percent); /* * Also color the filename and line if needed, with * the same color than the percentage. Don't print it * twice for close colored ip with the same filename:line */ if (path) { if (!prev_line || strcmp(prev_line, path) || color != prev_color) { color_fprintf(stdout, color, " %s", path); prev_line = path; prev_color = color; } } color_fprintf(stdout, color, " %7.2f", percent); printf(" : "); color_fprintf(stdout, PERF_COLOR_BLUE, "%s\n", line); } else { if (!*line) printf(" :\n"); else printf(" : %s\n", line); } return 0; }