From: Andi Kleen <a...@linux.intel.com>

Add srcline_from and srcline_to branch sort keys that allow
to show the source lines of a branch. That makes it much easier
to track down where particular branches happen in the program,
for example to examine branch mispredictions, or to associate
it with cycle counts:

% perf record -b -e cycles:p ./tcall
% perf report --sort srcline_from,srcline_to,mispredict
...
    15.10%  tcall.c:18                                 tcall.c:10               
                   N
    14.83%  tcall.c:11                                 tcall.c:5                
                   N
    14.12%  tcall.c:7                                  tcall.c:12               
                   N
    14.04%  tcall.c:12                                 tcall.c:5                
                   N
    12.42%  tcall.c:17                                 tcall.c:18               
                   N
    12.39%  tcall.c:7                                  tcall.c:13               
                   N
    12.27%  tcall.c:13                                 tcall.c:17               
                   N
...

% perf report --sort srcline_from,srcline_to,cycles
...
    17.12%  tcall.c:18                                 tcall.c:11               
                                   1
    17.01%  tcall.c:12                                 tcall.c:6                
                                   1
    16.98%  tcall.c:11                                 tcall.c:6                
                                   1
    15.91%  tcall.c:17                                 tcall.c:18               
                                   1
     6.38%  tcall.c:7                                  tcall.c:17               
                                   7
     4.80%  tcall.c:7                                  tcall.c:12               
                                   8
     4.21%  tcall.c:7                                  tcall.c:17               
                                   8
     2.67%  tcall.c:7                                  tcall.c:12               
                                   7
     2.62%  tcall.c:7                                  tcall.c:12               
                                   10
     2.10%  tcall.c:7                                  tcall.c:17               
                                   9
     1.58%  tcall.c:7                                  tcall.c:12               
                                   6
     1.44%  tcall.c:7                                  tcall.c:12               
                                   5
     1.38%  tcall.c:7                                  tcall.c:12               
                                   9
     1.06%  tcall.c:7                                  tcall.c:17               
                                   13
     1.05%  tcall.c:7                                  tcall.c:12               
                                   4
     1.01%  tcall.c:7                                  tcall.c:17               
                                   6

Open issues:
- Some kernel symbols get misresolved.

Signed-off-by: Andi Kleen <a...@linux.intel.com>
---
 tools/perf/Documentation/perf-report.txt |  3 +-
 tools/perf/util/hist.c                   |  9 ++++
 tools/perf/util/hist.h                   |  2 +
 tools/perf/util/sort.c                   | 84 ++++++++++++++++++++++++++++++++
 tools/perf/util/sort.h                   |  2 +
 tools/perf/util/symbol.h                 |  2 +
 6 files changed, 101 insertions(+), 1 deletion(-)

diff --git a/tools/perf/Documentation/perf-report.txt 
b/tools/perf/Documentation/perf-report.txt
index 496d42c..9cbddc2 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -103,12 +103,13 @@ OPTIONS
 
        If --branch-stack option is used, following sort keys are also
        available:
-       dso_from, dso_to, symbol_from, symbol_to, mispredict.
 
        - dso_from: name of library or module branched from
        - dso_to: name of library or module branched to
        - symbol_from: name of function branched from
        - symbol_to: name of function branched to
+       - srcline_from: source file and line branched from
+       - srcline_to: source file and line branched to
        - mispredict: "N" for predicted branch, "Y" for mispredicted branch
        - in_tx: branch in TSX transaction
        - abort: TSX transaction abort.
diff --git a/tools/perf/util/hist.c b/tools/perf/util/hist.c
index 3d34c57..58caa69 100644
--- a/tools/perf/util/hist.c
+++ b/tools/perf/util/hist.c
@@ -117,6 +117,13 @@ void hists__calc_col_len(struct hists *hists, struct 
hist_entry *h)
                        hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
                        hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
                }
+
+               if (h->branch_info->srcline_from)
+                       hists__new_col_len(hists, HISTC_SRCLINE_FROM,
+                                       strlen(h->branch_info->srcline_from));
+               if (h->branch_info->srcline_to)
+                       hists__new_col_len(hists, HISTC_SRCLINE_TO,
+                                       strlen(h->branch_info->srcline_to));
        }
 
        if (h->mem_info) {
@@ -1042,6 +1049,8 @@ void hist_entry__delete(struct hist_entry *he)
        if (he->branch_info) {
                map__zput(he->branch_info->from.map);
                map__zput(he->branch_info->to.map);
+               free_srcline(he->branch_info->srcline_from);
+               free_srcline(he->branch_info->srcline_to);
                zfree(&he->branch_info);
        }
 
diff --git a/tools/perf/util/hist.h b/tools/perf/util/hist.h
index 5885965..4dc87aa 100644
--- a/tools/perf/util/hist.h
+++ b/tools/perf/util/hist.h
@@ -52,6 +52,8 @@ enum hist_column {
        HISTC_MEM_IADDR_SYMBOL,
        HISTC_TRANSACTION,
        HISTC_CYCLES,
+       HISTC_SRCLINE_FROM,
+       HISTC_SRCLINE_TO,
        HISTC_TRACE,
        HISTC_NR_COLS, /* Last entry */
 };
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 47966a1..04093c4 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -360,6 +360,88 @@ struct sort_entry sort_srcline = {
        .se_width_idx   = HISTC_SRCLINE,
 };
 
+/* --sort srcline_from */
+
+static int64_t
+sort__srcline_from_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       if (!left->branch_info->srcline_from) {
+               struct map *map = left->branch_info->from.map;
+               if (!map)
+                       left->branch_info->srcline_from = SRCLINE_UNKNOWN;
+               else
+                       left->branch_info->srcline_from = get_srcline(map->dso,
+                                          map__rip_2objdump(map,
+                                                            
left->branch_info->from.al_addr),
+                                                        
left->branch_info->from.sym, true);
+       }
+       if (!right->branch_info->srcline_from) {
+               struct map *map = right->branch_info->from.map;
+               if (!map)
+                       right->branch_info->srcline_from = SRCLINE_UNKNOWN;
+               else
+                       right->branch_info->srcline_from = get_srcline(map->dso,
+                                            map__rip_2objdump(map,
+                                                              
right->branch_info->from.al_addr),
+                                                    
right->branch_info->from.sym, true);
+       }
+       return strcmp(right->branch_info->srcline_from, 
left->branch_info->srcline_from);
+}
+
+static int hist_entry__srcline_from_snprintf(struct hist_entry *he, char *bf,
+                                       size_t size, unsigned int width)
+{
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, 
he->branch_info->srcline_from);
+}
+
+struct sort_entry sort_srcline_from = {
+       .se_header      = "From Source:Line",
+       .se_cmp         = sort__srcline_from_cmp,
+       .se_snprintf    = hist_entry__srcline_from_snprintf,
+       .se_width_idx   = HISTC_SRCLINE_FROM,
+};
+
+/* --sort srcline_to */
+
+static int64_t
+sort__srcline_to_cmp(struct hist_entry *left, struct hist_entry *right)
+{
+       if (!left->branch_info->srcline_to) {
+               struct map *map = left->branch_info->to.map;
+               if (!map)
+                       left->branch_info->srcline_to = SRCLINE_UNKNOWN;
+               else
+                       left->branch_info->srcline_to = get_srcline(map->dso,
+                                          map__rip_2objdump(map,
+                                                            
left->branch_info->to.al_addr),
+                                                        
left->branch_info->from.sym, true);
+       }
+       if (!right->branch_info->srcline_to) {
+               struct map *map = right->branch_info->to.map;
+               if (!map)
+                       right->branch_info->srcline_to = SRCLINE_UNKNOWN;
+               else
+                       right->branch_info->srcline_to = get_srcline(map->dso,
+                                            map__rip_2objdump(map,
+                                                              
right->branch_info->to.al_addr),
+                                                    
right->branch_info->to.sym, true);
+       }
+       return strcmp(right->branch_info->srcline_to, 
left->branch_info->srcline_to);
+}
+
+static int hist_entry__srcline_to_snprintf(struct hist_entry *he, char *bf,
+                                       size_t size, unsigned int width)
+{
+       return repsep_snprintf(bf, size, "%-*.*s", width, width, 
he->branch_info->srcline_to);
+}
+
+struct sort_entry sort_srcline_to = {
+       .se_header      = "To Source:Line",
+       .se_cmp         = sort__srcline_to_cmp,
+       .se_snprintf    = hist_entry__srcline_to_snprintf,
+       .se_width_idx   = HISTC_SRCLINE_TO,
+};
+
 /* --sort srcfile */
 
 static char no_srcfile[1];
@@ -1354,6 +1436,8 @@ static struct sort_dimension bstack_sort_dimensions[] = {
        DIM(SORT_IN_TX, "in_tx", sort_in_tx),
        DIM(SORT_ABORT, "abort", sort_abort),
        DIM(SORT_CYCLES, "cycles", sort_cycles),
+       DIM(SORT_SRCLINE_FROM, "srcline_from", sort_srcline_from),
+       DIM(SORT_SRCLINE_TO, "srcline_to", sort_srcline_to),
 };
 
 #undef DIM
diff --git a/tools/perf/util/sort.h b/tools/perf/util/sort.h
index 3f4e359..9e3d80f 100644
--- a/tools/perf/util/sort.h
+++ b/tools/perf/util/sort.h
@@ -222,6 +222,8 @@ enum sort_type {
        SORT_ABORT,
        SORT_IN_TX,
        SORT_CYCLES,
+       SORT_SRCLINE_FROM,
+       SORT_SRCLINE_TO,
 
        /* memory mode specific sort keys */
        __SORT_MEMORY_MODE,
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index c8b7544..fecc30c 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -177,6 +177,8 @@ struct branch_info {
        struct addr_map_symbol from;
        struct addr_map_symbol to;
        struct branch_flags flags;
+       char                    *srcline_from;
+       char                    *srcline_to;
 };
 
 struct mem_info {
-- 
2.5.5

Reply via email to