linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Alexis Berlemont <alexis.berlemont@gmail.com>
To: linux-kernel@vger.kernel.org
Cc: Alexis Berlemont <alexis.berlemont@gmail.com>,
	peterz@infradead.org, mingo@redhat.com, acme@kernel.org,
	alexander.shishkin@linux.intel.com
Subject: [PATCH 2/3] perf hists browser: add callchain-specific annotation
Date: Tue, 18 Apr 2017 00:55:19 +0200	[thread overview]
Message-ID: <20170417225520.28082-3-alexis.berlemont@gmail.com> (raw)
In-Reply-To: <20170417225520.28082-1-alexis.berlemont@gmail.com>

By pressing 'a' in the hists browser, the user gets an annotated view of
the code of the selected symbols.

This patch adds the case 'A'; if this key is pressed (and if the
call-graph option was enabled at record time), perf will build
the callchain from the top frame until the selected symbol and select
the corresponding annotation histogram.

Thus, the user will get an annotated view of the symbol code specific to
the callchain displayed in the hists browser.

Signed-off-by: Alexis Berlemont <alexis.berlemont@gmail.com>
---
 tools/perf/ui/browsers/hists.c | 188 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 185 insertions(+), 3 deletions(-)

diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index da24072bb76e..9ed7fdc4dc51 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -2543,17 +2543,157 @@ struct popup_action {
 	struct thread 		*thread;
 	struct map_symbol 	ms;
 	int			socket;
+	bool                    context_annotate;
 
 	int (*fn)(struct hist_browser *browser, struct popup_action *act);
 };
 
+static int copy_call_list_entry(struct list_head *callchain,
+				struct callchain_list *call)
+{
+	struct call_list_entry *entry = zalloc(sizeof(*entry));
+
+	if (!entry) {
+		perror("not enough memory to scan callchains");
+		return -1;
+	}
+
+	entry->ip = entry->sym_start = call->ip;
+	if (call->ms.sym != NULL)
+		entry->sym_start = call->ms.sym->start;
+
+	list_add_tail(&entry->list, callchain);
+
+	return 0;
+}
+
+static int __hist_browser_build_callchain(struct list_head *callchain,
+					  struct rb_root *root,
+					  struct callchain_list *target)
+{
+	struct callchain_node *tmp_node;
+	struct rb_node *node;
+	struct callchain_list *call;
+	struct call_list_entry *new_call, *tmp;
+
+	node = rb_first(root);
+
+	while (node) {
+		char folded_sign = ' ';
+		size_t added_count = 0;
+
+		tmp_node = rb_entry(node, struct callchain_node, rb_node);
+
+		/*
+		 * If the callchain display mode is "flat", the list
+		 * "parent_val" may contain the entries in common.
+		 */
+
+		list_for_each_entry(call, &tmp_node->parent_val, list) {
+
+			/*
+			 * If we have not found the highlighted callchain
+			 * entry...
+			 */
+
+			if (target == call)
+				return 0;
+
+			/*
+			 * ...we need to keep the current element: the next
+			 * one could be the right one and we need to build a
+			 * callchain.
+			 */
+
+			if (copy_call_list_entry(callchain, call) < 0)
+				return -1;
+
+			added_count++;
+		}
+
+		/*
+		 * If the callchain display mode is "graph", "fractal" or even
+		 * "flat", the callchain entries (the last one for "flat" are in
+		 * the list "val".
+		 */
+
+		list_for_each_entry(call, &tmp_node->val, list) {
+
+			/*
+			 * If we have not found the highlighted callchain
+			 * entry...
+			 */
+
+			if (target == call)
+				return 0;
+
+			/*
+			 * ...we need to keep the current element: the next
+			 * one could be the right one and we need to build a
+			 * callchain.
+			 */
+
+			if (copy_call_list_entry(callchain, call) < 0)
+				return -1;
+
+			added_count++;
+
+			/*
+			 * If we meet the folded sign '+' (and if the current
+			 * element does not match), there is no need to go
+			 * further, the callchain elements below cannot be the
+			 * ones we are looking for.
+			 */
+
+			folded_sign = callchain_list__folded(call);
+			if (folded_sign == '+')
+				break;
+		}
+
+		/*
+		 * If the last scanned entry is unfolded, the callchain element
+		 * we are looking for may be behing; so, let's scan its tree of
+		 * callchain nodes.
+		 */
+
+		if (folded_sign == '-' &&
+		    __hist_browser_build_callchain(callchain,
+						   &tmp_node->rb_root,
+						   target) == 0)
+			return 0;
+
+		/*
+		 * Nothing was found, let's remove the scanned callchain
+		 * elements...
+		 */
+
+		list_for_each_entry_safe_reverse(new_call, tmp,
+						 callchain, list) {
+
+			if (added_count == 0)
+				break;
+
+			list_del(&new_call->list);
+			free(new_call);
+			added_count--;
+		}
+
+		/* ...and go to the next one. */
+		node = rb_next(node);
+	}
+
+	return -1;
+}
+
 static int
 do_annotate(struct hist_browser *browser, struct popup_action *act)
 {
 	struct perf_evsel *evsel;
 	struct annotation *notes;
 	struct hist_entry *he;
-	int err;
+	struct map_symbol *ms;
+	struct callchain_list *target;
+	int err, old_idx;
 
 	if (!objdump_path && perf_env__lookup_objdump(browser->env))
 		return 0;
@@ -2562,9 +2702,48 @@ do_annotate(struct hist_browser *browser, struct popup_action *act)
 	if (!notes->src)
 		return 0;
 
-	evsel = hists_to_evsel(browser->hists);
-	err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
 	he = hist_browser__selected_entry(browser);
+
+	ms = browser->selection;
+	target = container_of(ms, struct callchain_list, ms);
+
+	evsel = hists_to_evsel(browser->hists);
+	if (act->context_annotate && browser->selection != &he->ms) {
+		struct list_head callchain;
+
+		/*
+		 * Build the callchain which corresponds to the selected entry
+		 * in the browser in order to...
+		 */
+
+		INIT_LIST_HEAD(&callchain);
+		err = __hist_browser_build_callchain(&callchain,
+						     &he->sorted_chain, target);
+		if (err < 0)
+			return -1;
+
+		/*
+		 * ...select the histogram which callchain matches ours and copy
+		 * it into a fake evsel slot (the last one); then...
+		 */
+
+		err =  symbol_cxt__copy_hist(act->ms.sym,
+					     evsel->idx, &callchain);
+		if (err < 0)
+			return -1;
+
+		/* ...we just need to trick the current evsel index so as
+		 * display the copied annotation histogram.
+		 */
+
+		old_idx = evsel->idx;
+		evsel->idx = notes->src->nr_histograms - 1;
+		err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
+		evsel->idx = old_idx;
+
+	} else
+		err = map_symbol__tui_annotate(&act->ms, evsel, browser->hbt);
+
 	/*
 	 * offer option to annotate the other branch source or target
 	 * (if they exists) when returning from annotate
@@ -2939,6 +3118,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 	"ENTER         Zoom into DSO/Threads & Annotate current symbol\n" \
 	"ESC           Zoom out\n"					\
 	"a             Annotate current symbol\n"			\
+	"A             Annotate current symbol (callchain-specific)\n"	\
 	"C             Collapse all callchains\n"			\
 	"d             Zoom into current DSO\n"				\
 	"E             Expand all callchains\n"				\
@@ -3014,6 +3194,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 			 */
 			goto out_free_stack;
 		case 'a':
+		case 'A':
 			if (!hists__has(hists, sym)) {
 				ui_browser__warning(&browser->b, delay_secs * 2,
 			"Annotation is only available for symbolic views, "
@@ -3028,6 +3209,7 @@ static int perf_evsel__hists_browse(struct perf_evsel *evsel, int nr_events,
 
 			actions->ms.map = browser->selection->map;
 			actions->ms.sym = browser->selection->sym;
+			actions->context_annotate = key == 'A';
 			do_annotate(browser, actions);
 			continue;
 		case 'P':
-- 
2.12.2

  parent reply	other threads:[~2017-04-17 23:02 UTC|newest]

Thread overview: 4+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-17 22:55 [PATCH 0/3] perf: callchain-specific annotation Alexis Berlemont
2017-04-17 22:55 ` [PATCH 1/3] perf annotate: implement per-callchain annotation histogram Alexis Berlemont
2017-04-17 22:55 ` Alexis Berlemont [this message]
2017-04-17 22:55 ` [PATCH 3/3] perf report: fill per-callchain symbol annotation histograms Alexis Berlemont

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=20170417225520.28082-3-alexis.berlemont@gmail.com \
    --to=alexis.berlemont@gmail.com \
    --cc=acme@kernel.org \
    --cc=alexander.shishkin@linux.intel.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=peterz@infradead.org \
    /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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).