#include "annotate.h"
#include "util.h"
#include "build-id.h"
#include "hist.h"
#include "session.h"
#include "sort.h"
#include <math.h>
enum hist_filter {
HIST_FILTER__DSO,
HIST_FILTER__THREAD,
HIST_FILTER__PARENT,
};
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_REL,
.min_percent = 0.5
};
u16 hists__col_len(struct hists *self, enum hist_column col)
{
return self->col_len[col];
}
void hists__set_col_len(struct hists *self, enum hist_column col, u16 len)
{
self->col_len[col] = len;
}
bool hists__new_col_len(struct hists *self, enum hist_column col, u16 len)
{
if (len > hists__col_len(self, col)) {
hists__set_col_len(self, col, len);
return true;
}
return false;
}
static void hists__reset_col_len(struct hists *self)
{
enum hist_column col;
for (col = 0; col < HISTC_NR_COLS; ++col)
hists__set_col_len(self, col, 0);
}
static void hists__calc_col_len(struct hists *self, struct hist_entry *h)
{
u16 len;
if (h->ms.sym)
hists__new_col_len(self, HISTC_SYMBOL, h->ms.sym->namelen);
else {
const unsigned int unresolved_col_width = BITS_PER_LONG / 4;
if (hists__col_len(self, HISTC_DSO) < unresolved_col_width &&
!symbol_conf.col_width_list_str && !symbol_conf.field_sep &&
!symbol_conf.dso_list)
hists__set_col_len(self, HISTC_DSO,
unresolved_col_width);
}
len = thread__comm_len(h->thread);
if (hists__new_col_len(self, HISTC_COMM, len))
hists__set_col_len(self, HISTC_THREAD, len + 6);
if (h->ms.map) {
len = dso__name_len(h->ms.map->dso);
hists__new_col_len(self, HISTC_DSO, len);
}
}
static void hist_entry__add_cpumode_period(struct hist_entry *self,
unsigned int cpumode, u64 period)
{
switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
self->period_sys += period;
break;
case PERF_RECORD_MISC_USER:
self->period_us += period;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
self->period_guest_sys += period;
break;
case PERF_RECORD_MISC_GUEST_USER:
self->period_guest_us += period;
break;
default:
break;
}
}
/*
* histogram, sorted on item, collects periods
*/
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_root) : 0;
struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
if (self != NULL) {
*self = *template;
self->nr_events = 1;
if (self->ms.map)
self->ms.map->referenced = true;
if (symbol_conf.use_callchain)
callchain_init(self->callchain);
}
return self;
}
static void hists__inc_nr_entries(struct hists *self, struct hist_entry *h)
{
if (!h->filtered) {
hists__calc_col_len(self, h);
++self->nr_entries;
}
}
static u8 symbol__parent_filter(const struct symbol *parent)
{
if (symbol_conf.exclude_other && parent == NULL)
return 1 << HIST_FILTER__PARENT;
return 0;
}
struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al,
struct symbol *sym_parent, u64 period)
{
struct rb_node **p = &self->entries.rb_node;
struct rb_node *par