Skip to content
Snippets Groups Projects
annotate.c 32.1 KiB
Newer Older
  • Learn to ignore specific revisions
  • 	for (i = 0; i < src_line->nr_pcnt; i++)
    		src_line->p[i].percent_sum = src_line->p[i].percent;
    
    
    	rb_link_node(&src_line->node, parent, p);
    	rb_insert_color(&src_line->node, root);
    }
    
    
    static int cmp_source_line(struct source_line *a, struct source_line *b)
    {
    	int i;
    
    	for (i = 0; i < a->nr_pcnt; i++) {
    		if (a->p[i].percent_sum == b->p[i].percent_sum)
    			continue;
    		return a->p[i].percent_sum > b->p[i].percent_sum;
    	}
    
    	return 0;
    }
    
    
    static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
    {
    	struct source_line *iter;
    	struct rb_node **p = &root->rb_node;
    	struct rb_node *parent = NULL;
    
    	while (*p != NULL) {
    		parent = *p;
    		iter = rb_entry(parent, struct source_line, node);
    
    
    		if (cmp_source_line(src_line, iter))
    
    			p = &(*p)->rb_left;
    		else
    			p = &(*p)->rb_right;
    	}
    
    	rb_link_node(&src_line->node, parent, p);
    	rb_insert_color(&src_line->node, root);
    }
    
    
    static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
    {
    	struct source_line *src_line;
    	struct rb_node *node;
    
    	node = rb_first(src_root);
    	while (node) {
    		struct rb_node *next;
    
    		src_line = rb_entry(node, struct source_line, node);
    		next = rb_next(node);
    		rb_erase(node, src_root);
    
    		__resort_source_line(dest_root, src_line);
    		node = next;
    	}
    }
    
    
    static void symbol__free_source_line(struct symbol *sym, int len)
    {
    	struct annotation *notes = symbol__annotation(sym);
    
    	struct source_line *src_line = notes->src->lines;
    
    	sizeof_src_line = sizeof(*src_line) +
    			  (sizeof(src_line->p) * (src_line->nr_pcnt - 1));
    
    	for (i = 0; i < len; i++) {
    		free(src_line->path);
    		src_line = (void *)src_line + sizeof_src_line;
    	}
    
    	free(notes->src->lines);
    
    }
    
    /* Get the filename:line for the colored entries */
    static int symbol__get_source_line(struct symbol *sym, struct map *map,
    
    				   struct perf_evsel *evsel,
    				   struct rb_root *root, int len,
    
    	int i, k;
    	int evidx = evsel->idx;
    
    	char cmd[PATH_MAX * 2];
    	struct source_line *src_line;
    	struct annotation *notes = symbol__annotation(sym);
    
    	struct sym_hist *h = annotation__histogram(notes, evidx);
    
    	struct rb_root tmp_root = RB_ROOT;
    
    	int nr_pcnt = 1;
    	u64 h_sum = h->sum;
    	size_t sizeof_src_line = sizeof(struct source_line);
    
    	if (perf_evsel__is_group_event(evsel)) {
    		for (i = 1; i < evsel->nr_members; i++) {
    			h = annotation__histogram(notes, evidx + i);
    			h_sum += h->sum;
    		}
    		nr_pcnt = evsel->nr_members;
    		sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->p);
    	}
    
    	src_line = notes->src->lines = calloc(len, sizeof_src_line);
    
    	start = map__rip_2objdump(map, sym->start);
    
    
    	for (i = 0; i < len; i++) {
    		char *path = NULL;
    		size_t line_len;
    		u64 offset;
    		FILE *fp;
    
    		double percent_max = 0.0;
    
    		src_line->nr_pcnt = nr_pcnt;
    
    		for (k = 0; k < nr_pcnt; k++) {
    			h = annotation__histogram(notes, evidx + k);
    			src_line->p[k].percent = 100.0 * h->addr[i] / h->sum;
    
    			if (src_line->p[k].percent > percent_max)
    				percent_max = src_line->p[k].percent;
    		}
    
    		if (percent_max <= 0.5)
    			goto next;
    
    
    		offset = start + i;
    		sprintf(cmd, "addr2line -e %s %016" PRIx64, filename, offset);
    		fp = popen(cmd, "r");
    		if (!fp)
    
    
    		if (getline(&path, &line_len, fp) < 0 || !line_len)
    
    		src_line->path = malloc(sizeof(char) * line_len + 1);
    		if (!src_line->path)
    			goto next_close;
    
    		strcpy(src_line->path, path);
    		insert_source_line(&tmp_root, src_line);
    
    	next:
    		src_line = (void *)src_line + sizeof_src_line;
    
    	resort_source_line(root, &tmp_root);
    
    	return 0;
    }
    
    static void print_summary(struct rb_root *root, const char *filename)
    {
    	struct source_line *src_line;
    	struct rb_node *node;
    
    	printf("\nSorted summary for file %s\n", filename);
    	printf("----------------------------------------------\n\n");
    
    	if (RB_EMPTY_ROOT(root)) {
    		printf(" Nothing higher than %1.1f%%\n", MIN_GREEN);
    		return;
    	}
    
    	node = rb_first(root);
    	while (node) {
    
    		double percent, percent_max = 0.0;
    
    
    		src_line = rb_entry(node, struct source_line, node);
    
    		for (i = 0; i < src_line->nr_pcnt; i++) {
    			percent = src_line->p[i].percent_sum;
    			color = get_percent_color(percent);
    			color_fprintf(stdout, color, " %7.2f", percent);
    
    			if (percent > percent_max)
    				percent_max = percent;
    		}
    
    
    		color = get_percent_color(percent_max);
    		color_fprintf(stdout, color, " %s", path);
    
    static void symbol__annotate_hits(struct symbol *sym, struct perf_evsel *evsel)
    
    {
    	struct annotation *notes = symbol__annotation(sym);
    
    	struct sym_hist *h = annotation__histogram(notes, evsel->idx);
    
    	u64 len = symbol__size(sym), offset;
    
    
    	for (offset = 0; offset < len; ++offset)
    		if (h->addr[offset] != 0)
    			printf("%*" PRIx64 ": %" PRIu64 "\n", BITS_PER_LONG / 2,
    			       sym->start + offset, h->addr[offset]);
    	printf("%*s: %" PRIu64 "\n", BITS_PER_LONG / 2, "h->sum", h->sum);
    }
    
    
    int symbol__annotate_printf(struct symbol *sym, struct map *map,
    			    struct perf_evsel *evsel, bool full_paths,
    			    int min_pcnt, int max_lines, int context)
    
    	char *filename;
    	const char *d_filename;
    
    	struct annotation *notes = symbol__annotation(sym);
    
    	struct disasm_line *pos, *queue = NULL;
    
    	u64 start = map__rip_2objdump(map, sym->start);
    
    	int printed = 2, queue_len = 0;
    
    	int width = 8;
    	int namelen;
    
    	filename = strdup(dso->long_name);
    	if (!filename)
    		return -ENOMEM;
    
    
    	if (full_paths)
    		d_filename = filename;
    	else
    		d_filename = basename(filename);
    
    
    	len = symbol__size(sym);
    
    	namelen = strlen(d_filename);
    
    
    	if (perf_evsel__is_group_event(evsel))
    
    		width *= evsel->nr_members;
    
    	printf(" %-*.*s|	Source code & Disassembly of %s\n",
    	       width, width, "Percent", d_filename);
    	printf("-%-*.*s-------------------------------------\n",
    	       width+namelen, width+namelen, graph_dotted_line);
    
    		symbol__annotate_hits(sym, evsel);
    
    	list_for_each_entry(pos, &notes->src->source, node) {
    
    		if (context && queue == NULL) {
    			queue = pos;
    			queue_len = 0;
    		}
    
    
    		switch (disasm_line__print(pos, sym, start, evsel, len,
    
    			if (context) {
    				printed += queue_len;
    				queue = NULL;
    				queue_len = 0;
    			}
    
    			/*
    			 * Filtered by min_pcnt or non IP lines when
    			 * context != 0
    			 */
    			if (!context)
    				break;
    			if (queue_len == context)
    				queue = list_entry(queue->node.next, typeof(*queue), node);
    			else
    				++queue_len;
    
    void symbol__annotate_zero_histogram(struct symbol *sym, int evidx)
    {
    	struct annotation *notes = symbol__annotation(sym);
    	struct sym_hist *h = annotation__histogram(notes, evidx);
    
    
    	memset(h, 0, notes->src->sizeof_sym_hist);
    
    void symbol__annotate_decay_histogram(struct symbol *sym, int evidx)
    
    {
    	struct annotation *notes = symbol__annotation(sym);
    	struct sym_hist *h = annotation__histogram(notes, evidx);
    
    	int len = symbol__size(sym), offset;
    
    	for (offset = 0; offset < len; ++offset) {
    		h->addr[offset] = h->addr[offset] * 7 / 8;
    		h->sum += h->addr[offset];
    
    void disasm__purge(struct list_head *head)
    
    	struct disasm_line *pos, *n;
    
    
    	list_for_each_entry_safe(pos, n, head, node) {
    		list_del(&pos->node);
    
    static size_t disasm_line__fprintf(struct disasm_line *dl, FILE *fp)
    {
    	size_t printed;
    
    	if (dl->offset == -1)
    		return fprintf(fp, "%s\n", dl->line);
    
    	printed = fprintf(fp, "%#" PRIx64 " %s", dl->offset, dl->name);
    
    
    	if (dl->ops.raw[0] != '\0') {
    
    		printed += fprintf(fp, "%.*s %s\n", 6 - (int)printed, " ",
    
    	}
    
    	return printed + fprintf(fp, "\n");
    }
    
    size_t disasm__fprintf(struct list_head *head, FILE *fp)
    {
    	struct disasm_line *pos;
    	size_t printed = 0;
    
    	list_for_each_entry(pos, head, node)
    		printed += disasm_line__fprintf(pos, fp);
    
    	return printed;
    }
    
    
    int symbol__tty_annotate(struct symbol *sym, struct map *map,
    			 struct perf_evsel *evsel, bool print_lines,
    			 bool full_paths, int min_pcnt, int max_lines)
    
    {
    	struct dso *dso = map->dso;
    	const char *filename = dso->long_name;
    	struct rb_root source_line = RB_ROOT;
    	u64 len;
    
    
    	if (symbol__annotate(sym, map, 0) < 0)
    
    	len = symbol__size(sym);
    
    		symbol__get_source_line(sym, map, evsel, &source_line,
    
    					len, filename);
    		print_summary(&source_line, filename);
    
    	symbol__annotate_printf(sym, map, evsel, full_paths,
    
    	if (print_lines)
    		symbol__free_source_line(sym, len);
    
    
    	disasm__purge(&symbol__annotation(sym)->src->source);