|
@@ -28,6 +28,7 @@
|
|
|
|
|
|
#include "util/thread.h"
|
|
|
#include "util/sort.h"
|
|
|
+#include "util/hist.h"
|
|
|
|
|
|
static char const *input_name = "perf.data";
|
|
|
|
|
@@ -55,8 +56,6 @@ static int exclude_other = 1;
|
|
|
|
|
|
static char callchain_default_opt[] = "fractal,0.5";
|
|
|
|
|
|
-static int callchain;
|
|
|
-
|
|
|
static char __cwd[PATH_MAX];
|
|
|
static char *cwd = __cwd;
|
|
|
static int cwdlen;
|
|
@@ -66,50 +65,8 @@ static struct thread *last_match;
|
|
|
|
|
|
static struct perf_header *header;
|
|
|
|
|
|
-static
|
|
|
-struct callchain_param callchain_param = {
|
|
|
- .mode = CHAIN_GRAPH_REL,
|
|
|
- .min_percent = 0.5
|
|
|
-};
|
|
|
-
|
|
|
static u64 sample_type;
|
|
|
|
|
|
-static struct rb_root hist;
|
|
|
-
|
|
|
-static int64_t
|
|
|
-hist_entry__cmp(struct hist_entry *left, struct hist_entry *right)
|
|
|
-{
|
|
|
- struct sort_entry *se;
|
|
|
- int64_t cmp = 0;
|
|
|
-
|
|
|
- list_for_each_entry(se, &hist_entry__sort_list, list) {
|
|
|
- cmp = se->cmp(left, right);
|
|
|
- if (cmp)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return cmp;
|
|
|
-}
|
|
|
-
|
|
|
-static int64_t
|
|
|
-hist_entry__collapse(struct hist_entry *left, struct hist_entry *right)
|
|
|
-{
|
|
|
- struct sort_entry *se;
|
|
|
- int64_t cmp = 0;
|
|
|
-
|
|
|
- list_for_each_entry(se, &hist_entry__sort_list, list) {
|
|
|
- int64_t (*f)(struct hist_entry *, struct hist_entry *);
|
|
|
-
|
|
|
- f = se->collapse ?: se->cmp;
|
|
|
-
|
|
|
- cmp = f(left, right);
|
|
|
- if (cmp)
|
|
|
- break;
|
|
|
- }
|
|
|
-
|
|
|
- return cmp;
|
|
|
-}
|
|
|
-
|
|
|
static size_t ipchain__fprintf_graph_line(FILE *fp, int depth, int depth_mask)
|
|
|
{
|
|
|
int i;
|
|
@@ -308,7 +265,6 @@ hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-
|
|
|
static size_t
|
|
|
hist_entry__fprintf(FILE *fp, struct hist_entry *self, u64 total_samples)
|
|
|
{
|
|
@@ -573,117 +529,6 @@ hist_entry__add(struct thread *thread, struct map *map, struct dso *dso,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static void hist_entry__free(struct hist_entry *he)
|
|
|
-{
|
|
|
- free(he);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * collapse the histogram
|
|
|
- */
|
|
|
-
|
|
|
-static struct rb_root collapse_hists;
|
|
|
-
|
|
|
-static void collapse__insert_entry(struct hist_entry *he)
|
|
|
-{
|
|
|
- struct rb_node **p = &collapse_hists.rb_node;
|
|
|
- struct rb_node *parent = NULL;
|
|
|
- struct hist_entry *iter;
|
|
|
- int64_t cmp;
|
|
|
-
|
|
|
- while (*p != NULL) {
|
|
|
- parent = *p;
|
|
|
- iter = rb_entry(parent, struct hist_entry, rb_node);
|
|
|
-
|
|
|
- cmp = hist_entry__collapse(iter, he);
|
|
|
-
|
|
|
- if (!cmp) {
|
|
|
- iter->count += he->count;
|
|
|
- hist_entry__free(he);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (cmp < 0)
|
|
|
- p = &(*p)->rb_left;
|
|
|
- else
|
|
|
- p = &(*p)->rb_right;
|
|
|
- }
|
|
|
-
|
|
|
- rb_link_node(&he->rb_node, parent, p);
|
|
|
- rb_insert_color(&he->rb_node, &collapse_hists);
|
|
|
-}
|
|
|
-
|
|
|
-static void collapse__resort(void)
|
|
|
-{
|
|
|
- struct rb_node *next;
|
|
|
- struct hist_entry *n;
|
|
|
-
|
|
|
- if (!sort__need_collapse)
|
|
|
- return;
|
|
|
-
|
|
|
- next = rb_first(&hist);
|
|
|
- while (next) {
|
|
|
- n = rb_entry(next, struct hist_entry, rb_node);
|
|
|
- next = rb_next(&n->rb_node);
|
|
|
-
|
|
|
- rb_erase(&n->rb_node, &hist);
|
|
|
- collapse__insert_entry(n);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * reverse the map, sort on count.
|
|
|
- */
|
|
|
-
|
|
|
-static struct rb_root output_hists;
|
|
|
-
|
|
|
-static void output__insert_entry(struct hist_entry *he, u64 min_callchain_hits)
|
|
|
-{
|
|
|
- struct rb_node **p = &output_hists.rb_node;
|
|
|
- struct rb_node *parent = NULL;
|
|
|
- struct hist_entry *iter;
|
|
|
-
|
|
|
- if (callchain)
|
|
|
- callchain_param.sort(&he->sorted_chain, &he->callchain,
|
|
|
- min_callchain_hits, &callchain_param);
|
|
|
-
|
|
|
- while (*p != NULL) {
|
|
|
- parent = *p;
|
|
|
- iter = rb_entry(parent, struct hist_entry, rb_node);
|
|
|
-
|
|
|
- if (he->count > iter->count)
|
|
|
- p = &(*p)->rb_left;
|
|
|
- else
|
|
|
- p = &(*p)->rb_right;
|
|
|
- }
|
|
|
-
|
|
|
- rb_link_node(&he->rb_node, parent, p);
|
|
|
- rb_insert_color(&he->rb_node, &output_hists);
|
|
|
-}
|
|
|
-
|
|
|
-static void output__resort(u64 total_samples)
|
|
|
-{
|
|
|
- struct rb_node *next;
|
|
|
- struct hist_entry *n;
|
|
|
- struct rb_root *tree = &hist;
|
|
|
- u64 min_callchain_hits;
|
|
|
-
|
|
|
- min_callchain_hits = total_samples * (callchain_param.min_percent / 100);
|
|
|
-
|
|
|
- if (sort__need_collapse)
|
|
|
- tree = &collapse_hists;
|
|
|
-
|
|
|
- next = rb_first(tree);
|
|
|
-
|
|
|
- while (next) {
|
|
|
- n = rb_entry(next, struct hist_entry, rb_node);
|
|
|
- next = rb_next(&n->rb_node);
|
|
|
-
|
|
|
- rb_erase(&n->rb_node, tree);
|
|
|
- output__insert_entry(n, min_callchain_hits);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static size_t output__fprintf(FILE *fp, u64 total_samples)
|
|
|
{
|
|
|
struct hist_entry *pos;
|
|
@@ -778,13 +623,6 @@ print_entries:
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
-static unsigned long total = 0,
|
|
|
- total_mmap = 0,
|
|
|
- total_comm = 0,
|
|
|
- total_fork = 0,
|
|
|
- total_unknown = 0,
|
|
|
- total_lost = 0;
|
|
|
-
|
|
|
static int validate_chain(struct ip_callchain *chain, event_t *event)
|
|
|
{
|
|
|
unsigned int chain_size;
|