Release 4.10 tools/perf/util/hist.c
#include "util.h"
#include "build-id.h"
#include "hist.h"
#include "map.h"
#include "session.h"
#include "sort.h"
#include "evlist.h"
#include "evsel.h"
#include "annotate.h"
#include "ui/progress.h"
#include <math.h>
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);
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)
{
return hists->col_len[col];
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 22 | 100.00% | 2 | 100.00% |
| Total | 22 | 100.00% | 2 | 100.00% |
void hists__set_col_len(struct hists *hists, enum hist_column col, u16 len)
{
hists->col_len[col] = len;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 26 | 100.00% | 2 | 100.00% |
| Total | 26 | 100.00% | 2 | 100.00% |
bool hists__new_col_len(struct hists *hists, enum hist_column col, u16 len)
{
if (len > hists__col_len(hists, col)) {
hists__set_col_len(hists, col, len);
return true;
}
return false;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 45 | 100.00% | 2 | 100.00% |
| Total | 45 | 100.00% | 2 | 100.00% |
void hists__reset_col_len(struct hists *hists)
{
enum hist_column col;
for (col = 0; col < HISTC_NR_COLS; ++col)
hists__set_col_len(hists, col, 0);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 36 | 100.00% | 2 | 100.00% |
| Total | 36 | 100.00% | 2 | 100.00% |
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);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 53 | 91.38% | 3 | 75.00% |
roberto agostino vitillo | roberto agostino vitillo | 5 | 8.62% | 1 | 25.00% |
| Total | 58 | 100.00% | 4 | 100.00% |
void hists__calc_col_len(struct hists *hists, struct hist_entry *h)
{
const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
int symlen;
u16 len;
/*
* +4 accounts for '[x] ' priv level info
* +2 accounts for 0x prefix on raw addresses
* +3 accounts for ' y ' symtab origin info
*/
if (h->ms.sym) {
symlen = h->ms.sym->namelen + 4;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
hists__new_col_len(hists, HISTC_SYMBOL, symlen);
} else {
symlen = unresolved_col_width + 4 + 2;
hists__new_col_len(hists, HISTC_SYMBOL, symlen);
hists__set_unres_dso_col_len(hists, HISTC_DSO);
}
len = thread__comm_len(h->thread);
if (hists__new_col_len(hists, HISTC_COMM, len))
hists__set_col_len(hists, HISTC_THREAD, len + 8);
if (h->ms.map) {
len = dso__name_len(h->ms.map->dso);
hists__new_col_len(hists, HISTC_DSO, len);
}
if (h->parent)
hists__new_col_len(hists, HISTC_PARENT, h->parent->namelen);
if (h->branch_info) {
if (h->branch_info->from.sym) {
symlen = (int)h->branch_info->from.sym->namelen + 4;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
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;
if (verbose)
symlen += BITS_PER_LONG / 4 + 2 + 3;
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);
}
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) {
if (h->mem_info->daddr.sym) {
symlen = (int)h->mem_info->daddr.sym->namelen + 4
+ unresolved_col_width + 2;
hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
symlen);
hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
symlen + 1);
} else {
symlen = unresolved_col_width + 4 + 2;
hists__new_col_len(hists, HISTC_MEM_DADDR_SYMBOL,
symlen);
hists__new_col_len(hists, HISTC_MEM_DCACHELINE,
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,
symlen);
} else {
symlen = unresolved_col_width + 4 + 2;
hists__set_unres_dso_col_len(hists, HISTC_MEM_DADDR_DSO);
}
} 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);
hists__new_col_len(hists, HISTC_MEM_LVL, 21 + 3);
hists__new_col_len(hists, HISTC_LOCAL_WEIGHT, 12);
hists__new_col_len(hists, HISTC_GLOBAL_WEIGHT, 12);
if (h->srcline) {
len = MAX(strlen(h->srcline), strlen(sort_srcline.se_header));
hists__new_col_len(hists, HISTC_SRCLINE, len);
}
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());
if (h->trace_output)
hists__new_col_len(hists, HISTC_TRACE, strlen(h->trace_output));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
roberto agostino vitillo | roberto agostino vitillo | 239 | 27.95% | 1 | 5.56% |
stephane eranian | stephane eranian | 229 | 26.78% | 1 | 5.56% |
jiri olsa | jiri olsa | 102 | 11.93% | 4 | 22.22% |
namhyung kim | namhyung kim | 94 | 10.99% | 3 | 16.67% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 87 | 10.18% | 4 | 22.22% |
andi kleen | andi kleen | 84 | 9.82% | 3 | 16.67% |
don zickus | don zickus | 11 | 1.29% | 1 | 5.56% |
kan liang | kan liang | 9 | 1.05% | 1 | 5.56% |
| Total | 855 | 100.00% | 18 | 100.00% |
void hists__output_recalc_col_len(struct hists *hists, int max_rows)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
int row = 0;
hists__reset_col_len(hists);
while (next && row++ < max_rows) {
n = rb_entry(next, struct hist_entry, rb_node);
if (!n->filtered)
hists__calc_col_len(hists, n);
next = rb_next(&n->rb_node);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 88 | 100.00% | 1 | 100.00% |
| Total | 88 | 100.00% | 1 | 100.00% |
static void he_stat__add_cpumode_period(struct he_stat *he_stat,
unsigned int cpumode, u64 period)
{
switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
he_stat->period_sys += period;
break;
case PERF_RECORD_MISC_USER:
he_stat->period_us += period;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
he_stat->period_guest_sys += period;
break;
case PERF_RECORD_MISC_GUEST_USER:
he_stat->period_guest_us += period;
break;
default:
break;
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
yanmin zhang | yanmin zhang | 46 | 69.70% | 1 | 25.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 13 | 19.70% | 2 | 50.00% |
namhyung kim | namhyung kim | 7 | 10.61% | 1 | 25.00% |
| Total | 66 | 100.00% | 4 | 100.00% |
static void he_stat__add_period(struct he_stat *he_stat, u64 period,
u64 weight)
{
he_stat->period += period;
he_stat->weight += weight;
he_stat->nr_events += 1;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 26 | 74.29% | 1 | 50.00% |
andi kleen | andi kleen | 9 | 25.71% | 1 | 50.00% |
| Total | 35 | 100.00% | 2 | 100.00% |
static void he_stat__add_stat(struct he_stat *dest, struct he_stat *src)
{
dest->period += src->period;
dest->period_sys += src->period_sys;
dest->period_us += src->period_us;
dest->period_guest_sys += src->period_guest_sys;
dest->period_guest_us += src->period_guest_us;
dest->nr_events += src->nr_events;
dest->weight += src->weight;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 64 | 88.89% | 1 | 50.00% |
andi kleen | andi kleen | 8 | 11.11% | 1 | 50.00% |
| Total | 72 | 100.00% | 2 | 100.00% |
static void he_stat__decay(struct he_stat *he_stat)
{
he_stat->period = (he_stat->period * 7) / 8;
he_stat->nr_events = (he_stat->nr_events * 7) / 8;
/* XXX need decay for weight too? */
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 32 | 80.00% | 1 | 33.33% |
namhyung kim | namhyung kim | 7 | 17.50% | 1 | 33.33% |
andi kleen | andi kleen | 1 | 2.50% | 1 | 33.33% |
| Total | 40 | 100.00% | 3 | 100.00% |
static void hists__delete_entry(struct hists *hists, struct hist_entry *he);
static bool hists__decay_entry(struct hists *hists, struct hist_entry *he)
{
u64 prev_period = he->stat.period;
u64 diff;
if (prev_period == 0)
return true;
he_stat__decay(&he->stat);
if (symbol_conf.cumulate_callchain)
he_stat__decay(he->stat_acc);
decay_callchain(he->callchain);
diff = prev_period - he->stat.period;
if (!he->depth) {
hists->stats.total_period -= diff;
if (!he->filtered)
hists->stats.total_non_filtered_period -= diff;
}
if (!he->leaf) {
struct hist_entry *child;
struct rb_node *node = rb_first(&he->hroot_out);
while (node) {
child = rb_entry(node, struct hist_entry, rb_node);
node = rb_next(node);
if (hists__decay_entry(hists, child))
hists__delete_entry(hists, child);
}
}
return he->stat.period == 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 128 | 69.57% | 6 | 66.67% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 56 | 30.43% | 3 | 33.33% |
| Total | 184 | 100.00% | 9 | 100.00% |
static void hists__delete_entry(struct hists *hists, struct hist_entry *he)
{
struct rb_root *root_in;
struct rb_root *root_out;
if (he->parent_he) {
root_in = &he->parent_he->hroot_in;
root_out = &he->parent_he->hroot_out;
} else {
if (hists__has(hists, need_collapse))
root_in = &hists->entries_collapsed;
else
root_in = hists->entries_in;
root_out = &hists->entries;
}
rb_erase(&he->rb_node_in, root_in);
rb_erase(&he->rb_node, root_out);
--hists->nr_entries;
if (!he->filtered)
--hists->nr_non_filtered_entries;
hist_entry__delete(he);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 65 | 51.18% | 2 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 56 | 44.09% | 1 | 25.00% |
jiri olsa | jiri olsa | 6 | 4.72% | 1 | 25.00% |
| Total | 127 | 100.00% | 4 | 100.00% |
void hists__decay_entries(struct hists *hists, bool zap_user, bool zap_kernel)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
if (((zap_user && n->level == '.') ||
(zap_kernel && n->level != '.') ||
hists__decay_entry(hists, n))) {
hists__delete_entry(hists, n);
}
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 98 | 96.08% | 4 | 66.67% |
namhyung kim | namhyung kim | 4 | 3.92% | 2 | 33.33% |
| Total | 102 | 100.00% | 6 | 100.00% |
void hists__delete_entries(struct hists *hists)
{
struct rb_node *next = rb_first(&hists->entries);
struct hist_entry *n;
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
hists__delete_entry(hists, n);
}
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 62 | 98.41% | 1 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 1 | 1.59% | 1 | 50.00% |
| Total | 63 | 100.00% | 2 | 100.00% |
/*
* histogram, sorted on item, collects periods
*/
static int hist_entry__init(struct hist_entry *he,
struct hist_entry *template,
bool sample_self)
{
*he = *template;
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);
}
if (symbol_conf.use_callchain)
callchain_init(he->callchain);
if (he->raw_data) {
he->raw_data = memdup(he->raw_data, he->raw_size);
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);
return -ENOMEM;
}
}
INIT_LIST_HEAD(&he->pairs.node);
thread__get(he->thread);
he->hroot_in = RB_ROOT;
he->hroot_out = RB_ROOT;
if (!symbol_conf.report_hierarchy)
he->leaf = true;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 270 | 65.53% | 6 | 40.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 78 | 18.93% | 6 | 40.00% |
stephane eranian | stephane eranian | 48 | 11.65% | 2 | 13.33% |
jiri olsa | jiri olsa | 16 | 3.88% | 1 | 6.67% |
| Total | 412 | 100.00% | 15 | 100.00% |
static void *hist_entry__zalloc(size_t size)
{
return zalloc(size + sizeof(struct hist_entry));
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 22 | 100.00% | 1 | 100.00% |
| Total | 22 | 100.00% | 1 | 100.00% |
static void hist_entry__free(void *ptr)
{
free(ptr);
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 15 | 100.00% | 1 | 100.00% |
| Total | 15 | 100.00% | 1 | 100.00% |
static struct hist_entry_ops default_ops = {
.new = hist_entry__zalloc,
.free = hist_entry__free,
};
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 (!ops)
ops = template->ops = &default_ops;
if (symbol_conf.use_callchain)
callchain_size = sizeof(struct callchain_root);
he = ops->new(callchain_size);
if (he) {
err = hist_entry__init(he, template, sample_self);
if (err) {
ops->free(he);
he = NULL;
}
}
return he;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
jiri olsa | jiri olsa | 109 | 95.61% | 2 | 50.00% |
arnaldo carvalho de melo | arnaldo carvalho de melo | 5 | 4.39% | 2 | 50.00% |
| Total | 114 | 100.00% | 4 | 100.00% |
static u8 symbol__parent_filter(const struct symbol *parent)
{
if (symbol_conf.exclude_other && parent == NULL)
return 1 << HIST_FILTER__PARENT;
return 0;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
arnaldo carvalho de melo | arnaldo carvalho de melo | 30 | 100.00% | 1 | 100.00% |
| Total | 30 | 100.00% | 1 | 100.00% |
static void hist_entry__add_callchain_period(struct hist_entry *he, u64 period)
{
if (!symbol_conf.use_callchain)
return;
he->hists->callchain_period += period;
if (!he->filtered)
he->hists->callchain_non_filtered_period += period;
}
Contributors
| Person | Tokens | Prop | Commits | CommitProp |
namhyung kim | namhyung kim | 45 | 100.00% | 1 | 100.00% |
| Total | 45 | 100.00% | 1 | 100.00% |
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;
struct hist_entry *he;
int64_t cmp;
u64 period = entry->stat.period;
u64 weight = entry->stat.weight;
p = &hists->entries_in->rb_node;
while (*p != NULL) {
parent = *p;
he = rb_entry(parent, struct hist_entry, rb_node_in);
/*
* Make sure that it receives arguments in a same order as
* hist_entry__collapse() so that we can use an appropriate
* function when searching an entry regardless which sort
* keys were used.
*/
cmp = hist_entry__cmp(he, entry);
if (!cmp) {
if (sample_self) {
he_stat__add_period(&he->stat, period, weight);
hist_entry__add_callchain_period(he, period);
}
if (symbol_conf.cumulate_callchain)
he_stat__add_period(he->stat_acc, period, weight);
/*
* This mem info was allocated from sample__resolve_mem
* and will not be used anymore.
*/
zfree(&entry->mem_info);
/* If the map of an existing hist_entry has
* become out-of-date due to an exec() or
* similar, update it. Otherwise we will
* mis-adjust symbol addresses when computing
* the history counter to increment.
*/
if (he->ms.map != entry->ms.map) {
map__put(he->ms.map);
he->ms.map = map__get(entry->ms.map);
}
goto out;
}
if (cmp < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
he = hist_entry__new(entry, sample_self);
if (!he)
return NULL;
if (sample_self)
hist_entry__add_callchain_period(he, period);
hists->nr_entries++