]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blobdiff - tools/perf/util/hist.c
Merge tag 'clk-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[mirror_ubuntu-artful-kernel.git] / tools / perf / util / hist.c
index d1f19e0012d44d907a65ac4d1ca281eab38e9b70..de15dbcdcecf8af9d37d06fbbcbaf0bb38e2f29d 100644 (file)
@@ -79,7 +79,7 @@ void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
 
        len = thread__comm_len(h->thread);
        if (hists__new_col_len(hists, HISTC_COMM, len))
-               hists__set_col_len(hists, HISTC_THREAD, len + 6);
+               hists__set_col_len(hists, HISTC_THREAD, len + 8);
 
        if (h->ms.map) {
                len = dso__name_len(h->ms.map->dso);
@@ -352,86 +352,114 @@ void hists__delete_entries(struct hists *hists)
  * histogram, sorted on item, collects periods
  */
 
-static struct hist_entry *hist_entry__new(struct hist_entry *template,
-                                         bool sample_self)
+static int hist_entry__init(struct hist_entry *he,
+                           struct hist_entry *template,
+                           bool sample_self)
 {
-       size_t callchain_size = 0;
-       struct hist_entry *he;
+       *he = *template;
 
-       if (symbol_conf.use_callchain)
-               callchain_size = sizeof(struct callchain_root);
+       if (symbol_conf.cumulate_callchain) {
+               he->stat_acc = malloc(sizeof(he->stat));
+               if (he->stat_acc == NULL)
+                       return -ENOMEM;
+               memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
+               if (!sample_self)
+                       memset(&he->stat, 0, sizeof(he->stat));
+       }
+
+       map__get(he->ms.map);
+
+       if (he->branch_info) {
+               /*
+                * This branch info is (a part of) allocated from
+                * sample__resolve_bstack() and will be freed after
+                * adding new entries.  So we need to save a copy.
+                */
+               he->branch_info = malloc(sizeof(*he->branch_info));
+               if (he->branch_info == NULL) {
+                       map__zput(he->ms.map);
+                       free(he->stat_acc);
+                       return -ENOMEM;
+               }
+
+               memcpy(he->branch_info, template->branch_info,
+                      sizeof(*he->branch_info));
+
+               map__get(he->branch_info->from.map);
+               map__get(he->branch_info->to.map);
+       }
+
+       if (he->mem_info) {
+               map__get(he->mem_info->iaddr.map);
+               map__get(he->mem_info->daddr.map);
+       }
 
-       he = zalloc(sizeof(*he) + callchain_size);
+       if (symbol_conf.use_callchain)
+               callchain_init(he->callchain);
 
-       if (he != NULL) {
-               *he = *template;
+       if (he->raw_data) {
+               he->raw_data = memdup(he->raw_data, he->raw_size);
 
-               if (symbol_conf.cumulate_callchain) {
-                       he->stat_acc = malloc(sizeof(he->stat));
-                       if (he->stat_acc == NULL) {
-                               free(he);
-                               return NULL;
+               if (he->raw_data == NULL) {
+                       map__put(he->ms.map);
+                       if (he->branch_info) {
+                               map__put(he->branch_info->from.map);
+                               map__put(he->branch_info->to.map);
+                               free(he->branch_info);
+                       }
+                       if (he->mem_info) {
+                               map__put(he->mem_info->iaddr.map);
+                               map__put(he->mem_info->daddr.map);
                        }
-                       memcpy(he->stat_acc, &he->stat, sizeof(he->stat));
-                       if (!sample_self)
-                               memset(&he->stat, 0, sizeof(he->stat));
+                       free(he->stat_acc);
+                       return -ENOMEM;
                }
+       }
+       INIT_LIST_HEAD(&he->pairs.node);
+       thread__get(he->thread);
 
-               map__get(he->ms.map);
+       if (!symbol_conf.report_hierarchy)
+               he->leaf = true;
 
-               if (he->branch_info) {
-                       /*
-                        * This branch info is (a part of) allocated from
-                        * sample__resolve_bstack() and will be freed after
-                        * adding new entries.  So we need to save a copy.
-                        */
-                       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;
-                       }
+       return 0;
+}
 
-                       memcpy(he->branch_info, template->branch_info,
-                              sizeof(*he->branch_info));
+static void *hist_entry__zalloc(size_t size)
+{
+       return zalloc(size + sizeof(struct hist_entry));
+}
 
-                       map__get(he->branch_info->from.map);
-                       map__get(he->branch_info->to.map);
-               }
+static void hist_entry__free(void *ptr)
+{
+       free(ptr);
+}
 
-               if (he->mem_info) {
-                       map__get(he->mem_info->iaddr.map);
-                       map__get(he->mem_info->daddr.map);
-               }
+static struct hist_entry_ops default_ops = {
+       .new    = hist_entry__zalloc,
+       .free   = hist_entry__free,
+};
 
-               if (symbol_conf.use_callchain)
-                       callchain_init(he->callchain);
+static struct hist_entry *hist_entry__new(struct hist_entry *template,
+                                         bool sample_self)
+{
+       struct hist_entry_ops *ops = template->ops;
+       size_t callchain_size = 0;
+       struct hist_entry *he;
+       int err = 0;
 
-               if (he->raw_data) {
-                       he->raw_data = memdup(he->raw_data, he->raw_size);
+       if (!ops)
+               ops = template->ops = &default_ops;
 
-                       if (he->raw_data == NULL) {
-                               map__put(he->ms.map);
-                               if (he->branch_info) {
-                                       map__put(he->branch_info->from.map);
-                                       map__put(he->branch_info->to.map);
-                                       free(he->branch_info);
-                               }
-                               if (he->mem_info) {
-                                       map__put(he->mem_info->iaddr.map);
-                                       map__put(he->mem_info->daddr.map);
-                               }
-                               free(he->stat_acc);
-                               free(he);
-                               return NULL;
-                       }
-               }
-               INIT_LIST_HEAD(&he->pairs.node);
-               thread__get(he->thread);
+       if (symbol_conf.use_callchain)
+               callchain_size = sizeof(struct callchain_root);
 
-               if (!symbol_conf.report_hierarchy)
-                       he->leaf = true;
+       he = ops->new(callchain_size);
+       if (he) {
+               err = hist_entry__init(he, template, sample_self);
+               if (err) {
+                       ops->free(he);
+                       he = NULL;
+               }
        }
 
        return he;
@@ -531,13 +559,15 @@ out:
        return he;
 }
 
-struct hist_entry *__hists__add_entry(struct hists *hists,
-                                     struct addr_location *al,
-                                     struct symbol *sym_parent,
-                                     struct branch_info *bi,
-                                     struct mem_info *mi,
-                                     struct perf_sample *sample,
-                                     bool sample_self)
+static struct hist_entry*
+__hists__add_entry(struct hists *hists,
+                  struct addr_location *al,
+                  struct symbol *sym_parent,
+                  struct branch_info *bi,
+                  struct mem_info *mi,
+                  struct perf_sample *sample,
+                  bool sample_self,
+                  struct hist_entry_ops *ops)
 {
        struct hist_entry entry = {
                .thread = al->thread,
@@ -564,11 +594,37 @@ struct hist_entry *__hists__add_entry(struct hists *hists,
                .transaction = sample->transaction,
                .raw_data = sample->raw_data,
                .raw_size = sample->raw_size,
+               .ops = ops,
        };
 
        return hists__findnew_entry(hists, &entry, al, sample_self);
 }
 
+struct hist_entry *hists__add_entry(struct hists *hists,
+                                   struct addr_location *al,
+                                   struct symbol *sym_parent,
+                                   struct branch_info *bi,
+                                   struct mem_info *mi,
+                                   struct perf_sample *sample,
+                                   bool sample_self)
+{
+       return __hists__add_entry(hists, al, sym_parent, bi, mi,
+                                 sample, sample_self, NULL);
+}
+
+struct hist_entry *hists__add_entry_ops(struct hists *hists,
+                                       struct hist_entry_ops *ops,
+                                       struct addr_location *al,
+                                       struct symbol *sym_parent,
+                                       struct branch_info *bi,
+                                       struct mem_info *mi,
+                                       struct perf_sample *sample,
+                                       bool sample_self)
+{
+       return __hists__add_entry(hists, al, sym_parent, bi, mi,
+                                 sample, sample_self, ops);
+}
+
 static int
 iter_next_nop_entry(struct hist_entry_iter *iter __maybe_unused,
                    struct addr_location *al __maybe_unused)
@@ -622,8 +678,8 @@ iter_add_single_mem_entry(struct hist_entry_iter *iter, struct addr_location *al
         */
        sample->period = cost;
 
-       he = __hists__add_entry(hists, al, iter->parent, NULL, mi,
-                               sample, true);
+       he = hists__add_entry(hists, al, iter->parent, NULL, mi,
+                             sample, true);
        if (!he)
                return -ENOMEM;
 
@@ -727,8 +783,8 @@ iter_add_next_branch_entry(struct hist_entry_iter *iter, struct addr_location *a
        sample->period = 1;
        sample->weight = bi->flags.cycles ? bi->flags.cycles : 1;
 
-       he = __hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
-                               sample, true);
+       he = hists__add_entry(hists, al, iter->parent, &bi[i], NULL,
+                             sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -764,8 +820,8 @@ iter_add_single_normal_entry(struct hist_entry_iter *iter, struct addr_location
        struct perf_sample *sample = iter->sample;
        struct hist_entry *he;
 
-       he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
-                               sample, true);
+       he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
+                             sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -825,8 +881,8 @@ iter_add_single_cumulative_entry(struct hist_entry_iter *iter,
        struct hist_entry *he;
        int err = 0;
 
-       he = __hists__add_entry(hists, al, iter->parent, NULL, NULL,
-                               sample, true);
+       he = hists__add_entry(hists, al, iter->parent, NULL, NULL,
+                             sample, true);
        if (he == NULL)
                return -ENOMEM;
 
@@ -900,8 +956,8 @@ iter_add_next_cumulative_entry(struct hist_entry_iter *iter,
                }
        }
 
-       he = __hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
-                               sample, false);
+       he = hists__add_entry(evsel__hists(evsel), al, iter->parent, NULL, NULL,
+                             sample, false);
        if (he == NULL)
                return -ENOMEM;
 
@@ -1043,6 +1099,8 @@ hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
 
 void hist_entry__delete(struct hist_entry *he)
 {
+       struct hist_entry_ops *ops = he->ops;
+
        thread__zput(he->thread);
        map__zput(he->ms.map);
 
@@ -1067,7 +1125,7 @@ void hist_entry__delete(struct hist_entry *he)
        free_callchain(he->callchain);
        free(he->trace_output);
        free(he->raw_data);
-       free(he);
+       ops->free(he);
 }
 
 /*
@@ -1081,7 +1139,7 @@ int hist_entry__snprintf_alignment(struct hist_entry *he, struct perf_hpp *hpp,
                                   struct perf_hpp_fmt *fmt, int printed)
 {
        if (!list_is_last(&fmt->list, &he->hists->hpp_list->fields)) {
-               const int width = fmt->width(fmt, hpp, hists_to_evsel(he->hists));
+               const int width = fmt->width(fmt, hpp, he->hists);
                if (printed < width) {
                        advance_hpp(hpp, printed);
                        printed = scnprintf(hpp->buf, hpp->size, "%-*s", width - printed, " ");
@@ -1614,7 +1672,7 @@ static void __hists__insert_output_entry(struct rb_root *entries,
 }
 
 static void output_resort(struct hists *hists, struct ui_progress *prog,
-                         bool use_callchain)
+                         bool use_callchain, hists__resort_cb_t cb)
 {
        struct rb_root *root;
        struct rb_node *next;
@@ -1653,6 +1711,9 @@ static void 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);
 
+               if (cb && cb(n))
+                       continue;
+
                __hists__insert_output_entry(&hists->entries, n, min_callchain_hits, use_callchain);
                hists__inc_stats(hists, n);
 
@@ -1673,12 +1734,18 @@ void perf_evsel__output_resort(struct perf_evsel *evsel, struct ui_progress *pro
        else
                use_callchain = symbol_conf.use_callchain;
 
-       output_resort(evsel__hists(evsel), prog, use_callchain);
+       output_resort(evsel__hists(evsel), prog, use_callchain, NULL);
 }
 
 void hists__output_resort(struct hists *hists, struct ui_progress *prog)
 {
-       output_resort(hists, prog, symbol_conf.use_callchain);
+       output_resort(hists, prog, symbol_conf.use_callchain, NULL);
+}
+
+void hists__output_resort_cb(struct hists *hists, struct ui_progress *prog,
+                            hists__resort_cb_t cb)
+{
+       output_resort(hists, prog, symbol_conf.use_callchain, cb);
 }
 
 static bool can_goto_child(struct hist_entry *he, enum hierarchy_move_dir hmd)
@@ -2199,7 +2266,7 @@ size_t perf_evlist__fprintf_nr_events(struct perf_evlist *evlist, FILE *fp)
        struct perf_evsel *pos;
        size_t ret = 0;
 
-       evlist__for_each(evlist, pos) {
+       evlist__for_each_entry(evlist, pos) {
                ret += fprintf(fp, "%s stats:\n", perf_evsel__name(pos));
                ret += events_stats__fprintf(&evsel__hists(pos)->stats, fp);
        }