Commit 5bbd6bad authored by Jin Yao's avatar Jin Yao Committed by Arnaldo Carvalho de Melo
Browse files

perf streams: Report hot streams



We show the streams separately. They are divided into different sections.

1. "Matched hot streams"

2. "Hot streams in old perf data only"

3. "Hot streams in new perf data only".

For each stream, we report the cycles and hot percent (hits%).

For example,

     cycles: 2, hits: 4.08%
 --------------------------
              main div.c:42
      compute_flag div.c:28

Signed-off-by: default avatarJin Yao <yao.jin@linux.intel.com>
Acked-by: default avatarJiri Olsa <jolsa@kernel.org>
Link: https://lore.kernel.org/r/20201009022845.13141-7-yao.jin@linux.intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 28904f4d
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -1699,3 +1699,16 @@ u64 callchain_total_hits(struct hists *hists)

	return chain_hits;
}

s64 callchain_avg_cycles(struct callchain_node *cnode)
{
	struct callchain_list *chain;
	s64 cycles = 0;

	list_for_each_entry(chain, &cnode->val, list) {
		if (chain->srcline && chain->branch_count)
			cycles += chain->cycles_count / chain->branch_count;
	}

	return cycles;
}
+2 −0
Original line number Diff line number Diff line
@@ -305,4 +305,6 @@ bool callchain_cnode_matched(struct callchain_node *base_cnode,

u64 callchain_total_hits(struct hists *hists);

s64 callchain_avg_cycles(struct callchain_node *cnode);

#endif	/* __PERF_CALLCHAIN_H */
+123 −0
Original line number Diff line number Diff line
@@ -217,3 +217,126 @@ void evsel_streams__match(struct evsel_streams *es_base,
			stream__link(base_stream, pair_stream);
	}
}

static void print_callchain_pair(struct stream *base_stream, int idx,
				 struct evsel_streams *es_base,
				 struct evsel_streams *es_pair)
{
	struct callchain_node *base_cnode = base_stream->cnode;
	struct callchain_node *pair_cnode = base_stream->pair_cnode;
	struct callchain_list *base_chain, *pair_chain;
	char buf1[512], buf2[512], cbuf1[256], cbuf2[256];
	char *s1, *s2;
	double pct;

	printf("\nhot chain pair %d:\n", idx);

	pct = (double)base_cnode->hit / (double)es_base->streams_hits;
	scnprintf(buf1, sizeof(buf1), "cycles: %ld, hits: %.2f%%",
		  callchain_avg_cycles(base_cnode), pct * 100.0);

	pct = (double)pair_cnode->hit / (double)es_pair->streams_hits;
	scnprintf(buf2, sizeof(buf2), "cycles: %ld, hits: %.2f%%",
		  callchain_avg_cycles(pair_cnode), pct * 100.0);

	printf("%35s\t%35s\n", buf1, buf2);

	printf("%35s\t%35s\n",
	       "---------------------------",
	       "--------------------------");

	pair_chain = list_first_entry(&pair_cnode->val,
				      struct callchain_list,
				      list);

	list_for_each_entry(base_chain, &base_cnode->val, list) {
		if (&pair_chain->list == &pair_cnode->val)
			return;

		s1 = callchain_list__sym_name(base_chain, cbuf1, sizeof(cbuf1),
					      false);
		s2 = callchain_list__sym_name(pair_chain, cbuf2, sizeof(cbuf2),
					      false);

		scnprintf(buf1, sizeof(buf1), "%35s\t%35s", s1, s2);
		printf("%s\n", buf1);
		pair_chain = list_next_entry(pair_chain, list);
	}
}

static void print_stream_callchain(struct stream *stream, int idx,
				   struct evsel_streams *es, bool pair)
{
	struct callchain_node *cnode = stream->cnode;
	struct callchain_list *chain;
	char buf[512], cbuf[256], *s;
	double pct;

	printf("\nhot chain %d:\n", idx);

	pct = (double)cnode->hit / (double)es->streams_hits;
	scnprintf(buf, sizeof(buf), "cycles: %ld, hits: %.2f%%",
		  callchain_avg_cycles(cnode), pct * 100.0);

	if (pair) {
		printf("%35s\t%35s\n", "", buf);
		printf("%35s\t%35s\n",
		       "", "--------------------------");
	} else {
		printf("%35s\n", buf);
		printf("%35s\n", "--------------------------");
	}

	list_for_each_entry(chain, &cnode->val, list) {
		s = callchain_list__sym_name(chain, cbuf, sizeof(cbuf), false);

		if (pair)
			scnprintf(buf, sizeof(buf), "%35s\t%35s", "", s);
		else
			scnprintf(buf, sizeof(buf), "%35s", s);

		printf("%s\n", buf);
	}
}

static void callchain_streams_report(struct evsel_streams *es_base,
				     struct evsel_streams *es_pair)
{
	struct stream *base_stream;
	int i, idx = 0;

	printf("[ Matched hot streams ]\n");
	for (i = 0; i < es_base->nr_streams; i++) {
		base_stream = &es_base->streams[i];
		if (base_stream->pair_cnode) {
			print_callchain_pair(base_stream, ++idx,
					     es_base, es_pair);
		}
	}

	idx = 0;
	printf("\n[ Hot streams in old perf data only ]\n");
	for (i = 0; i < es_base->nr_streams; i++) {
		base_stream = &es_base->streams[i];
		if (!base_stream->pair_cnode) {
			print_stream_callchain(base_stream, ++idx,
					       es_base, false);
		}
	}

	idx = 0;
	printf("\n[ Hot streams in new perf data only ]\n");
	for (i = 0; i < es_pair->nr_streams; i++) {
		base_stream = &es_pair->streams[i];
		if (!base_stream->pair_cnode) {
			print_stream_callchain(base_stream, ++idx,
					       es_pair, true);
		}
	}
}

void evsel_streams__report(struct evsel_streams *es_base,
			   struct evsel_streams *es_pair)
{
	return callchain_streams_report(es_base, es_pair);
}
+3 −0
Original line number Diff line number Diff line
@@ -35,4 +35,7 @@ struct evsel_streams *evsel_streams__entry(struct evlist_streams *els,
void evsel_streams__match(struct evsel_streams *es_base,
			  struct evsel_streams *es_pair);

void evsel_streams__report(struct evsel_streams *es_base,
			   struct evsel_streams *es_pair);

#endif /* __PERF_STREAM_H */