]> Pileus Git - ~andy/linux/blobdiff - tools/perf/util/hist.c
perf diff: Fix to work with new hists design
[~andy/linux] / tools / perf / util / hist.c
index 6f505d1abac72e493043e87f029ea9c0d9d4cea5..c61235f81260a0b63eca35ec6b9cf19ce799b77e 100644 (file)
@@ -10,11 +10,14 @@ static bool hists__filter_entry_by_dso(struct hists *hists,
                                       struct hist_entry *he);
 static bool hists__filter_entry_by_thread(struct hists *hists,
                                          struct hist_entry *he);
+static bool hists__filter_entry_by_symbol(struct hists *hists,
+                                         struct hist_entry *he);
 
 enum hist_filter {
        HIST_FILTER__DSO,
        HIST_FILTER__THREAD,
        HIST_FILTER__PARENT,
+       HIST_FILTER__SYMBOL,
 };
 
 struct callchain_param callchain_param = {
@@ -50,21 +53,25 @@ static void hists__reset_col_len(struct hists *hists)
                hists__set_col_len(hists, col, 0);
 }
 
+static void hists__set_unres_dso_col_len(struct hists *hists, int dso)
+{
+       const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
+
+       if (hists__col_len(hists, dso) < unresolved_col_width &&
+           !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
+           !symbol_conf.dso_list)
+               hists__set_col_len(hists, dso, unresolved_col_width);
+}
+
 static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 {
+       const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
        u16 len;
 
        if (h->ms.sym)
-               hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen);
-       else {
-               const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
-
-               if (hists__col_len(hists, HISTC_DSO) < unresolved_col_width &&
-                   !symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
-                   !symbol_conf.dso_list)
-                       hists__set_col_len(hists, HISTC_DSO,
-                                          unresolved_col_width);
-       }
+               hists__new_col_len(hists, HISTC_SYMBOL, h->ms.sym->namelen + 4);
+       else
+               hists__set_unres_dso_col_len(hists, HISTC_DSO);
 
        len = thread__comm_len(h->thread);
        if (hists__new_col_len(hists, HISTC_COMM, len))
@@ -74,6 +81,37 @@ static void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
                len = dso__name_len(h->ms.map->dso);
                hists__new_col_len(hists, HISTC_DSO, len);
        }
+
+       if (h->branch_info) {
+               int symlen;
+               /*
+                * +4 accounts for '[x] ' priv level info
+                * +2 account of 0x prefix on raw addresses
+                */
+               if (h->branch_info->from.sym) {
+                       symlen = (int)h->branch_info->from.sym->namelen + 4;
+                       hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
+
+                       symlen = dso__name_len(h->branch_info->from.map->dso);
+                       hists__new_col_len(hists, HISTC_DSO_FROM, symlen);
+               } else {
+                       symlen = unresolved_col_width + 4 + 2;
+                       hists__new_col_len(hists, HISTC_SYMBOL_FROM, symlen);
+                       hists__set_unres_dso_col_len(hists, HISTC_DSO_FROM);
+               }
+
+               if (h->branch_info->to.sym) {
+                       symlen = (int)h->branch_info->to.sym->namelen + 4;
+                       hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
+
+                       symlen = dso__name_len(h->branch_info->to.map->dso);
+                       hists__new_col_len(hists, HISTC_DSO_TO, symlen);
+               } else {
+                       symlen = unresolved_col_width + 4 + 2;
+                       hists__new_col_len(hists, HISTC_SYMBOL_TO, symlen);
+                       hists__set_unres_dso_col_len(hists, HISTC_DSO_TO);
+               }
+       }
 }
 
 static void hist_entry__add_cpumode_period(struct hist_entry *he,
@@ -195,26 +233,14 @@ static u8 symbol__parent_filter(const struct symbol *parent)
        return 0;
 }
 
-struct hist_entry *__hists__add_entry(struct hists *hists,
+static struct hist_entry *add_hist_entry(struct hists *hists,
+                                     struct hist_entry *entry,
                                      struct addr_location *al,
-                                     struct symbol *sym_parent, u64 period)
+                                     u64 period)
 {
        struct rb_node **p;
        struct rb_node *parent = NULL;
        struct hist_entry *he;
-       struct hist_entry entry = {
-               .thread = al->thread,
-               .ms = {
-                       .map    = al->map,
-                       .sym    = al->sym,
-               },
-               .cpu    = al->cpu,
-               .ip     = al->addr,
-               .level  = al->level,
-               .period = period,
-               .parent = sym_parent,
-               .filtered = symbol__parent_filter(sym_parent),
-       };
        int cmp;
 
        pthread_mutex_lock(&hists->lock);
@@ -225,7 +251,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                parent = *p;
                he = rb_entry(parent, struct hist_entry, rb_node_in);
 
-               cmp = hist_entry__cmp(&entry, he);
+               cmp = hist_entry__cmp(entry, he);
 
                if (!cmp) {
                        he->period += period;
@@ -239,7 +265,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                        p = &(*p)->rb_right;
        }
 
-       he = hist_entry__new(&entry);
+       he = hist_entry__new(entry);
        if (!he)
                goto out_unlock;
 
@@ -252,6 +278,51 @@ out_unlock:
        return he;
 }
 
+struct hist_entry *__hists__add_branch_entry(struct hists *self,
+                                            struct addr_location *al,
+                                            struct symbol *sym_parent,
+                                            struct branch_info *bi,
+                                            u64 period)
+{
+       struct hist_entry entry = {
+               .thread = al->thread,
+               .ms = {
+                       .map    = bi->to.map,
+                       .sym    = bi->to.sym,
+               },
+               .cpu    = al->cpu,
+               .ip     = bi->to.addr,
+               .level  = al->level,
+               .period = period,
+               .parent = sym_parent,
+               .filtered = symbol__parent_filter(sym_parent),
+               .branch_info = bi,
+       };
+
+       return add_hist_entry(self, &entry, al, period);
+}
+
+struct hist_entry *__hists__add_entry(struct hists *self,
+                                     struct addr_location *al,
+                                     struct symbol *sym_parent, u64 period)
+{
+       struct hist_entry entry = {
+               .thread = al->thread,
+               .ms = {
+                       .map    = al->map,
+                       .sym    = al->sym,
+               },
+               .cpu    = al->cpu,
+               .ip     = al->addr,
+               .level  = al->level,
+               .period = period,
+               .parent = sym_parent,
+               .filtered = symbol__parent_filter(sym_parent),
+       };
+
+       return add_hist_entry(self, &entry, al, period);
+}
+
 int64_t
 hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
 {
@@ -352,6 +423,7 @@ static void hists__apply_filters(struct hists *hists, struct hist_entry *he)
 {
        hists__filter_entry_by_dso(hists, he);
        hists__filter_entry_by_thread(hists, he);
+       hists__filter_entry_by_symbol(hists, he);
 }
 
 static void __hists__collapse_resort(struct hists *hists, bool threaded)
@@ -768,7 +840,7 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
                                                     sep ? "%.2f" : "   %6.2f%%",
                                                     (period * 100.0) / total);
                else
-                       ret = snprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
+                       ret = scnprintf(s, size, sep ? "%.2f" : "   %6.2f%%",
                                       (period * 100.0) / total);
                if (symbol_conf.show_cpu_utilization) {
                        ret += percent_color_snprintf(s + ret, size - ret,
@@ -791,20 +863,20 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
                        }
                }
        } else
-               ret = snprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
+               ret = scnprintf(s, size, sep ? "%" PRIu64 : "%12" PRIu64 " ", period);
 
        if (symbol_conf.show_nr_samples) {
                if (sep)
-                       ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
+                       ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, nr_events);
                else
-                       ret += snprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
+                       ret += scnprintf(s + ret, size - ret, "%11" PRIu64, nr_events);
        }
 
        if (symbol_conf.show_total_period) {
                if (sep)
-                       ret += snprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
+                       ret += scnprintf(s + ret, size - ret, "%c%" PRIu64, *sep, period);
                else
-                       ret += snprintf(s + ret, size - ret, " %12" PRIu64, period);
+                       ret += scnprintf(s + ret, size - ret, " %12" PRIu64, period);
        }
 
        if (pair_hists) {
@@ -819,25 +891,25 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
                diff = new_percent - old_percent;
 
                if (fabs(diff) >= 0.01)
-                       snprintf(bf, sizeof(bf), "%+4.2F%%", diff);
+                       scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
                else
-                       snprintf(bf, sizeof(bf), " ");
+                       scnprintf(bf, sizeof(bf), " ");
 
                if (sep)
-                       ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+                       ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
                else
-                       ret += snprintf(s + ret, size - ret, "%11.11s", bf);
+                       ret += scnprintf(s + ret, size - ret, "%11.11s", bf);
 
                if (show_displacement) {
                        if (displacement)
-                               snprintf(bf, sizeof(bf), "%+4ld", displacement);
+                               scnprintf(bf, sizeof(bf), "%+4ld", displacement);
                        else
-                               snprintf(bf, sizeof(bf), " ");
+                               scnprintf(bf, sizeof(bf), " ");
 
                        if (sep)
-                               ret += snprintf(s + ret, size - ret, "%c%s", *sep, bf);
+                               ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
                        else
-                               ret += snprintf(s + ret, size - ret, "%6.6s", bf);
+                               ret += scnprintf(s + ret, size - ret, "%6.6s", bf);
                }
        }
 
@@ -855,7 +927,7 @@ int hist_entry__snprintf(struct hist_entry *he, char *s, size_t size,
                if (se->elide)
                        continue;
 
-               ret += snprintf(s + ret, size - ret, "%s", sep ?: "  ");
+               ret += scnprintf(s + ret, size - ret, "%s", sep ?: "  ");
                ret += se->se_snprintf(he, s + ret, size - ret,
                                       hists__col_len(hists, se->se_width_idx));
        }
@@ -1179,6 +1251,37 @@ void hists__filter_by_thread(struct hists *hists)
        }
 }
 
+static bool hists__filter_entry_by_symbol(struct hists *hists,
+                                         struct hist_entry *he)
+{
+       if (hists->symbol_filter_str != NULL &&
+           (!he->ms.sym || strstr(he->ms.sym->name,
+                                  hists->symbol_filter_str) == NULL)) {
+               he->filtered |= (1 << HIST_FILTER__SYMBOL);
+               return true;
+       }
+
+       return false;
+}
+
+void hists__filter_by_symbol(struct hists *hists)
+{
+       struct rb_node *nd;
+
+       hists->nr_entries = hists->stats.total_period = 0;
+       hists->stats.nr_events[PERF_RECORD_SAMPLE] = 0;
+       hists__reset_col_len(hists);
+
+       for (nd = rb_first(&hists->entries); nd; nd = rb_next(nd)) {
+               struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
+
+               if (hists__filter_entry_by_symbol(hists, h))
+                       continue;
+
+               hists__remove_entry_filter(hists, h, HIST_FILTER__SYMBOL);
+       }
+}
+
 int hist_entry__inc_addr_samples(struct hist_entry *he, int evidx, u64 ip)
 {
        return symbol__inc_addr_samples(he->ms.sym, he->ms.map, evidx, ip);