All of lore.kernel.org
 help / color / mirror / Atom feed
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
Cc: eranian@google.com, peterz@infradead.org, mpe@ellerman.id.au,
	paulus@samba.org, mingo@redhat.com, acme@kernel.org,
	mark.rutland@arm.com, alexander.shishkin@linux.intel.com,
	jolsa@redhat.com, namhyung@kernel.org, adrian.hunter@intel.com,
	ak@linux.intel.com, kan.liang@linux.intel.com,
	alexey.budankov@linux.intel.com, yao.jin@linux.intel.com,
	robert.richter@amd.com, kim.phillips@amd.com,
	maddy@linux.ibm.com, ravi.bangoria@linux.ibm.com
Subject: [RFC 11/11] perf annotate: Show hazard data in tui mode
Date: Mon,  2 Mar 2020 10:53:55 +0530	[thread overview]
Message-ID: <20200302052355.36365-12-ravi.bangoria@linux.ibm.com> (raw)
In-Reply-To: <20200302052355.36365-1-ravi.bangoria@linux.ibm.com>

Enable perf report->annotate tui mode to show hazard information. By
default they are hidden, but user can unhide them by pressing hot key
'S'. Sample o/p:

         │    Disassembly of section .text:
         │
         │    0000000010001cf8 <compare>:
         │    compare():
         │    return NULL;
         │    }
         │
         │    static int
         │    compare(const void *p1, const void *p2)
         │    {
   33.23 │      std    r31,-8(r1)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: Load Hit Store, stall_stage: LSU, stall_reason: -, icache: L3 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: -, stall_reason: -, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
    0.84 │      stdu   r1,-64(r1)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: -, stall_reason: -, icache: L1 hit}
    0.24 │      mr     r31,r1
         │       {haz_stage: -, haz_reason: -, stall_stage: -, stall_reason: -, icache: L1 hit}
   21.18 │      std    r3,32(r31)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
 tools/perf/builtin-annotate.c     |   5 ++
 tools/perf/ui/browsers/annotate.c | 124 ++++++++++++++++++++++++++----
 tools/perf/util/annotate.c        |  51 +++++++++++-
 tools/perf/util/annotate.h        |  18 ++++-
 4 files changed, 178 insertions(+), 20 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 78552a9428a6..a51313a6b019 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -472,6 +472,7 @@ static const char * const annotate_usage[] = {
 
 int cmd_annotate(int argc, const char **argv)
 {
+	bool annotate_haz = false;
 	struct perf_annotate annotate = {
 		.tool = {
 			.sample	= process_sample_event,
@@ -531,6 +532,8 @@ int cmd_annotate(int argc, const char **argv)
 		     symbol__config_symfs),
 	OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,
 		    "Interleave source code with assembly code (default)"),
+	OPT_BOOLEAN(0, "hazard", &annotate_haz,
+		    "Interleave CPU pileline hazard/stall data with assembly code"),
 	OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw,
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style",
@@ -583,6 +586,8 @@ int cmd_annotate(int argc, const char **argv)
 	if (annotate_check_args(&annotate.opts) < 0)
 		return -EINVAL;
 
+	annotate.opts.hide_haz_data = !annotate_haz;
+
 	if (symbol_conf.show_nr_samples && annotate.use_gtk) {
 		pr_err("--show-nr-samples is not available in --gtk mode at this time\n");
 		return ret;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 2e4db8216b3b..b04d825cee50 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -190,9 +190,15 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 		return;
 	}
 
-	if (notes->options->hide_src_code) {
+	if (notes->options->hide_src_code && notes->options->hide_haz_data) {
 		from = cursor->al.idx_asm;
 		to = target->idx_asm;
+	} else if (!notes->options->hide_src_code && notes->options->hide_haz_data) {
+		from = cursor->al.idx_asm + cursor->al.idx_src + 1;
+		to = target->idx_asm + target->idx_src + 1;
+	} else if (notes->options->hide_src_code && !notes->options->hide_haz_data) {
+		from = cursor->al.idx_asm + cursor->al.idx_haz + 1;
+		to = target->idx_asm + target->idx_haz + 1;
 	} else {
 		from = (u64)cursor->al.idx;
 		to = (u64)target->idx;
@@ -293,8 +299,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
 	u32 idx = pos->idx;
 
-	if (notes->options->hide_src_code)
+	if (notes->options->hide_src_code && notes->options->hide_haz_data)
 		idx = pos->idx_asm;
+	else if (!notes->options->hide_src_code && notes->options->hide_haz_data)
+		idx = pos->idx_asm + pos->idx_src + 1;
+	else if (notes->options->hide_src_code && !notes->options->hide_haz_data)
+		idx = pos->idx_asm + pos->idx_haz + 1;
+
 	annotate_browser__set_top(browser, pos, idx);
 	browser->curr_hot = nd;
 }
@@ -348,44 +359,117 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser)
 	struct annotation *notes = browser__annotation(&browser->b);
 	struct annotation_line *al;
 	off_t offset = browser->b.index - browser->b.top_idx;
+	u32 curr_idx;
 
 	browser->b.seek(&browser->b, offset, SEEK_CUR);
 	al = list_entry(browser->b.top, struct annotation_line, node);
 
 	if (notes->options->hide_src_code) {
-		if (al->idx_asm < offset)
-			offset = al->idx;
+		if (notes->options->hide_haz_data) {
+			curr_idx = al->idx_asm + al->idx_src + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_src_entries;
+		} else {
+			curr_idx = al->idx;
+			browser->b.nr_entries = notes->nr_entries;
+		}
 
-		browser->b.nr_entries = notes->nr_entries;
 		notes->options->hide_src_code = false;
 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = al->idx - offset;
-		browser->b.index = al->idx;
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
 	} else {
-		if (al->idx_asm < 0) {
+		if (al->type != AL_TYPE_ASM) {
 			ui_helpline__puts("Only available for assembly lines.");
 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
 			return false;
 		}
 
-		if (al->idx_asm < offset)
-			offset = al->idx_asm;
+		if (notes->options->hide_haz_data) {
+			curr_idx = al->idx_asm;
+			browser->b.nr_entries = notes->nr_asm_entries;
+		} else {
+			curr_idx = al->idx_asm + al->idx_haz + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_haz_entries;
+		}
+
+		if (curr_idx < offset)
+			offset = curr_idx;
 
-		browser->b.nr_entries = notes->nr_asm_entries;
 		notes->options->hide_src_code = true;
 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = al->idx_asm - offset;
-		browser->b.index = al->idx_asm;
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
+	}
+
+	return true;
+}
+
+static bool annotate_browser__toggle_hazard(struct annotate_browser *browser)
+{
+	struct annotation *notes = browser__annotation(&browser->b);
+	struct annotation_line *al;
+	off_t offset = browser->b.index - browser->b.top_idx;
+	u32 curr_idx;
+
+	browser->b.seek(&browser->b, offset, SEEK_CUR);
+	al = list_entry(browser->b.top, struct annotation_line, node);
+
+	if (notes->options->hide_haz_data) {
+		if (notes->options->hide_src_code) {
+			curr_idx = al->idx_asm + al->idx_haz + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_haz_entries;
+		} else {
+			curr_idx = al->idx;
+			browser->b.nr_entries = notes->nr_entries;
+		}
+
+		notes->options->hide_haz_data = false;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
+	} else {
+		if (al->type != AL_TYPE_ASM) {
+			ui_helpline__puts("Only available for assembly lines.");
+			browser->b.seek(&browser->b, -offset, SEEK_CUR);
+			return false;
+		}
+
+		if (notes->options->hide_src_code) {
+			curr_idx = al->idx_asm;
+			browser->b.nr_entries = notes->nr_asm_entries;
+		} else {
+			curr_idx = al->idx_asm + al->idx_src + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_src_entries;
+		}
+
+		if (curr_idx < offset)
+			offset = curr_idx;
+
+		notes->options->hide_haz_data = true;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
 	}
 
 	return true;
 }
 
-static void ui_browser__init_asm_mode(struct ui_browser *browser)
+static void ui_browser__hide_src_code(struct ui_browser *browser)
+{
+	struct annotation *notes = browser__annotation(browser);
+	ui_browser__reset_index(browser);
+	browser->nr_entries -= notes->nr_src_entries;
+}
+
+static void ui_browser__hide_haz_data(struct ui_browser *browser)
 {
 	struct annotation *notes = browser__annotation(browser);
 	ui_browser__reset_index(browser);
-	browser->nr_entries = notes->nr_asm_entries;
+	browser->nr_entries -= notes->nr_haz_entries;
 }
 
 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
@@ -743,6 +827,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
 		"o             Toggle disassembler output/simplified view\n"
 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
 		"s             Toggle source code view\n"
+		"S             Toggle pipeline hazard/stall view\n"
 		"t             Circulate percent, total period, samples view\n"
 		"c             Show min/max cycle\n"
 		"/             Search string\n"
@@ -767,6 +852,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
 			if (annotate_browser__toggle_source(browser))
 				ui_helpline__puts(help);
 			continue;
+		case 'S':
+			if (annotate_browser__toggle_hazard(browser))
+				ui_helpline__puts(help);
+			continue;
 		case 'o':
 			notes->options->use_offset = !notes->options->use_offset;
 			annotation__update_column_widths(notes);
@@ -932,7 +1021,10 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
 	browser.b.width += 18; /* Percentage */
 
 	if (notes->options->hide_src_code)
-		ui_browser__init_asm_mode(&browser.b);
+		ui_browser__hide_src_code(&browser.b);
+
+	if (notes->options->hide_haz_data)
+		ui_browser__hide_haz_data(&browser.b);
 
 	ret = annotate_browser__run(&browser, evsel, hbt);
 
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 766934b0f36d..d782ee193345 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -66,6 +66,7 @@ struct annotation_options annotation__default_options = {
 	.annotate_src	= true,
 	.offset_level	= ANNOTATION__OFFSET_JUMP_TARGETS,
 	.percent_type	= PERCENT_PERIOD_LOCAL,
+	.hide_haz_data	= true,
 };
 
 static regex_t	 file_lineno;
@@ -1268,7 +1269,7 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args)
 	struct disasm_line *dl = NULL;
 	int nr = 1;
 
-	if (perf_evsel__is_group_event(args->evsel))
+	if (args->type != AL_TYPE_HAZ && perf_evsel__is_group_event(args->evsel))
 		nr = args->evsel->core.nr_members;
 
 	dl = zalloc(disasm_line_size(nr));
@@ -1509,6 +1510,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
 	} else if (max_lines && printed >= max_lines)
 		return 1;
 	else {
+		/* TODO: Hazard specific changes */
 		int width = symbol_conf.show_total_period ? 12 : 8;
 
 		if (queue)
@@ -1526,6 +1528,34 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
 	return 0;
 }
 
+static int annotation_add_hazard_detail(struct annotation *notes, s64 offset)
+{
+	int ret;
+	struct hazard_hist *hh;
+	struct disasm_line *dl;
+	struct annotate_args args = {
+		.type = AL_TYPE_HAZ,
+		.offset = -1,
+	};
+
+	list_for_each_entry(hh, &notes->src->haz_hist[offset].list, list) {
+		ret = asprintf(&(args.line), "       {haz_stage: %s, "
+			"haz_reason: %s, stall_stage: %s, stall_reason: %s, "
+			"icache: %s}", hh->haz_stage, hh->haz_reason,
+			hh->stall_stage, hh->stall_reason, hh->icache);
+		if (ret == -1)
+			return -ENOMEM;
+
+		dl = disasm_line__new(&args);
+		free(args.line);
+		if (!dl)
+			return -ENOMEM;
+
+		annotation_line__add(&dl->al, &notes->src->source);
+	}
+	return 0;
+}
+
 /*
  * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
  * which looks like following
@@ -1608,6 +1638,10 @@ static int symbol__parse_objdump_line(struct symbol *sym,
 
 	annotation_line__add(&dl->al, &notes->src->source);
 
+	if (offset != -1 && notes->src->haz_hist &&
+	    !list_empty(&notes->src->haz_hist[offset].list))
+		return annotation_add_hazard_detail(notes, offset);
+
 	return 0;
 }
 
@@ -2701,6 +2735,8 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
 	notes->max_line_len = 0;
 	notes->nr_entries = 0;
 	notes->nr_asm_entries = 0;
+	notes->nr_src_entries = 0;
+	notes->nr_haz_entries = 0;
 
 	list_for_each_entry(al, &notes->src->source, node) {
 		size_t line_len = strlen(al->line);
@@ -2710,6 +2746,8 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
 		al->idx = notes->nr_entries++;
 		if (al->type == AL_TYPE_ASM) {
 			al->idx_asm = notes->nr_asm_entries++;
+			al->idx_src = notes->nr_src_entries - 1;
+			al->idx_haz = notes->nr_haz_entries - 1;
 			/*
 			 * FIXME: short term bandaid to cope with assembly
 			 * routines that comes with labels in the same column
@@ -2719,8 +2757,15 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
  			 */
 			if (al->offset < size)
 				notes->offsets[al->offset] = al;
-		} else
+		} else if (al->type == AL_TYPE_SRC) {
 			al->idx_asm = -1;
+			al->idx_src = notes->nr_src_entries++;
+			al->idx_haz = notes->nr_haz_entries - 1;
+		} else if (al->type == AL_TYPE_HAZ) {
+			al->idx_asm = -1;
+			al->idx_haz = notes->nr_haz_entries++;
+			al->idx_src = notes->nr_src_entries - 1;
+		}
 	}
 }
 
@@ -3051,6 +3096,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
 			printed = scnprintf(bf, sizeof(bf), "%-*s  ", notes->widths.addr, " ");
 		obj__printf(obj, bf);
 		obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line);
+	} else if (al->type == AL_TYPE_HAZ) {
+		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, al->line);
 	} else {
 		u64 addr = al->offset;
 		int color = -1;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index a3803f89b8fc..3a082c13bdad 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -85,7 +85,8 @@ struct annotation_options {
 	     show_nr_jumps,
 	     show_minmax_cycle,
 	     show_asm_raw,
-	     annotate_src;
+	     annotate_src,
+	     hide_haz_data;
 	u8   offset_level;
 	int  min_pcnt;
 	int  max_lines;
@@ -131,8 +132,16 @@ struct annotation_data {
 enum annotation_line_type {
 	AL_TYPE_ASM = 0,
 	AL_TYPE_SRC,
+	AL_TYPE_HAZ,
 };
 
+/*
+ * @idx_asm, @idx_src and @idx_haz starts from -1 and increments in
+ * chronological order. For _all_ non-assembly lines, @idx_asm is -1.
+ * OTOH, for non-source line, @idx_src contains prev value. Similarly
+ * for non-hazard lines @idx_haz also contains prev value.
+ * And @idx = @idx_asm + (@idx_src + 1) + (@idx_haz + 1);
+ */
 struct annotation_line {
 	struct list_head	 node;
 	struct rb_node		 rb_node;
@@ -148,6 +157,8 @@ struct annotation_line {
 	char			*path;
 	u32			 idx;
 	int			 idx_asm;
+	int			 idx_src;
+	int			 idx_haz;
 	int			 data_nr;
 	struct annotation_data	 data[0];
 };
@@ -298,6 +309,8 @@ struct annotation {
 	int			max_jump_sources;
 	int			nr_entries;
 	int			nr_asm_entries;
+	int			nr_src_entries;
+	int			nr_haz_entries;
 	u16			max_line_len;
 	struct {
 		u8		addr;
@@ -326,7 +339,8 @@ static inline int annotation__pcnt_width(struct annotation *notes)
 
 static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
 {
-	return notes->options->hide_src_code && al->type == AL_TYPE_SRC;
+	return ((notes->options->hide_src_code && al->type == AL_TYPE_SRC) ||
+		(notes->options->hide_haz_data && al->type == AL_TYPE_HAZ));
 }
 
 void annotation__update_column_widths(struct annotation *notes);
-- 
2.21.1


WARNING: multiple messages have this Message-ID (diff)
From: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
To: linuxppc-dev@lists.ozlabs.org, linux-kernel@vger.kernel.org
Cc: mark.rutland@arm.com, ravi.bangoria@linux.ibm.com,
	ak@linux.intel.com, maddy@linux.ibm.com, peterz@infradead.org,
	alexey.budankov@linux.intel.com, adrian.hunter@intel.com,
	acme@kernel.org, alexander.shishkin@linux.intel.com,
	yao.jin@linux.intel.com, mingo@redhat.com, paulus@samba.org,
	eranian@google.com, robert.richter@amd.com, namhyung@kernel.org,
	kim.phillips@amd.com, jolsa@redhat.com,
	kan.liang@linux.intel.com
Subject: [RFC 11/11] perf annotate: Show hazard data in tui mode
Date: Mon,  2 Mar 2020 10:53:55 +0530	[thread overview]
Message-ID: <20200302052355.36365-12-ravi.bangoria@linux.ibm.com> (raw)
In-Reply-To: <20200302052355.36365-1-ravi.bangoria@linux.ibm.com>

Enable perf report->annotate tui mode to show hazard information. By
default they are hidden, but user can unhide them by pressing hot key
'S'. Sample o/p:

         │    Disassembly of section .text:
         │
         │    0000000010001cf8 <compare>:
         │    compare():
         │    return NULL;
         │    }
         │
         │    static int
         │    compare(const void *p1, const void *p2)
         │    {
   33.23 │      std    r31,-8(r1)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: Load Hit Store, stall_stage: LSU, stall_reason: -, icache: L3 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: -, stall_reason: -, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
    0.84 │      stdu   r1,-64(r1)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: -, stall_reason: -, icache: L1 hit}
    0.24 │      mr     r31,r1
         │       {haz_stage: -, haz_reason: -, stall_stage: -, stall_reason: -, icache: L1 hit}
   21.18 │      std    r3,32(r31)
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}
         │       {haz_stage: LSU, haz_reason: ERAT Miss, stall_stage: LSU, stall_reason: Store, icache: L1 hit}

Signed-off-by: Ravi Bangoria <ravi.bangoria@linux.ibm.com>
---
 tools/perf/builtin-annotate.c     |   5 ++
 tools/perf/ui/browsers/annotate.c | 124 ++++++++++++++++++++++++++----
 tools/perf/util/annotate.c        |  51 +++++++++++-
 tools/perf/util/annotate.h        |  18 ++++-
 4 files changed, 178 insertions(+), 20 deletions(-)

diff --git a/tools/perf/builtin-annotate.c b/tools/perf/builtin-annotate.c
index 78552a9428a6..a51313a6b019 100644
--- a/tools/perf/builtin-annotate.c
+++ b/tools/perf/builtin-annotate.c
@@ -472,6 +472,7 @@ static const char * const annotate_usage[] = {
 
 int cmd_annotate(int argc, const char **argv)
 {
+	bool annotate_haz = false;
 	struct perf_annotate annotate = {
 		.tool = {
 			.sample	= process_sample_event,
@@ -531,6 +532,8 @@ int cmd_annotate(int argc, const char **argv)
 		     symbol__config_symfs),
 	OPT_BOOLEAN(0, "source", &annotate.opts.annotate_src,
 		    "Interleave source code with assembly code (default)"),
+	OPT_BOOLEAN(0, "hazard", &annotate_haz,
+		    "Interleave CPU pileline hazard/stall data with assembly code"),
 	OPT_BOOLEAN(0, "asm-raw", &annotate.opts.show_asm_raw,
 		    "Display raw encoding of assembly instructions (default)"),
 	OPT_STRING('M', "disassembler-style", &annotate.opts.disassembler_style, "disassembler style",
@@ -583,6 +586,8 @@ int cmd_annotate(int argc, const char **argv)
 	if (annotate_check_args(&annotate.opts) < 0)
 		return -EINVAL;
 
+	annotate.opts.hide_haz_data = !annotate_haz;
+
 	if (symbol_conf.show_nr_samples && annotate.use_gtk) {
 		pr_err("--show-nr-samples is not available in --gtk mode at this time\n");
 		return ret;
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index 2e4db8216b3b..b04d825cee50 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -190,9 +190,15 @@ static void annotate_browser__draw_current_jump(struct ui_browser *browser)
 		return;
 	}
 
-	if (notes->options->hide_src_code) {
+	if (notes->options->hide_src_code && notes->options->hide_haz_data) {
 		from = cursor->al.idx_asm;
 		to = target->idx_asm;
+	} else if (!notes->options->hide_src_code && notes->options->hide_haz_data) {
+		from = cursor->al.idx_asm + cursor->al.idx_src + 1;
+		to = target->idx_asm + target->idx_src + 1;
+	} else if (notes->options->hide_src_code && !notes->options->hide_haz_data) {
+		from = cursor->al.idx_asm + cursor->al.idx_haz + 1;
+		to = target->idx_asm + target->idx_haz + 1;
 	} else {
 		from = (u64)cursor->al.idx;
 		to = (u64)target->idx;
@@ -293,8 +299,13 @@ static void annotate_browser__set_rb_top(struct annotate_browser *browser,
 	struct annotation_line * pos = rb_entry(nd, struct annotation_line, rb_node);
 	u32 idx = pos->idx;
 
-	if (notes->options->hide_src_code)
+	if (notes->options->hide_src_code && notes->options->hide_haz_data)
 		idx = pos->idx_asm;
+	else if (!notes->options->hide_src_code && notes->options->hide_haz_data)
+		idx = pos->idx_asm + pos->idx_src + 1;
+	else if (notes->options->hide_src_code && !notes->options->hide_haz_data)
+		idx = pos->idx_asm + pos->idx_haz + 1;
+
 	annotate_browser__set_top(browser, pos, idx);
 	browser->curr_hot = nd;
 }
@@ -348,44 +359,117 @@ static bool annotate_browser__toggle_source(struct annotate_browser *browser)
 	struct annotation *notes = browser__annotation(&browser->b);
 	struct annotation_line *al;
 	off_t offset = browser->b.index - browser->b.top_idx;
+	u32 curr_idx;
 
 	browser->b.seek(&browser->b, offset, SEEK_CUR);
 	al = list_entry(browser->b.top, struct annotation_line, node);
 
 	if (notes->options->hide_src_code) {
-		if (al->idx_asm < offset)
-			offset = al->idx;
+		if (notes->options->hide_haz_data) {
+			curr_idx = al->idx_asm + al->idx_src + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_src_entries;
+		} else {
+			curr_idx = al->idx;
+			browser->b.nr_entries = notes->nr_entries;
+		}
 
-		browser->b.nr_entries = notes->nr_entries;
 		notes->options->hide_src_code = false;
 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = al->idx - offset;
-		browser->b.index = al->idx;
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
 	} else {
-		if (al->idx_asm < 0) {
+		if (al->type != AL_TYPE_ASM) {
 			ui_helpline__puts("Only available for assembly lines.");
 			browser->b.seek(&browser->b, -offset, SEEK_CUR);
 			return false;
 		}
 
-		if (al->idx_asm < offset)
-			offset = al->idx_asm;
+		if (notes->options->hide_haz_data) {
+			curr_idx = al->idx_asm;
+			browser->b.nr_entries = notes->nr_asm_entries;
+		} else {
+			curr_idx = al->idx_asm + al->idx_haz + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_haz_entries;
+		}
+
+		if (curr_idx < offset)
+			offset = curr_idx;
 
-		browser->b.nr_entries = notes->nr_asm_entries;
 		notes->options->hide_src_code = true;
 		browser->b.seek(&browser->b, -offset, SEEK_CUR);
-		browser->b.top_idx = al->idx_asm - offset;
-		browser->b.index = al->idx_asm;
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
+	}
+
+	return true;
+}
+
+static bool annotate_browser__toggle_hazard(struct annotate_browser *browser)
+{
+	struct annotation *notes = browser__annotation(&browser->b);
+	struct annotation_line *al;
+	off_t offset = browser->b.index - browser->b.top_idx;
+	u32 curr_idx;
+
+	browser->b.seek(&browser->b, offset, SEEK_CUR);
+	al = list_entry(browser->b.top, struct annotation_line, node);
+
+	if (notes->options->hide_haz_data) {
+		if (notes->options->hide_src_code) {
+			curr_idx = al->idx_asm + al->idx_haz + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_haz_entries;
+		} else {
+			curr_idx = al->idx;
+			browser->b.nr_entries = notes->nr_entries;
+		}
+
+		notes->options->hide_haz_data = false;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
+	} else {
+		if (al->type != AL_TYPE_ASM) {
+			ui_helpline__puts("Only available for assembly lines.");
+			browser->b.seek(&browser->b, -offset, SEEK_CUR);
+			return false;
+		}
+
+		if (notes->options->hide_src_code) {
+			curr_idx = al->idx_asm;
+			browser->b.nr_entries = notes->nr_asm_entries;
+		} else {
+			curr_idx = al->idx_asm + al->idx_src + 1;
+			browser->b.nr_entries = notes->nr_asm_entries +
+						notes->nr_src_entries;
+		}
+
+		if (curr_idx < offset)
+			offset = curr_idx;
+
+		notes->options->hide_haz_data = true;
+		browser->b.seek(&browser->b, -offset, SEEK_CUR);
+		browser->b.top_idx = curr_idx - offset;
+		browser->b.index = curr_idx;
 	}
 
 	return true;
 }
 
-static void ui_browser__init_asm_mode(struct ui_browser *browser)
+static void ui_browser__hide_src_code(struct ui_browser *browser)
+{
+	struct annotation *notes = browser__annotation(browser);
+	ui_browser__reset_index(browser);
+	browser->nr_entries -= notes->nr_src_entries;
+}
+
+static void ui_browser__hide_haz_data(struct ui_browser *browser)
 {
 	struct annotation *notes = browser__annotation(browser);
 	ui_browser__reset_index(browser);
-	browser->nr_entries = notes->nr_asm_entries;
+	browser->nr_entries -= notes->nr_haz_entries;
 }
 
 #define SYM_TITLE_MAX_SIZE (PATH_MAX + 64)
@@ -743,6 +827,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
 		"o             Toggle disassembler output/simplified view\n"
 		"O             Bump offset level (jump targets -> +call -> all -> cycle thru)\n"
 		"s             Toggle source code view\n"
+		"S             Toggle pipeline hazard/stall view\n"
 		"t             Circulate percent, total period, samples view\n"
 		"c             Show min/max cycle\n"
 		"/             Search string\n"
@@ -767,6 +852,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
 			if (annotate_browser__toggle_source(browser))
 				ui_helpline__puts(help);
 			continue;
+		case 'S':
+			if (annotate_browser__toggle_hazard(browser))
+				ui_helpline__puts(help);
+			continue;
 		case 'o':
 			notes->options->use_offset = !notes->options->use_offset;
 			annotation__update_column_widths(notes);
@@ -932,7 +1021,10 @@ int symbol__tui_annotate(struct map_symbol *ms, struct evsel *evsel,
 	browser.b.width += 18; /* Percentage */
 
 	if (notes->options->hide_src_code)
-		ui_browser__init_asm_mode(&browser.b);
+		ui_browser__hide_src_code(&browser.b);
+
+	if (notes->options->hide_haz_data)
+		ui_browser__hide_haz_data(&browser.b);
 
 	ret = annotate_browser__run(&browser, evsel, hbt);
 
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 766934b0f36d..d782ee193345 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -66,6 +66,7 @@ struct annotation_options annotation__default_options = {
 	.annotate_src	= true,
 	.offset_level	= ANNOTATION__OFFSET_JUMP_TARGETS,
 	.percent_type	= PERCENT_PERIOD_LOCAL,
+	.hide_haz_data	= true,
 };
 
 static regex_t	 file_lineno;
@@ -1268,7 +1269,7 @@ static struct disasm_line *disasm_line__new(struct annotate_args *args)
 	struct disasm_line *dl = NULL;
 	int nr = 1;
 
-	if (perf_evsel__is_group_event(args->evsel))
+	if (args->type != AL_TYPE_HAZ && perf_evsel__is_group_event(args->evsel))
 		nr = args->evsel->core.nr_members;
 
 	dl = zalloc(disasm_line_size(nr));
@@ -1509,6 +1510,7 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
 	} else if (max_lines && printed >= max_lines)
 		return 1;
 	else {
+		/* TODO: Hazard specific changes */
 		int width = symbol_conf.show_total_period ? 12 : 8;
 
 		if (queue)
@@ -1526,6 +1528,34 @@ annotation_line__print(struct annotation_line *al, struct symbol *sym, u64 start
 	return 0;
 }
 
+static int annotation_add_hazard_detail(struct annotation *notes, s64 offset)
+{
+	int ret;
+	struct hazard_hist *hh;
+	struct disasm_line *dl;
+	struct annotate_args args = {
+		.type = AL_TYPE_HAZ,
+		.offset = -1,
+	};
+
+	list_for_each_entry(hh, &notes->src->haz_hist[offset].list, list) {
+		ret = asprintf(&(args.line), "       {haz_stage: %s, "
+			"haz_reason: %s, stall_stage: %s, stall_reason: %s, "
+			"icache: %s}", hh->haz_stage, hh->haz_reason,
+			hh->stall_stage, hh->stall_reason, hh->icache);
+		if (ret == -1)
+			return -ENOMEM;
+
+		dl = disasm_line__new(&args);
+		free(args.line);
+		if (!dl)
+			return -ENOMEM;
+
+		annotation_line__add(&dl->al, &notes->src->source);
+	}
+	return 0;
+}
+
 /*
  * symbol__parse_objdump_line() parses objdump output (with -d --no-show-raw)
  * which looks like following
@@ -1608,6 +1638,10 @@ static int symbol__parse_objdump_line(struct symbol *sym,
 
 	annotation_line__add(&dl->al, &notes->src->source);
 
+	if (offset != -1 && notes->src->haz_hist &&
+	    !list_empty(&notes->src->haz_hist[offset].list))
+		return annotation_add_hazard_detail(notes, offset);
+
 	return 0;
 }
 
@@ -2701,6 +2735,8 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
 	notes->max_line_len = 0;
 	notes->nr_entries = 0;
 	notes->nr_asm_entries = 0;
+	notes->nr_src_entries = 0;
+	notes->nr_haz_entries = 0;
 
 	list_for_each_entry(al, &notes->src->source, node) {
 		size_t line_len = strlen(al->line);
@@ -2710,6 +2746,8 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
 		al->idx = notes->nr_entries++;
 		if (al->type == AL_TYPE_ASM) {
 			al->idx_asm = notes->nr_asm_entries++;
+			al->idx_src = notes->nr_src_entries - 1;
+			al->idx_haz = notes->nr_haz_entries - 1;
 			/*
 			 * FIXME: short term bandaid to cope with assembly
 			 * routines that comes with labels in the same column
@@ -2719,8 +2757,15 @@ static void annotation__set_offsets(struct annotation *notes, s64 size)
  			 */
 			if (al->offset < size)
 				notes->offsets[al->offset] = al;
-		} else
+		} else if (al->type == AL_TYPE_SRC) {
 			al->idx_asm = -1;
+			al->idx_src = notes->nr_src_entries++;
+			al->idx_haz = notes->nr_haz_entries - 1;
+		} else if (al->type == AL_TYPE_HAZ) {
+			al->idx_asm = -1;
+			al->idx_haz = notes->nr_haz_entries++;
+			al->idx_src = notes->nr_src_entries - 1;
+		}
 	}
 }
 
@@ -3051,6 +3096,8 @@ static void __annotation_line__write(struct annotation_line *al, struct annotati
 			printed = scnprintf(bf, sizeof(bf), "%-*s  ", notes->widths.addr, " ");
 		obj__printf(obj, bf);
 		obj__printf(obj, "%-*s", width - printed - pcnt_width - cycles_width + 1, al->line);
+	} else if (al->type == AL_TYPE_HAZ) {
+		obj__printf(obj, "%-*s", width - pcnt_width - cycles_width, al->line);
 	} else {
 		u64 addr = al->offset;
 		int color = -1;
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index a3803f89b8fc..3a082c13bdad 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -85,7 +85,8 @@ struct annotation_options {
 	     show_nr_jumps,
 	     show_minmax_cycle,
 	     show_asm_raw,
-	     annotate_src;
+	     annotate_src,
+	     hide_haz_data;
 	u8   offset_level;
 	int  min_pcnt;
 	int  max_lines;
@@ -131,8 +132,16 @@ struct annotation_data {
 enum annotation_line_type {
 	AL_TYPE_ASM = 0,
 	AL_TYPE_SRC,
+	AL_TYPE_HAZ,
 };
 
+/*
+ * @idx_asm, @idx_src and @idx_haz starts from -1 and increments in
+ * chronological order. For _all_ non-assembly lines, @idx_asm is -1.
+ * OTOH, for non-source line, @idx_src contains prev value. Similarly
+ * for non-hazard lines @idx_haz also contains prev value.
+ * And @idx = @idx_asm + (@idx_src + 1) + (@idx_haz + 1);
+ */
 struct annotation_line {
 	struct list_head	 node;
 	struct rb_node		 rb_node;
@@ -148,6 +157,8 @@ struct annotation_line {
 	char			*path;
 	u32			 idx;
 	int			 idx_asm;
+	int			 idx_src;
+	int			 idx_haz;
 	int			 data_nr;
 	struct annotation_data	 data[0];
 };
@@ -298,6 +309,8 @@ struct annotation {
 	int			max_jump_sources;
 	int			nr_entries;
 	int			nr_asm_entries;
+	int			nr_src_entries;
+	int			nr_haz_entries;
 	u16			max_line_len;
 	struct {
 		u8		addr;
@@ -326,7 +339,8 @@ static inline int annotation__pcnt_width(struct annotation *notes)
 
 static inline bool annotation_line__filter(struct annotation_line *al, struct annotation *notes)
 {
-	return notes->options->hide_src_code && al->type == AL_TYPE_SRC;
+	return ((notes->options->hide_src_code && al->type == AL_TYPE_SRC) ||
+		(notes->options->hide_haz_data && al->type == AL_TYPE_HAZ));
 }
 
 void annotation__update_column_widths(struct annotation *notes);
-- 
2.21.1


  parent reply	other threads:[~2020-03-02  5:25 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-03-02  5:23 [RFC 00/11] perf: Enhancing perf to export processor hazard information Ravi Bangoria
2020-03-02  5:23 ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 01/11] powerpc/perf: Simplify ISA207_SIER macros Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 02/11] perf/core: Data structure to present hazard data Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  9:55   ` Peter Zijlstra
2020-03-02  9:55     ` Peter Zijlstra
2020-03-02 14:23     ` maddy
2020-03-02 14:23       ` maddy
2020-03-02 14:48   ` Mark Rutland
2020-03-02 14:48     ` Mark Rutland
2020-03-03 14:32     ` Ravi Bangoria
2020-03-03 14:32       ` Ravi Bangoria
2020-03-02 14:54   ` Mark Rutland
2020-03-02 14:54     ` Mark Rutland
2020-03-03 14:31     ` Ravi Bangoria
2020-03-03 14:31       ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 03/11] powerpc/perf: Arch specific definitions for pipeline Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 04/11] powerpc/perf: Arch support to expose Hazard data Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 05/11] perf tools: Enable record and script to record and show hazard data Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 06/11] perf hists: Make a room for hazard info in struct hist_entry Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 07/11] perf hazard: Functions to convert generic hazard data to arch specific string Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 08/11] perf report: Enable hazard mode Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 09/11] perf annotate: Introduce type for annotation_line Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` [RFC 10/11] perf annotate: Preparation for hazard Ravi Bangoria
2020-03-02  5:23   ` Ravi Bangoria
2020-03-02  5:23 ` Ravi Bangoria [this message]
2020-03-02  5:23   ` [RFC 11/11] perf annotate: Show hazard data in tui mode Ravi Bangoria
2020-03-02 10:13 ` [RFC 00/11] perf: Enhancing perf to export processor hazard information Peter Zijlstra
2020-03-02 10:13   ` Peter Zijlstra
2020-03-02 20:21   ` Stephane Eranian
2020-03-02 20:21     ` Stephane Eranian
2020-03-02 22:25     ` Kim Phillips
2020-03-02 22:25       ` Kim Phillips
2020-03-05  4:46       ` Ravi Bangoria
2020-03-05  4:46         ` Ravi Bangoria
2020-03-05 22:06         ` Kim Phillips
2020-03-05 22:06           ` Kim Phillips
2020-03-11 16:00           ` Ravi Bangoria
2020-03-12 22:38             ` Kim Phillips
2020-03-12 22:38               ` Kim Phillips
2020-03-17  6:50               ` maddy
2020-03-17  6:50                 ` maddy
2020-03-18 17:35                 ` Kim Phillips
2020-03-18 17:35                   ` Kim Phillips
2020-03-19 11:22                   ` Michael Ellerman
2020-03-19 11:22                     ` Michael Ellerman
2020-03-26 10:19                   ` maddy
2020-03-26 10:19                     ` maddy
2020-03-26 19:48                     ` Kim Phillips
2020-03-26 19:48                       ` Kim Phillips
2020-04-20  7:09                       ` Madhavan Srinivasan
2020-04-20  7:09                         ` Madhavan Srinivasan
2020-04-27  7:18                         ` Madhavan Srinivasan
2020-04-27  7:18                           ` Madhavan Srinivasan
2020-03-05  4:28     ` maddy
2020-03-05  4:28       ` maddy
2020-03-03  1:33   ` Andi Kleen
2020-03-03  1:33     ` Andi Kleen
2020-03-05  5:06     ` Ravi Bangoria
2020-03-05  5:06       ` Ravi Bangoria
2020-03-02 21:08 ` Paul Clarke
2020-03-02 21:08   ` Paul Clarke
2020-03-05  5:06   ` Ravi Bangoria
2020-03-05  5:06     ` Ravi Bangoria

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20200302052355.36365-12-ravi.bangoria@linux.ibm.com \
    --to=ravi.bangoria@linux.ibm.com \
    --cc=acme@kernel.org \
    --cc=adrian.hunter@intel.com \
    --cc=ak@linux.intel.com \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=alexey.budankov@linux.intel.com \
    --cc=eranian@google.com \
    --cc=jolsa@redhat.com \
    --cc=kan.liang@linux.intel.com \
    --cc=kim.phillips@amd.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linuxppc-dev@lists.ozlabs.org \
    --cc=maddy@linux.ibm.com \
    --cc=mark.rutland@arm.com \
    --cc=mingo@redhat.com \
    --cc=mpe@ellerman.id.au \
    --cc=namhyung@kernel.org \
    --cc=paulus@samba.org \
    --cc=peterz@infradead.org \
    --cc=robert.richter@amd.com \
    --cc=yao.jin@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.