#include "hist.h"
#include "session.h"
#include "sort.h"
#include <math.h>
struct callchain_param callchain_param = {
.mode = CHAIN_GRAPH_REL,
.min_percent = 0.5
};
static void hist_entry__add_cpumode_count(struct hist_entry *self,
unsigned int cpumode, u64 count)
{
switch (cpumode) {
case PERF_RECORD_MISC_KERNEL:
self->count_sys += count;
break;
case PERF_RECORD_MISC_USER:
self->count_us += count;
break;
case PERF_RECORD_MISC_GUEST_KERNEL:
self->count_guest_sys += count;
break;
case PERF_RECORD_MISC_GUEST_USER:
self->count_guest_us += count;
break;
default:
break;
}
}
/*
* histogram, sorted on item, collects counts
*/
static struct hist_entry *hist_entry__new(struct hist_entry *template)
{
size_t callchain_size = symbol_conf.use_callchain ? sizeof(struct callchain_node) : 0;
struct hist_entry *self = malloc(sizeof(*self) + callchain_size);
if (self != NULL) {
*self = *template;
if (symbol_conf.use_callchain)
callchain_init(self->callchain);
}
return self;
}
struct hist_entry *__hists__add_entry(struct hists *self,
struct addr_location *al,
struct symbol *sym_parent, u64 count)
{
struct rb_node **p = &self->entries.rb_node;
struct rb_node *parent = NULL;
struct hist_entry *he;
struct hist_entry entry = {
.thread = al->thread,
.ms = {
.map = al->map,
.sym = al->sym,
},
.ip = al->addr,
.level = al->level,
.count = count,
.parent = sym_parent,
};
int cmp;
while (*p != NULL) {
parent = *p;
he = rb_entry(parent, struct hist_entry, rb_node);
cmp = hist_entry__cmp(&entry, he);
if (!cmp) {
he->count += count;
goto out;
}
if (cmp < 0)
p = &(*p)->rb_left;
else
p = &(*p)->rb_right;
}
he = hist_entry__new(&entry);
if (!he)
return NULL;
rb_link_node(&he->rb_node, parent, p);
rb_insert_color(&he->rb_node, &self->entries);
out:
hist_entry__add_cpumode_count(he, al->cpumode, count);
return he;
}
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->se_cmp(left, right);
if (cmp)
break;
}
return cmp;
}
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->se_collapse ?: se->se_cmp;
cmp = f(left, right);
if (cmp)
break;
}
return cmp;
}
void hist_entry__free(struct hist_entry *he)
{
free(he);
}
/*
* collapse the histogram
*/
static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
{
struct rb_node **p = &root->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, root);
}
void hists__collapse_resort(struct hists *self)
{
struct rb_root tmp;
struct rb_node *next;
struct hist_entry *n;
if (!sort__need_collapse)
return;
tmp = RB_ROOT;
next = rb_first(&self->entries);
while (next) {
n = rb_entry(next, struct hist_entry, rb_node);
next = rb_next(&n->rb_node);
rb_erase(&n->rb_node, &self->entries);
collapse__insert_entry(&tmp, n);
}
self->entries = tmp;
}
/*
* reve