Commit 20d6f555 authored by Kan Liang's avatar Kan Liang Committed by Arnaldo Carvalho de Melo
Browse files

perf report: Display the branch counter histogram



Reusing the existing --total-cycles option to display the branch
counters. Add a new PERF_HPP_REPORT__BLOCK_BRANCH_COUNTER to display
the logged branch counter events. They are shown right after all the
cycle-related annotations.

Extend the 'struct block_info' to store and pass the branch counter
related information.

The annotation_br_cntr_entry() is to print the histogram of each branch
counter event. If the number of logged events is less than 4, the exact
number of the abbr name is printed. Otherwise, using '+' to stands for
more than 3 events.

Assume the number of logged events is less than 4.

The annotation_br_cntr_abbr_list() prints the branch counter's
abbreviation list. Press 'B' to display the list in the TUI mode.

  $ perf record -e "{branch-instructions:ppp,branch-misses}:S" -j any,counter
  $ perf report  --total-cycles --stdio

  # To display the perf.data header info, please use --header/--header-only options.
  #
  #
  # Total Lost Samples: 0
  #
  # Samples: 1M of events 'anon group { branch-instructions:ppp, branch-misses }'
  # Event count (approx.): 1610046
  #
  # Branch counter abbr list:
  # branch-instructions:ppp = A
  # branch-misses = B
  # '-' No event occurs
  # '+' Event occurrences may be lost due to branch counter saturated
  #
  # Sampled Cycles%  Sampled Cycles  Avg Cycles%  Avg Cycles  Branch Counter [Program Block Range]
  # ...............  ..............  ...........  ..........  ..............  ..................
  #
            57.55%            2.5M        0.00%           3     |A   |-   |                 ...
            25.27%            1.1M        0.00%           2     |AA  |-   |                 ...
            15.61%          667.2K        0.00%           1     |A   |-   |                 ...
             0.16%            6.9K        0.81%         575     |A   |-   |                 ...
             0.16%            6.8K        1.38%         977     |AA  |-   |                 ...
             0.16%            6.8K        0.04%          28     |AA  |B   |                 ...
             0.15%            6.6K        1.33%         946     |A   |-   |                 ...
             0.11%            4.5K        0.06%          46     |AAA+|-   |                 ...
             0.10%            4.4K        0.88%         624     |A   |-   |                 ...
             0.09%            3.7K        0.74%         524     |AAA+|B   |                 ...

With -v applied,

  # Sampled Cycles%  Sampled Cycles  Avg Cycles%  Avg Cycles  Branch Counter [Program Block Range]
  # ...............  ..............  ...........  ..........  ..............  ..................
  #
            57.55%            2.5M        0.00%           3       A=1 ,B=-                  ...
            25.27%            1.1M        0.00%           2       A=2 ,B=-                  ...
            15.61%          667.2K        0.00%           1       A=1 ,B=-                  ...
             0.16%            6.9K        0.81%         575       A=1 ,B=-                  ...
             0.16%            6.8K        1.38%         977       A=2 ,B=-                  ...
             0.16%            6.8K        0.04%          28       A=2 ,B=1                  ...
             0.15%            6.6K        1.33%         946       A=1 ,B=-                  ...
             0.11%            4.5K        0.06%          46       A=3+,B=-                  ...
             0.10%            4.4K        0.88%         624       A=1 ,B=-                  ...
             0.09%            3.7K        0.74%         524       A=3+,B=1                  ...

Reviewed-by: default avatarAndi Kleen <ak@linux.intel.com>
Signed-off-by: default avatarKan Liang <kan.liang@linux.intel.com>
Acked-by: default avatarNamhyung Kim <namhyung@kernel.org>
Cc: Adrian Hunter <adrian.hunter@intel.com>
Cc: Ian Rogers <irogers@google.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: https://lore.kernel.org/r/20240813160208.2493643-7-kan.liang@linux.intel.com


Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent 7398bf18
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -614,6 +614,7 @@ include::itrace.txt[]
	'Avg Cycles%'     - block average sampled cycles / sum of total block average
			    sampled cycles
	'Avg Cycles'      - block average sampled cycles
	'Branch Counter'  - block branch counter histogram (with -v showing the number)

--skip-empty::
	Do not print 0 results in the --stat output.
+2 −2
Original line number Diff line number Diff line
@@ -691,7 +691,7 @@ static void hists__precompute(struct hists *hists)
		if (compute == COMPUTE_CYCLES) {
			bh = container_of(he, struct block_hist, he);
			init_block_hist(bh);
			block_info__process_sym(he, bh, NULL, 0);
			block_info__process_sym(he, bh, NULL, 0, 0);
		}

		data__for_each_file_new(i, d) {
@@ -714,7 +714,7 @@ static void hists__precompute(struct hists *hists)
				pair_bh = container_of(pair, struct block_hist,
						       he);
				init_block_hist(pair_bh);
				block_info__process_sym(pair, pair_bh, NULL, 0);
				block_info__process_sym(pair, pair_bh, NULL, 0, 0);

				bh = container_of(he, struct block_hist, he);

+16 −4
Original line number Diff line number Diff line
@@ -575,6 +575,13 @@ static int evlist__tty_browse_hists(struct evlist *evlist, struct report *rep, c
		hists__fprintf_nr_sample_events(hists, rep, evname, stdout);

		if (rep->total_cycles_mode) {
			char *buf;

			if (!annotation_br_cntr_abbr_list(&buf, pos, true)) {
				fprintf(stdout, "%s", buf);
				fprintf(stdout, "#\n");
				free(buf);
			}
			report__browse_block_hists(&rep->block_reports[i - 1].hist,
						   rep->min_percent, pos, NULL);
			continue;
@@ -1119,18 +1126,23 @@ static int __cmd_report(struct report *rep)
	report__output_resort(rep);

	if (rep->total_cycles_mode) {
		int block_hpps[6] = {
		int nr_hpps = 4;
		int block_hpps[PERF_HPP_REPORT__BLOCK_MAX_INDEX] = {
			PERF_HPP_REPORT__BLOCK_TOTAL_CYCLES_PCT,
			PERF_HPP_REPORT__BLOCK_LBR_CYCLES,
			PERF_HPP_REPORT__BLOCK_CYCLES_PCT,
			PERF_HPP_REPORT__BLOCK_AVG_CYCLES,
			PERF_HPP_REPORT__BLOCK_RANGE,
			PERF_HPP_REPORT__BLOCK_DSO,
		};

		if (session->evlist->nr_br_cntr > 0)
			block_hpps[nr_hpps++] = PERF_HPP_REPORT__BLOCK_BRANCH_COUNTER;

		block_hpps[nr_hpps++] = PERF_HPP_REPORT__BLOCK_RANGE;
		block_hpps[nr_hpps++] = PERF_HPP_REPORT__BLOCK_DSO;

		rep->block_reports = block_info__create_report(session->evlist,
							       rep->total_cycles,
							       block_hpps, 6,
							       block_hpps, nr_hpps,
							       &rep->nr_block_reports);
		if (!rep->block_reports)
			return -1;
+16 −1
Original line number Diff line number Diff line
@@ -3684,8 +3684,10 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
	struct hist_browser *browser;
	int key = -1;
	struct popup_action action;
	char *br_cntr_text = NULL;
	static const char help[] =
	" q             Quit \n";
	" q             Quit \n"
	" B             Branch counter abbr list (Optional)\n";

	browser = hist_browser__new(hists);
	if (!browser)
@@ -3703,6 +3705,8 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,

	memset(&action, 0, sizeof(action));

	annotation_br_cntr_abbr_list(&br_cntr_text, evsel, false);

	while (1) {
		key = hist_browser__run(browser, "? - help", true, 0);

@@ -3723,6 +3727,16 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,
			action.ms.sym = browser->selection->sym;
			do_annotate(browser, &action);
			continue;
		case 'B':
			if (br_cntr_text) {
				ui__question_window("Branch counter abbr list",
						    br_cntr_text, "Press any key...", 0);
			} else {
				ui__question_window("Branch counter abbr list",
						    "\n The branch counter is not available.\n",
						    "Press any key...", 0);
			}
			continue;
		default:
			break;
		}
@@ -3730,5 +3744,6 @@ int block_hists_tui_browse(struct block_hist *bh, struct evsel *evsel,

out:
	hist_browser__delete(browser);
	free(br_cntr_text);
	return 0;
}
+145 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@
#include "namespaces.h"
#include "thread.h"
#include "hashmap.h"
#include "strbuf.h"
#include <regex.h>
#include <linux/bitops.h>
#include <linux/kernel.h>
@@ -48,6 +49,7 @@
#include <linux/zalloc.h>
#include <subcmd/parse-options.h>
#include <subcmd/run-command.h>
#include <math.h>

/* FIXME: For the HE_COLORSET */
#include "ui/browser.h"
@@ -1719,6 +1721,149 @@ static void ipc_coverage_string(char *bf, int size, struct annotation *notes)
		  ipc, coverage);
}

int annotation_br_cntr_abbr_list(char **str, struct evsel *evsel, bool header)
{
	struct evsel *pos;
	struct strbuf sb;

	if (evsel->evlist->nr_br_cntr <= 0)
		return -ENOTSUP;

	strbuf_init(&sb, /*hint=*/ 0);

	if (header && strbuf_addf(&sb, "# Branch counter abbr list:\n"))
		goto err;

	evlist__for_each_entry(evsel->evlist, pos) {
		if (!(pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS))
			continue;
		if (header && strbuf_addf(&sb, "#"))
			goto err;

		if (strbuf_addf(&sb, " %s = %s\n", pos->name, pos->abbr_name))
			goto err;
	}

	if (header && strbuf_addf(&sb, "#"))
		goto err;
	if (strbuf_addf(&sb, " '-' No event occurs\n"))
		goto err;

	if (header && strbuf_addf(&sb, "#"))
		goto err;
	if (strbuf_addf(&sb, " '+' Event occurrences may be lost due to branch counter saturated\n"))
		goto err;

	*str = strbuf_detach(&sb, NULL);

	return 0;
err:
	strbuf_release(&sb);
	return -ENOMEM;
}

/* Assume the branch counter saturated at 3 */
#define ANNOTATION_BR_CNTR_SATURATION		3

int annotation_br_cntr_entry(char **str, int br_cntr_nr,
			     u64 *br_cntr, int num_aggr,
			     struct evsel *evsel)
{
	struct evsel *pos = evsel ? evlist__first(evsel->evlist) : NULL;
	bool saturated = false;
	int i, j, avg, used;
	struct strbuf sb;

	strbuf_init(&sb, /*hint=*/ 0);
	for (i = 0; i < br_cntr_nr; i++) {
		used = 0;
		avg = ceil((double)(br_cntr[i] & ~ANNOTATION__BR_CNTR_SATURATED_FLAG) /
			   (double)num_aggr);

		/*
		 * A histogram with the abbr name is displayed by default.
		 * With -v, the exact number of branch counter is displayed.
		 */
		if (verbose) {
			evlist__for_each_entry_from(evsel->evlist, pos) {
				if ((pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) &&
				    (pos->br_cntr_idx == i))
				break;
			}
			if (strbuf_addstr(&sb, pos->abbr_name))
				goto err;

			if (!br_cntr[i]) {
				if (strbuf_addstr(&sb, "=-"))
					goto err;
			} else {
				if (strbuf_addf(&sb, "=%d", avg))
					goto err;
			}
			if (br_cntr[i] & ANNOTATION__BR_CNTR_SATURATED_FLAG) {
				if (strbuf_addch(&sb, '+'))
					goto err;
			} else {
				if (strbuf_addch(&sb, ' '))
					goto err;
			}

			if ((i < br_cntr_nr - 1) && strbuf_addch(&sb, ','))
				goto err;
			continue;
		}

		if (strbuf_addch(&sb, '|'))
			goto err;

		if (!br_cntr[i]) {
			if (strbuf_addch(&sb, '-'))
				goto err;
			used++;
		} else {
			evlist__for_each_entry_from(evsel->evlist, pos) {
				if ((pos->core.attr.branch_sample_type & PERF_SAMPLE_BRANCH_COUNTERS) &&
				    (pos->br_cntr_idx == i))
					break;
			}
			if (br_cntr[i] & ANNOTATION__BR_CNTR_SATURATED_FLAG)
				saturated = true;

			for (j = 0; j < avg; j++, used++) {
				/* Print + if the number of logged events > 3 */
				if (j >= ANNOTATION_BR_CNTR_SATURATION) {
					saturated = true;
					break;
				}
				if (strbuf_addstr(&sb, pos->abbr_name))
					goto err;
			}

			if (saturated) {
				if (strbuf_addch(&sb, '+'))
					goto err;
				used++;
			}
			pos = list_next_entry(pos, core.node);
		}

		for (j = used; j < ANNOTATION_BR_CNTR_SATURATION + 1; j++) {
			if (strbuf_addch(&sb, ' '))
				goto err;
		}
	}

	if (!verbose && strbuf_addch(&sb, br_cntr_nr ? '|' : ' '))
		goto err;

	*str = strbuf_detach(&sb, NULL);

	return 0;
err:
	strbuf_release(&sb);
	return -ENOMEM;
}

static void __annotation_line__write(struct annotation_line *al, struct annotation *notes,
				     bool first_line, bool current_entry, bool change_color, int width,
				     void *obj, unsigned int percent_type,
Loading