These changes are the raw update to linux-4.4.6-rt14. Kernel sources
[kvmfornfv.git] / kernel / tools / perf / util / hist.c
index cc22b91..4fd37d6 100644 (file)
@@ -15,6 +15,8 @@ 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);
+static bool hists__filter_entry_by_socket(struct hists *hists,
+                                         struct hist_entry *he);
 
 u16 hists__col_len(struct hists *hists, enum hist_column col)
 {
@@ -130,6 +132,18 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
                        hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
                                           symlen);
                }
+
+               if (h->mem_info->iaddr.sym) {
+                       symlen = (int)h->mem_info->iaddr.sym->namelen + 4
+                              + unresolved_col_width + 2;
+                       hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
+                                          symlen);
+               } else {
+                       symlen = unresolved_col_width + 4 + 2;
+                       hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL,
+                                          symlen);
+               }
+
                if (h->mem_info->daddr.map) {
                        symlen = dso__name_len(h->mem_info->daddr.map->dso);
                        hists__new_col_len(hists, HISTC_MEM_DADDR_DSO,
@@ -141,9 +155,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        } else {
                symlen = unresolved_col_width + 4 + 2;
                hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL, symlen);
+               hists__new_col_len(hists, HISTC_MEM_IADDR_SYMBOL, symlen);
                hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
        }
 
+       hists__new_col_len(hists, HISTC_CPU, 3);
+       hists__new_col_len(hists, HISTC_SOCKET, 6);
        hists__new_col_len(hists, HISTC_MEM_LOCKED, 6);
        hists__new_col_len(hists, HISTC_MEM_TLB, 22);
        hists__new_col_len(hists, HISTC_MEM_SNOOP, 12);
@@ -151,6 +168,12 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
        hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
        hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
 
+       if (h->srcline)
+               hists__new_col_len(hists, HISTC_SRCLINE, strlen(h->srcline));
+
+       if (h->srcfile)
+               hists__new_col_len(hists, HISTC_SRCFILE, strlen(h->srcfile));
+
        if (h->transaction)
                hists__new_col_len(hists, HISTC_TRANSACTION,
                                   hist_entry__transaction_len());
@@ -313,8 +336,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
                                memset(&he->stat, 0, sizeof(he->stat));
                }
 
-               if (he->ms.map)
-                       he->ms.map->referenced = true;
+               map__get(he->ms.map);
 
                if (he->branch_info) {
                        /*
@@ -324,6 +346,7 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
                         */
                        he->branch_info = malloc(sizeof(*he->branch_info));
                        if (he->branch_info == NULL) {
+                               map__zput(he->ms.map);
                                free(he->stat_acc);
                                free(he);
                                return NULL;
@@ -332,17 +355,13 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template,
                        memcpy(he->branch_info, template->branch_info,
                               sizeof(*he->branch_info));
 
-                       if (he->branch_info->from.map)
-                               he->branch_info->from.map->referenced = true;
-                       if (he->branch_info->to.map)
-                               he->branch_info->to.map->referenced = true;
+                       map__get(he->branch_info->from.map);
+                       map__get(he->branch_info->to.map);
                }
 
                if (he->mem_info) {
-                       if (he->mem_info->iaddr.map)
-                               he->mem_info->iaddr.map->referenced = true;
-                       if (he->mem_info->daddr.map)
-                               he->mem_info->daddr.map->referenced = true;
+                       map__get(he->mem_info->iaddr.map);
+                       map__get(he->mem_info->daddr.map);
                }
 
                if (symbol_conf.use_callchain)
@@ -362,10 +381,10 @@ static u8 symbol__parent_filter(const struct symbol *parent)
        return 0;
 }
 
-static struct hist_entry *add_hist_entry(struct hists *hists,
-                                        struct hist_entry *entry,
-                                        struct addr_location *al,
-                                        bool sample_self)
+static struct hist_entry *hists__findnew_entry(struct hists *hists,
+                                              struct hist_entry *entry,
+                                              struct addr_location *al,
+                                              bool sample_self)
 {
        struct rb_node **p;
        struct rb_node *parent = NULL;
@@ -407,9 +426,8 @@ static struct hist_entry *add_hist_entry(struct hists *hists,
                         * the history counter to increment.
                         */
                        if (he->ms.map != entry->ms.map) {
-                               he->ms.map = entry->ms.map;
-                               if (he->ms.map)
-                                       he->ms.map->referenced = true;
+                               map__put(he->ms.map);
+                               he->ms.map = map__get(entry->ms.map);
                        }
                        goto out;
                }
@@ -451,6 +469,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                        .map    = al->map,
                        .sym    = al->sym,
                },
+               .socket  = al->socket,
                .cpu     = al->cpu,
                .cpumode = al->cpumode,
                .ip      = al->addr,
@@ -468,7 +487,7 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                .transaction = transaction,
        };
 
-       return add_hist_entry(hists, &entry, al, sample_self);
+       return hists__findnew_entry(hists, &entry, al, sample_self);
 }
 
 static int
@@ -548,9 +567,9 @@ iter_finish_mem_entry(struct hist_entry_iter *iter,
 
 out:
        /*
-        * We don't need to free iter->priv (mem_info) here since
-        * the mem info was either already freed in add_hist_entry() or
-        * passed to a new hist entry by hist_entry__new().
+        * We don't need to free iter->priv (mem_info) here since the mem info
+        * was either already freed in hists__findnew_entry() or passed to a
+        * new hist entry by hist_entry__new().
         */
        iter->priv = NULL;
 
@@ -623,7 +642,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
         * and not events sampled. Thus we use a pseudo period of 1.
         */
        he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
-                               1, 1, 0, true);
+                               1, bi->flags.cycles ? bi->flags.cycles : 1,
+                               0, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -688,7 +708,7 @@ iter_finish_normal_entry(struct hist_entry_iter *iter,
 }
 
 static int
-iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
+iter_prepare_cumulative_entry(struct hist_entry_iter *iter,
                              struct addr_location *al __maybe_unused)
 {
        struct hist_entry **he_cache;
@@ -700,7 +720,7 @@ iter_prepare_cumulative_entry(struct hist_entry_iter *iter __maybe_unused,
         * cumulated only one time to prevent entries more than 100%
         * overhead.
         */
-       he_cache = malloc(sizeof(*he_cache) * (PERF_MAX_STACK_DEPTH + 1));
+       he_cache = malloc(sizeof(*he_cache) * (iter->max_stack + 1));
        if (he_cache == NULL)
                return -ENOMEM;
 
@@ -765,6 +785,7 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
        struct hist_entry **he_cache = iter->priv;
        struct hist_entry *he;
        struct hist_entry he_tmp = {
+               .hists = evsel__hists(evsel),
                .cpu = al->cpu,
                .thread = al->thread,
                .comm = thread__comm(al->thread),
@@ -851,18 +872,16 @@ const struct hist_iter_ops hist_iter_cumulative = {
 };
 
 int hist_entry_iter__add(struct hist_entry_iter *iter, struct addr_location *al,
-                        struct perf_evsel *evsel, struct perf_sample *sample,
                         int max_stack_depth, void *arg)
 {
        int err, err2;
 
-       err = sample__resolve_callchain(sample, &iter->parent, evsel, al,
-                                       max_stack_depth);
+       err = sample__resolve_callchain(iter->sample, &iter->parent,
+                                       iter->evsel, al, max_stack_depth);
        if (err)
                return err;
 
-       iter->evsel = evsel;
-       iter->sample = sample;
+       iter->max_stack = max_stack_depth;
 
        err = iter->ops->prepare_entry(iter, al);
        if (err)
@@ -937,10 +956,24 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
 void hist_entry__delete(struct hist_entry *he)
 {
        thread__zput(he->thread);
-       zfree(&he->branch_info);
-       zfree(&he->mem_info);
+       map__zput(he->ms.map);
+
+       if (he->branch_info) {
+               map__zput(he->branch_info->from.map);
+               map__zput(he->branch_info->to.map);
+               zfree(&he->branch_info);
+       }
+
+       if (he->mem_info) {
+               map__zput(he->mem_info->iaddr.map);
+               map__zput(he->mem_info->daddr.map);
+               zfree(&he->mem_info);
+       }
+
        zfree(&he->stat_acc);
        free_srcline(he->srcline);
+       if (he->srcfile && he->srcfile[0])
+               free(he->srcfile);
        free_callchain(he->callchain);
        free(he);
 }
@@ -1011,6 +1044,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);
+       hists__filter_entry_by_socket(hists, he);
 }
 
 void hists__collapse_resort(struct hists *hists, struct ui_progress *prog)
@@ -1096,13 +1130,14 @@ void hists__inc_stats(struct hists *hists, struct hist_entry *h)
 
 static void __hists__insert_output_entry(struct rb_root *entries,
                                         struct hist_entry *he,
-                                        u64 min_callchain_hits)
+                                        u64 min_callchain_hits,
+                                        bool use_callchain)
 {
        struct rb_node **p = &entries->rb_node;
        struct rb_node *parent = NULL;
        struct hist_entry *iter;
 
-       if (symbol_conf.use_callchain)
+       if (use_callchain)
                callchain_param.sort(&he->sorted_chain, he->callchain,
                                      min_callchain_hits, &callchain_param);
 
@@ -1126,6 +1161,13 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
        struct rb_node *next;
        struct hist_entry *n;
        u64 min_callchain_hits;
+       struct perf_evsel *evsel = hists_to_evsel(hists);
+       bool use_callchain;
+
+       if (evsel && symbol_conf.use_callchain && !symbol_conf.show_ref_callgraph)
+               use_callchain = evsel->attr.sample_type & PERF_SAMPLE_CALLCHAIN;
+       else
+               use_callchain = symbol_conf.use_callchain;
 
        min_callchain_hits = hists->stats.total_period * (callchain_param.min_percent / 100);
 
@@ -1144,7 +1186,7 @@ void hists__output_resort(struct hists *hists, struct ui_progress *prog)
                n = rb_entry(next, struct hist_entry, rb_node_in);
                next = rb_next(&n->rb_node_in);
 
-               __hists__insert_output_entry(&hists->entries, n, min_callchain_hits);
+               __hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
                hists__inc_stats(hists, n);
 
                if (!n->filtered)
@@ -1163,7 +1205,7 @@ static void hists__remove_entry_filter(struct hists *hists, struct hist_entry *h
                return;
 
        /* force fold unfiltered entry for simplicity */
-       h->ms.unfolded = false;
+       h->unfolded = false;
        h->row_offset = 0;
        h->nr_rows = 0;
 
@@ -1271,6 +1313,37 @@ void hists__filter_by_symbol(struct hists *hists)
        }
 }
 
+static bool hists__filter_entry_by_socket(struct hists *hists,
+                                         struct hist_entry *he)
+{
+       if ((hists->socket_filter > -1) &&
+           (he->socket != hists->socket_filter)) {
+               he->filtered |= (1 << HIST_FILTER__SOCKET);
+               return true;
+       }
+
+       return false;
+}
+
+void hists__filter_by_socket(struct hists *hists)
+{
+       struct rb_node *nd;
+
+       hists->stats.nr_non_filtered_samples = 0;
+
+       hists__reset_filter_stats(hists);
+       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_socket(hists, h))
+                       continue;
+
+               hists__remove_entry_filter(hists, h, HIST_FILTER__SOCKET);
+       }
+}
+
 void events_stats__inc(struct events_stats *stats, u32 type)
 {
        ++stats->nr_events[0];
@@ -1411,6 +1484,39 @@ int hists__link(struct hists *leader, struct hists *other)
        return 0;
 }
 
+void hist__account_cycles(struct branch_stack *bs, struct addr_location *al,
+                         struct perf_sample *sample, bool nonany_branch_mode)
+{
+       struct branch_info *bi;
+
+       /* If we have branch cycles always annotate them. */
+       if (bs && bs->nr && bs->entries[0].flags.cycles) {
+               int i;
+
+               bi = sample__resolve_bstack(sample, al);
+               if (bi) {
+                       struct addr_map_symbol *prev = NULL;
+
+                       /*
+                        * Ignore errors, still want to process the
+                        * other entries.
+                        *
+                        * For non standard branch modes always
+                        * force no IPC (prev == NULL)
+                        *
+                        * Note that perf stores branches reversed from
+                        * program order!
+                        */
+                       for (i = bs->nr - 1; i >= 0; i--) {
+                               addr_map_symbol__account_cycles(&bi[i].from,
+                                       nonany_branch_mode ? NULL : prev,
+                                       bi[i].flags.cycles);
+                               prev = &bi[i].to;
+                       }
+                       free(bi);
+               }
+       }
+}
 
 size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp)
 {
@@ -1463,6 +1569,7 @@ static int hists_evsel__init(struct perf_evsel *evsel)
        hists->entries_collapsed = RB_ROOT;
        hists->entries = RB_ROOT;
        pthread_mutex_init(&hists->lock, NULL);
+       hists->socket_filter = -1;
        return 0;
 }