Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8b4c74dc authored by Jiri Olsa's avatar Jiri Olsa Committed by Arnaldo Carvalho de Melo
Browse files

perf annotate: Add symbol__calc_lines function



Replace symbol__get_source_line() with symbol__calc_lines(), which
calculates the source line tree over the struct annotation_line.

This will allow us to remove redundant struct source_line in following
patches.

Signed-off-by: default avatarJiri Olsa <jolsa@kernel.org>
Cc: Andi Kleen <andi@firstfloor.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Namhyung Kim <namhyung@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Link: http://lkml.kernel.org/r/20171011150158.11895-19-jolsa@kernel.org


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 073ae601
Loading
Loading
Loading
Loading
+66 −120
Original line number Diff line number Diff line
@@ -892,6 +892,7 @@ static void annotation_line__delete(struct annotation_line *al)
{
	void *ptr = (void *) al - al->privsize;

	free_srcline(al->path);
	zfree(&al->line);
	free(ptr);
}
@@ -1726,21 +1727,21 @@ int symbol__annotate(struct symbol *sym, struct map *map,
	return symbol__calc_percent(sym, evsel);
}

static void insert_source_line(struct rb_root *root, struct source_line *src_line)
static void insert_source_line(struct rb_root *root, struct annotation_line *al)
{
	struct source_line *iter;
	struct annotation_line *iter;
	struct rb_node **p = &root->rb_node;
	struct rb_node *parent = NULL;
	int i, ret;

	while (*p != NULL) {
		parent = *p;
		iter = rb_entry(parent, struct source_line, node);
		iter = rb_entry(parent, struct annotation_line, rb_node);

		ret = strcmp(iter->path, src_line->path);
		ret = strcmp(iter->path, al->path);
		if (ret == 0) {
			for (i = 0; i < src_line->nr_pcnt; i++)
				iter->samples[i].percent_sum += src_line->samples[i].percent;
			for (i = 0; i < al->samples_nr; i++)
				iter->samples[i].percent_sum += al->samples[i].percent;
			return;
		}

@@ -1750,18 +1751,18 @@ static void insert_source_line(struct rb_root *root, struct source_line *src_lin
			p = &(*p)->rb_right;
	}

	for (i = 0; i < src_line->nr_pcnt; i++)
		src_line->samples[i].percent_sum = src_line->samples[i].percent;
	for (i = 0; i < al->samples_nr; i++)
		al->samples[i].percent_sum = al->samples[i].percent;

	rb_link_node(&src_line->node, parent, p);
	rb_insert_color(&src_line->node, root);
	rb_link_node(&al->rb_node, parent, p);
	rb_insert_color(&al->rb_node, root);
}

static int cmp_source_line(struct source_line *a, struct source_line *b)
static int cmp_source_line(struct annotation_line *a, struct annotation_line *b)
{
	int i;

	for (i = 0; i < a->nr_pcnt; i++) {
	for (i = 0; i < a->samples_nr; i++) {
		if (a->samples[i].percent_sum == b->samples[i].percent_sum)
			continue;
		return a->samples[i].percent_sum > b->samples[i].percent_sum;
@@ -1770,135 +1771,47 @@ static int cmp_source_line(struct source_line *a, struct source_line *b)
	return 0;
}

static void __resort_source_line(struct rb_root *root, struct source_line *src_line)
static void __resort_source_line(struct rb_root *root, struct annotation_line *al)
{
	struct source_line *iter;
	struct annotation_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);
		iter = rb_entry(parent, struct annotation_line, rb_node);

		if (cmp_source_line(src_line, iter))
		if (cmp_source_line(al, 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);
	rb_link_node(&al->rb_node, parent, p);
	rb_insert_color(&al->rb_node, root);
}

static void resort_source_line(struct rb_root *dest_root, struct rb_root *src_root)
{
	struct source_line *src_line;
	struct annotation_line *al;
	struct rb_node *node;

	node = rb_first(src_root);
	while (node) {
		struct rb_node *next;

		src_line = rb_entry(node, struct source_line, node);
		al = rb_entry(node, struct annotation_line, rb_node);
		next = rb_next(node);
		rb_erase(node, src_root);

		__resort_source_line(dest_root, src_line);
		__resort_source_line(dest_root, al);
		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;
	size_t sizeof_src_line;
	int i;

	sizeof_src_line = sizeof(*src_line) +
			  (sizeof(src_line->samples) * (src_line->nr_pcnt - 1));

	for (i = 0; i < len; i++) {
		free_srcline(src_line->path);
		src_line = (void *)src_line + sizeof_src_line;
	}

	zfree(&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)
{
	u64 start;
	int i, k;
	int evidx = evsel->idx;
	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 nr_samples = h->nr_samples;
	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);
			nr_samples += h->nr_samples;
		}
		nr_pcnt = evsel->nr_members;
		sizeof_src_line += (nr_pcnt - 1) * sizeof(src_line->samples);
	}

	if (!nr_samples)
		return 0;

	src_line = notes->src->lines = calloc(len, sizeof_src_line);
	if (!notes->src->lines)
		return -1;

	start = map__rip_2objdump(map, sym->start);

	for (i = 0; i < len; i++) {
		u64 offset;
		double percent_max = 0.0;

		src_line->nr_pcnt = nr_pcnt;

		for (k = 0; k < nr_pcnt; k++) {
			double percent = 0.0;

			h = annotation__histogram(notes, evidx + k);
			nr_samples = h->addr[i].nr_samples;
			if (h->nr_samples)
				percent = 100.0 * nr_samples / h->nr_samples;

			if (percent > percent_max)
				percent_max = percent;
			src_line->samples[k].percent = percent;
			src_line->samples[k].nr = nr_samples;
		}

		if (percent_max <= 0.5)
			goto next;

		offset = start + i;
		src_line->path = get_srcline(map->dso, offset, NULL,
					     false, true);
		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 annotation_line *al;
	struct rb_node *node;

	printf("\nSorted summary for file %s\n", filename);
@@ -1916,9 +1829,9 @@ static void print_summary(struct rb_root *root, const char *filename)
		char *path;
		int i;

		src_line = rb_entry(node, struct source_line, node);
		for (i = 0; i < src_line->nr_pcnt; i++) {
			percent = src_line->samples[i].percent_sum;
		al = rb_entry(node, struct annotation_line, rb_node);
		for (i = 0; i < al->samples_nr; i++) {
			percent = al->samples[i].percent_sum;
			color = get_percent_color(percent);
			color_fprintf(stdout, color, " %7.2f", percent);

@@ -1926,7 +1839,7 @@ static void print_summary(struct rb_root *root, const char *filename)
				percent_max = percent;
		}

		path = src_line->path;
		path = al->path;
		color = get_percent_color(percent_max);
		color_fprintf(stdout, color, " %s\n", path);

@@ -2091,29 +2004,62 @@ size_t disasm__fprintf(struct list_head *head, FILE *fp)
	return printed;
}

static void annotation__calc_lines(struct annotation *notes, struct map *map,
				  struct rb_root *root, u64 start)
{
	struct annotation_line *al;
	struct rb_root tmp_root = RB_ROOT;

	list_for_each_entry(al, &notes->src->source, node) {
		double percent_max = 0.0;
		int i;

		for (i = 0; i < al->samples_nr; i++) {
			struct annotation_data *sample;

			sample = &al->samples[i];

			if (sample->percent > percent_max)
				percent_max = sample->percent;
		}

		if (percent_max <= 0.5)
			continue;

		al->path = get_srcline(map->dso, start + al->offset, NULL, false, true);
		insert_source_line(&tmp_root, al);
	}

	resort_source_line(root, &tmp_root);
}

static void symbol__calc_lines(struct symbol *sym, struct map *map,
			      struct rb_root *root)
{
	struct annotation *notes = symbol__annotation(sym);
	u64 start = map__rip_2objdump(map, sym->start);

	annotation__calc_lines(notes, map, root, start);
}

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;
	struct rb_root source_line = RB_ROOT;
	u64 len;

	if (symbol__annotate(sym, map, evsel, 0, NULL, NULL) < 0)
		return -1;

	len = symbol__size(sym);

	if (print_lines) {
		srcline_full_filename = full_paths;
		symbol__get_source_line(sym, map, evsel, &source_line, len);
		symbol__calc_lines(sym, map, &source_line);
		print_summary(&source_line, dso->long_name);
	}

	symbol__annotate_printf(sym, map, evsel, full_paths,
				min_pcnt, max_lines, 0);
	if (print_lines)
		symbol__free_source_line(sym, len);

	annotated_source__purge(symbol__annotation(sym)->src);

+2 −0
Original line number Diff line number Diff line
@@ -66,6 +66,7 @@ struct sym_hist_entry {

struct annotation_data {
	double			 percent;
	double			 percent_sum;
	struct sym_hist_entry	 he;
};

@@ -78,6 +79,7 @@ struct annotation_line {
	float			 ipc;
	u64			 cycles;
	size_t			 privsize;
	char			*path;
	int			 samples_nr;
	struct annotation_data	 samples[0];
};