perf annotate browser: Initial loop detection

Simple algorithm, just look for the next backward jump that points to
before the cursor.

Then draw an arrow connecting the jump to its target.

Do this as you move the cursor, entering/exiting possible loops.

Ex (graph chars replaced to avoid mail encoding woes):

avc_has_perm_flags
    0.00 |         nopl   0x0(%rax)
    5.36 |+-> 68:  mov    (%rax),%rax
    5.15 ||        test   %rax,%rax
    0.00 ||      v je     130
    2.96 ||   74:  cmp    -0x20(%rax),%ebx
   47.38 ||        lea    -0x20(%rax),%rcx
    0.28 ||      ^ jne    68
    3.16 ||        cmp    -0x18(%rax),%dx
    0.00 |+------^ jne    68
    4.92 |         cmp    0x4(%rcx),%r13d
    0.00 |       v jne    68
    1.15 |         test   %rcx,%rcx
    0.00 |       v je     130

Suggested-by: Linus Torvalds <torvalds@linux-foundation.org>
Cc: David Ahern <dsahern@gmail.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Mike Galbraith <efault@gmx.de>
Cc: Namhyung Kim <namhyung@gmail.com>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Stephane Eranian <eranian@google.com>
Link: http://lkml.kernel.org/n/tip-5gairf6or7dazlx3ocxwvftm@git.kernel.org
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index c3fc6f3..9e3310c 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -94,13 +94,13 @@
 			addr += ab->start;
 
 		if (!ab->use_offset) {
-			printed = scnprintf(bf, sizeof(bf), "%" PRIx64 ":", addr);
+			printed = scnprintf(bf, sizeof(bf), "  %" PRIx64 ":", addr);
 		} else {
 			if (bdl->jump_target) {
-				printed = scnprintf(bf, sizeof(bf), "%*" PRIx64 ":",
+				printed = scnprintf(bf, sizeof(bf), "  %*" PRIx64 ":",
 						    ab->offset_width, addr);
 			} else {
-				printed = scnprintf(bf, sizeof(bf), "%*s ",
+				printed = scnprintf(bf, sizeof(bf), "  %*s ",
 						    ab->offset_width, " ");
 			}
 		}
@@ -141,6 +141,59 @@
 		ab->selection = dl;
 }
 
+static void annotate_browser__draw_current_loop(struct ui_browser *browser)
+{
+	struct annotate_browser *ab = container_of(browser, struct annotate_browser, b);
+	struct map_symbol *ms = browser->priv;
+	struct symbol *sym = ms->sym;
+	struct annotation *notes = symbol__annotation(sym);
+	struct disasm_line *cursor = ab->selection, *pos = cursor, *target;
+	struct browser_disasm_line *bcursor = disasm_line__browser(cursor),
+				   *btarget, *bpos;
+	unsigned int from, to, start_width = 2;
+
+	list_for_each_entry_from(pos, &notes->src->source, node) {
+		if (!pos->ins || !ins__is_jump(pos->ins))
+			continue;
+
+		target = ab->offsets[pos->ops.target];
+		if (!target)
+			continue;
+
+		btarget = disasm_line__browser(target);
+		if (btarget->idx <= bcursor->idx)
+			goto found;
+	}
+
+	return;
+
+found:
+	bpos = disasm_line__browser(pos);
+	if (ab->hide_src_code) {
+		from = bpos->idx_asm;
+		to = btarget->idx_asm;
+	} else {
+		from = (u64)bpos->idx;
+		to = (u64)btarget->idx;
+	}
+
+	ui_browser__set_color(browser, HE_COLORSET_CODE);
+
+	if (!bpos->jump_target)
+		start_width += ab->offset_width + 1;
+
+	__ui_browser__line_arrow_up(browser, 10, from, to, start_width);
+}
+
+static unsigned int annotate_browser__refresh(struct ui_browser *browser)
+{
+	int ret = ui_browser__list_head_refresh(browser);
+
+	annotate_browser__draw_current_loop(browser);
+
+	return ret;
+}
+
 static double disasm_line__calc_percent(struct disasm_line *dl, struct symbol *sym, int evidx)
 {
 	double percent = 0.0;
@@ -666,7 +719,7 @@
 	};
 	struct annotate_browser browser = {
 		.b = {
-			.refresh = ui_browser__list_head_refresh,
+			.refresh = annotate_browser__refresh,
 			.seek	 = ui_browser__list_head_seek,
 			.write	 = annotate_browser__write,
 			.filter  = disasm_line__filter,