perf hist: Introduce hists class and move lots of methods to it
In cbbc79a we introduced support for multiple events by introducing a new "event_stat_id" struct and then made several perf_session methods receive a point to it instead of a pointer to perf_session, and kept the event_stats and hists rb_tree in perf_session. While working on the new newt based browser, I realised that it would be better to introduce a new class, "hists" (short for "histograms"), renaming the "event_stat_id" struct and the perf_session methods that were really "hists" methods, as they manipulate only struct hists members, not touching anything in the other perf_session members. Other optimizations, such as calculating the maximum lenght of a symbol name present in an hists instance will be possible as we add them, avoiding a re-traversal just for finding that information. The rationale for the name "hists" to replace "event_stat_id" is that we may have multiple sets of hists for the same event_stat id, as, for instance, the 'perf diff' tool has, so event stat id is not what characterizes what this struct and the functions that manipulate it do. Cc: Eric B Munson <ebmunson@us.ibm.com> Cc: Frédéric Weisbecker <fweisbec@gmail.com> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Tom Zanussi <tzanussi@gmail.com> LKML-Reference: <new-submission> Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Родитель
d118f8ba6a
Коммит
1c02c4d2e9
|
@ -96,8 +96,7 @@ static int annotate__hist_hit(struct hist_entry *he, u64 ip)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int perf_session__add_hist_entry(struct perf_session *self,
|
static int hists__add_entry(struct hists *self, struct addr_location *al)
|
||||||
struct addr_location *al)
|
|
||||||
{
|
{
|
||||||
struct hist_entry *he;
|
struct hist_entry *he;
|
||||||
|
|
||||||
|
@ -112,7 +111,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
he = __perf_session__add_hist_entry(&self->hists, al, NULL, 1);
|
he = __hists__add_entry(self, al, NULL, 1);
|
||||||
if (he == NULL)
|
if (he == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
|
@ -132,7 +131,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!al.filtered && perf_session__add_hist_entry(session, &al)) {
|
if (!al.filtered && hists__add_entry(&session->hists, &al)) {
|
||||||
pr_warning("problem incrementing symbol count, "
|
pr_warning("problem incrementing symbol count, "
|
||||||
"skipping event\n");
|
"skipping event\n");
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -514,11 +513,11 @@ static void annotate_sym(struct hist_entry *he)
|
||||||
free_source_line(he, len);
|
free_source_line(he, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_session__find_annotations(struct perf_session *self)
|
static void hists__find_annotations(struct hists *self)
|
||||||
{
|
{
|
||||||
struct rb_node *nd;
|
struct rb_node *nd;
|
||||||
|
|
||||||
for (nd = rb_first(&self->hists); nd; nd = rb_next(nd)) {
|
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
|
||||||
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
struct hist_entry *he = rb_entry(nd, struct hist_entry, rb_node);
|
||||||
struct sym_priv *priv;
|
struct sym_priv *priv;
|
||||||
|
|
||||||
|
@ -570,9 +569,9 @@ static int __cmd_annotate(void)
|
||||||
if (verbose > 2)
|
if (verbose > 2)
|
||||||
perf_session__fprintf_dsos(session, stdout);
|
perf_session__fprintf_dsos(session, stdout);
|
||||||
|
|
||||||
perf_session__collapse_resort(&session->hists);
|
hists__collapse_resort(&session->hists);
|
||||||
perf_session__output_resort(&session->hists, session->event_total[0]);
|
hists__output_resort(&session->hists);
|
||||||
perf_session__find_annotations(session);
|
hists__find_annotations(&session->hists);
|
||||||
out_delete:
|
out_delete:
|
||||||
perf_session__delete(session);
|
perf_session__delete(session);
|
||||||
|
|
||||||
|
|
|
@ -22,10 +22,10 @@ static char diff__default_sort_order[] = "dso,symbol";
|
||||||
static bool force;
|
static bool force;
|
||||||
static bool show_displacement;
|
static bool show_displacement;
|
||||||
|
|
||||||
static int perf_session__add_hist_entry(struct perf_session *self,
|
static int hists__add_entry(struct hists *self,
|
||||||
struct addr_location *al, u64 count)
|
struct addr_location *al, u64 count)
|
||||||
{
|
{
|
||||||
if (__perf_session__add_hist_entry(&self->hists, al, NULL, count) != NULL)
|
if (__hists__add_entry(self, al, NULL, count) != NULL)
|
||||||
return 0;
|
return 0;
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
@ -49,12 +49,12 @@ static int diff__process_sample_event(event_t *event, struct perf_session *sessi
|
||||||
|
|
||||||
event__parse_sample(event, session->sample_type, &data);
|
event__parse_sample(event, session->sample_type, &data);
|
||||||
|
|
||||||
if (perf_session__add_hist_entry(session, &al, data.period)) {
|
if (hists__add_entry(&session->hists, &al, data.period)) {
|
||||||
pr_warning("problem incrementing symbol count, skipping event\n");
|
pr_warning("problem incrementing symbol count, skipping event\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
session->events_stats.total += data.period;
|
session->hists.stats.total += data.period;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,35 +87,34 @@ static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
||||||
rb_insert_color(&he->rb_node, root);
|
rb_insert_color(&he->rb_node, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_session__resort_hist_entries(struct perf_session *self)
|
static void hists__resort_entries(struct hists *self)
|
||||||
{
|
{
|
||||||
unsigned long position = 1;
|
unsigned long position = 1;
|
||||||
struct rb_root tmp = RB_ROOT;
|
struct rb_root tmp = RB_ROOT;
|
||||||
struct rb_node *next = rb_first(&self->hists);
|
struct rb_node *next = rb_first(&self->entries);
|
||||||
|
|
||||||
while (next != NULL) {
|
while (next != NULL) {
|
||||||
struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
|
struct hist_entry *n = rb_entry(next, struct hist_entry, rb_node);
|
||||||
|
|
||||||
next = rb_next(&n->rb_node);
|
next = rb_next(&n->rb_node);
|
||||||
rb_erase(&n->rb_node, &self->hists);
|
rb_erase(&n->rb_node, &self->entries);
|
||||||
n->position = position++;
|
n->position = position++;
|
||||||
perf_session__insert_hist_entry_by_name(&tmp, n);
|
perf_session__insert_hist_entry_by_name(&tmp, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
self->hists = tmp;
|
self->entries = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_session__set_hist_entries_positions(struct perf_session *self)
|
static void hists__set_positions(struct hists *self)
|
||||||
{
|
{
|
||||||
perf_session__output_resort(&self->hists, self->events_stats.total);
|
hists__output_resort(self);
|
||||||
perf_session__resort_hist_entries(self);
|
hists__resort_entries(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct hist_entry *
|
static struct hist_entry *hists__find_entry(struct hists *self,
|
||||||
perf_session__find_hist_entry(struct perf_session *self,
|
struct hist_entry *he)
|
||||||
struct hist_entry *he)
|
|
||||||
{
|
{
|
||||||
struct rb_node *n = self->hists.rb_node;
|
struct rb_node *n = self->entries.rb_node;
|
||||||
|
|
||||||
while (n) {
|
while (n) {
|
||||||
struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
|
struct hist_entry *iter = rb_entry(n, struct hist_entry, rb_node);
|
||||||
|
@ -132,14 +131,13 @@ perf_session__find_hist_entry(struct perf_session *self,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void perf_session__match_hists(struct perf_session *old_session,
|
static void hists__match(struct hists *older, struct hists *newer)
|
||||||
struct perf_session *new_session)
|
|
||||||
{
|
{
|
||||||
struct rb_node *nd;
|
struct rb_node *nd;
|
||||||
|
|
||||||
for (nd = rb_first(&new_session->hists); nd; nd = rb_next(nd)) {
|
for (nd = rb_first(&newer->entries); nd; nd = rb_next(nd)) {
|
||||||
struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
|
struct hist_entry *pos = rb_entry(nd, struct hist_entry, rb_node);
|
||||||
pos->pair = perf_session__find_hist_entry(old_session, pos);
|
pos->pair = hists__find_entry(older, pos);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -159,15 +157,13 @@ static int __cmd_diff(void)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
}
|
}
|
||||||
|
|
||||||
perf_session__output_resort(&session[1]->hists,
|
hists__output_resort(&session[1]->hists);
|
||||||
session[1]->events_stats.total);
|
|
||||||
if (show_displacement)
|
if (show_displacement)
|
||||||
perf_session__set_hist_entries_positions(session[0]);
|
hists__set_positions(&session[0]->hists);
|
||||||
|
|
||||||
perf_session__match_hists(session[0], session[1]);
|
hists__match(&session[0]->hists, &session[1]->hists);
|
||||||
perf_session__fprintf_hists(&session[1]->hists, session[0],
|
hists__fprintf(&session[1]->hists, &session[0]->hists,
|
||||||
show_displacement, stdout,
|
show_displacement, stdout);
|
||||||
session[1]->events_stats.total);
|
|
||||||
out_delete:
|
out_delete:
|
||||||
for (i = 0; i < 2; ++i)
|
for (i = 0; i < 2; ++i)
|
||||||
perf_session__delete(session[i]);
|
perf_session__delete(session[i]);
|
||||||
|
|
|
@ -44,16 +44,17 @@ static char *pretty_printing_style = default_pretty_printing_style;
|
||||||
|
|
||||||
static char callchain_default_opt[] = "fractal,0.5";
|
static char callchain_default_opt[] = "fractal,0.5";
|
||||||
|
|
||||||
static struct event_stat_id *get_stats(struct perf_session *self,
|
static struct hists *perf_session__hists_findnew(struct perf_session *self,
|
||||||
u64 event_stream, u32 type, u64 config)
|
u64 event_stream, u32 type,
|
||||||
|
u64 config)
|
||||||
{
|
{
|
||||||
struct rb_node **p = &self->stats_by_id.rb_node;
|
struct rb_node **p = &self->hists_tree.rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
struct event_stat_id *iter, *new;
|
struct hists *iter, *new;
|
||||||
|
|
||||||
while (*p != NULL) {
|
while (*p != NULL) {
|
||||||
parent = *p;
|
parent = *p;
|
||||||
iter = rb_entry(parent, struct event_stat_id, rb_node);
|
iter = rb_entry(parent, struct hists, rb_node);
|
||||||
if (iter->config == config)
|
if (iter->config == config)
|
||||||
return iter;
|
return iter;
|
||||||
|
|
||||||
|
@ -64,15 +65,15 @@ static struct event_stat_id *get_stats(struct perf_session *self,
|
||||||
p = &(*p)->rb_left;
|
p = &(*p)->rb_left;
|
||||||
}
|
}
|
||||||
|
|
||||||
new = malloc(sizeof(struct event_stat_id));
|
new = malloc(sizeof(struct hists));
|
||||||
if (new == NULL)
|
if (new == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
memset(new, 0, sizeof(struct event_stat_id));
|
memset(new, 0, sizeof(struct hists));
|
||||||
new->event_stream = event_stream;
|
new->event_stream = event_stream;
|
||||||
new->config = config;
|
new->config = config;
|
||||||
new->type = type;
|
new->type = type;
|
||||||
rb_link_node(&new->rb_node, parent, p);
|
rb_link_node(&new->rb_node, parent, p);
|
||||||
rb_insert_color(&new->rb_node, &self->stats_by_id);
|
rb_insert_color(&new->rb_node, &self->hists_tree);
|
||||||
return new;
|
return new;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +85,7 @@ static int perf_session__add_hist_entry(struct perf_session *self,
|
||||||
struct symbol *parent = NULL;
|
struct symbol *parent = NULL;
|
||||||
int err = -ENOMEM;
|
int err = -ENOMEM;
|
||||||
struct hist_entry *he;
|
struct hist_entry *he;
|
||||||
struct event_stat_id *stats;
|
struct hists *hists;
|
||||||
struct perf_event_attr *attr;
|
struct perf_event_attr *attr;
|
||||||
|
|
||||||
if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
|
if ((sort__has_parent || symbol_conf.use_callchain) && data->callchain) {
|
||||||
|
@ -96,13 +97,12 @@ static int perf_session__add_hist_entry(struct perf_session *self,
|
||||||
|
|
||||||
attr = perf_header__find_attr(data->id, &self->header);
|
attr = perf_header__find_attr(data->id, &self->header);
|
||||||
if (attr)
|
if (attr)
|
||||||
stats = get_stats(self, data->id, attr->type, attr->config);
|
hists = perf_session__hists_findnew(self, data->id, attr->type, attr->config);
|
||||||
else
|
else
|
||||||
stats = get_stats(self, data->id, 0, 0);
|
hists = perf_session__hists_findnew(self, data->id, 0, 0);
|
||||||
if (stats == NULL)
|
if (hists == NULL)
|
||||||
goto out_free_syms;
|
goto out_free_syms;
|
||||||
he = __perf_session__add_hist_entry(&stats->hists, al, parent,
|
he = __hists__add_entry(hists, al, parent, data->period);
|
||||||
data->period);
|
|
||||||
if (he == NULL)
|
if (he == NULL)
|
||||||
goto out_free_syms;
|
goto out_free_syms;
|
||||||
err = 0;
|
err = 0;
|
||||||
|
@ -117,18 +117,19 @@ static int add_event_total(struct perf_session *session,
|
||||||
struct sample_data *data,
|
struct sample_data *data,
|
||||||
struct perf_event_attr *attr)
|
struct perf_event_attr *attr)
|
||||||
{
|
{
|
||||||
struct event_stat_id *stats;
|
struct hists *hists;
|
||||||
|
|
||||||
if (attr)
|
if (attr)
|
||||||
stats = get_stats(session, data->id, attr->type, attr->config);
|
hists = perf_session__hists_findnew(session, data->id,
|
||||||
|
attr->type, attr->config);
|
||||||
else
|
else
|
||||||
stats = get_stats(session, data->id, 0, 0);
|
hists = perf_session__hists_findnew(session, data->id, 0, 0);
|
||||||
|
|
||||||
if (!stats)
|
if (!hists)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
stats->stats.total += data->period;
|
hists->stats.total += data->period;
|
||||||
session->events_stats.total += data->period;
|
session->hists.stats.total += data->period;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -292,35 +293,33 @@ static int __cmd_report(void)
|
||||||
if (verbose > 2)
|
if (verbose > 2)
|
||||||
perf_session__fprintf_dsos(session, stdout);
|
perf_session__fprintf_dsos(session, stdout);
|
||||||
|
|
||||||
next = rb_first(&session->stats_by_id);
|
next = rb_first(&session->hists_tree);
|
||||||
while (next) {
|
while (next) {
|
||||||
struct event_stat_id *stats;
|
struct hists *hists;
|
||||||
u64 nr_hists;
|
u64 nr_hists;
|
||||||
|
|
||||||
stats = rb_entry(next, struct event_stat_id, rb_node);
|
hists = rb_entry(next, struct hists, rb_node);
|
||||||
perf_session__collapse_resort(&stats->hists);
|
hists__collapse_resort(hists);
|
||||||
nr_hists = perf_session__output_resort(&stats->hists,
|
nr_hists = hists__output_resort(hists);
|
||||||
stats->stats.total);
|
|
||||||
if (use_browser)
|
if (use_browser)
|
||||||
perf_session__browse_hists(&stats->hists, nr_hists,
|
perf_session__browse_hists(&hists->entries, nr_hists,
|
||||||
stats->stats.total, help,
|
hists->stats.total, help,
|
||||||
input_name);
|
input_name);
|
||||||
else {
|
else {
|
||||||
if (rb_first(&session->stats_by_id) ==
|
if (rb_first(&session->hists.entries) ==
|
||||||
rb_last(&session->stats_by_id))
|
rb_last(&session->hists.entries))
|
||||||
fprintf(stdout, "# Samples: %Ld\n#\n",
|
fprintf(stdout, "# Samples: %Ld\n#\n",
|
||||||
stats->stats.total);
|
hists->stats.total);
|
||||||
else
|
else
|
||||||
fprintf(stdout, "# Samples: %Ld %s\n#\n",
|
fprintf(stdout, "# Samples: %Ld %s\n#\n",
|
||||||
stats->stats.total,
|
hists->stats.total,
|
||||||
__event_name(stats->type, stats->config));
|
__event_name(hists->type, hists->config));
|
||||||
|
|
||||||
perf_session__fprintf_hists(&stats->hists, NULL, false, stdout,
|
hists__fprintf(hists, NULL, false, stdout);
|
||||||
stats->stats.total);
|
|
||||||
fprintf(stdout, "\n\n");
|
fprintf(stdout, "\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
next = rb_next(&stats->rb_node);
|
next = rb_next(&hists->rb_node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!use_browser && sort_order == default_sort_order &&
|
if (!use_browser && sort_order == default_sort_order &&
|
||||||
|
|
|
@ -107,7 +107,7 @@ static int process_sample_event(event_t *event, struct perf_session *session)
|
||||||
data.time, thread->comm);
|
data.time, thread->comm);
|
||||||
}
|
}
|
||||||
|
|
||||||
session->events_stats.total += data.period;
|
session->hists.stats.total += data.period;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -368,7 +368,7 @@ int event__process_comm(event_t *self, struct perf_session *session)
|
||||||
int event__process_lost(event_t *self, struct perf_session *session)
|
int event__process_lost(event_t *self, struct perf_session *session)
|
||||||
{
|
{
|
||||||
dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
|
dump_printf(": id:%Ld: lost:%Ld\n", self->lost.id, self->lost.lost);
|
||||||
session->events_stats.lost += self->lost.lost;
|
session->hists.stats.lost += self->lost.lost;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -131,20 +131,6 @@ typedef union event_union {
|
||||||
struct build_id_event build_id;
|
struct build_id_event build_id;
|
||||||
} event_t;
|
} event_t;
|
||||||
|
|
||||||
struct events_stats {
|
|
||||||
u64 total;
|
|
||||||
u64 lost;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct event_stat_id {
|
|
||||||
struct rb_node rb_node;
|
|
||||||
struct rb_root hists;
|
|
||||||
struct events_stats stats;
|
|
||||||
u64 config;
|
|
||||||
u64 event_stream;
|
|
||||||
u32 type;
|
|
||||||
};
|
|
||||||
|
|
||||||
void event__print_totals(void);
|
void event__print_totals(void);
|
||||||
|
|
||||||
struct perf_session;
|
struct perf_session;
|
||||||
|
|
|
@ -8,21 +8,21 @@ struct callchain_param callchain_param = {
|
||||||
.min_percent = 0.5
|
.min_percent = 0.5
|
||||||
};
|
};
|
||||||
|
|
||||||
static void perf_session__add_cpumode_count(struct hist_entry *he,
|
static void hist_entry__add_cpumode_count(struct hist_entry *self,
|
||||||
unsigned int cpumode, u64 count)
|
unsigned int cpumode, u64 count)
|
||||||
{
|
{
|
||||||
switch (cpumode) {
|
switch (cpumode) {
|
||||||
case PERF_RECORD_MISC_KERNEL:
|
case PERF_RECORD_MISC_KERNEL:
|
||||||
he->count_sys += count;
|
self->count_sys += count;
|
||||||
break;
|
break;
|
||||||
case PERF_RECORD_MISC_USER:
|
case PERF_RECORD_MISC_USER:
|
||||||
he->count_us += count;
|
self->count_us += count;
|
||||||
break;
|
break;
|
||||||
case PERF_RECORD_MISC_GUEST_KERNEL:
|
case PERF_RECORD_MISC_GUEST_KERNEL:
|
||||||
he->count_guest_sys += count;
|
self->count_guest_sys += count;
|
||||||
break;
|
break;
|
||||||
case PERF_RECORD_MISC_GUEST_USER:
|
case PERF_RECORD_MISC_GUEST_USER:
|
||||||
he->count_guest_us += count;
|
self->count_guest_us += count;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -47,12 +47,11 @@ static struct hist_entry *hist_entry__new(struct hist_entry *template)
|
||||||
return self;
|
return self;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
|
struct hist_entry *__hists__add_entry(struct hists *self,
|
||||||
struct addr_location *al,
|
struct addr_location *al,
|
||||||
struct symbol *sym_parent,
|
struct symbol *sym_parent, u64 count)
|
||||||
u64 count)
|
|
||||||
{
|
{
|
||||||
struct rb_node **p = &hists->rb_node;
|
struct rb_node **p = &self->entries.rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
struct hist_entry *he;
|
struct hist_entry *he;
|
||||||
struct hist_entry entry = {
|
struct hist_entry entry = {
|
||||||
|
@ -89,9 +88,9 @@ struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
|
||||||
if (!he)
|
if (!he)
|
||||||
return NULL;
|
return NULL;
|
||||||
rb_link_node(&he->rb_node, parent, p);
|
rb_link_node(&he->rb_node, parent, p);
|
||||||
rb_insert_color(&he->rb_node, hists);
|
rb_insert_color(&he->rb_node, &self->entries);
|
||||||
out:
|
out:
|
||||||
perf_session__add_cpumode_count(he, al->cpumode, count);
|
hist_entry__add_cpumode_count(he, al->cpumode, count);
|
||||||
return he;
|
return he;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -167,7 +166,7 @@ static void collapse__insert_entry(struct rb_root *root, struct hist_entry *he)
|
||||||
rb_insert_color(&he->rb_node, root);
|
rb_insert_color(&he->rb_node, root);
|
||||||
}
|
}
|
||||||
|
|
||||||
void perf_session__collapse_resort(struct rb_root *hists)
|
void hists__collapse_resort(struct hists *self)
|
||||||
{
|
{
|
||||||
struct rb_root tmp;
|
struct rb_root tmp;
|
||||||
struct rb_node *next;
|
struct rb_node *next;
|
||||||
|
@ -177,28 +176,28 @@ void perf_session__collapse_resort(struct rb_root *hists)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
tmp = RB_ROOT;
|
tmp = RB_ROOT;
|
||||||
next = rb_first(hists);
|
next = rb_first(&self->entries);
|
||||||
|
|
||||||
while (next) {
|
while (next) {
|
||||||
n = rb_entry(next, struct hist_entry, rb_node);
|
n = rb_entry(next, struct hist_entry, rb_node);
|
||||||
next = rb_next(&n->rb_node);
|
next = rb_next(&n->rb_node);
|
||||||
|
|
||||||
rb_erase(&n->rb_node, hists);
|
rb_erase(&n->rb_node, &self->entries);
|
||||||
collapse__insert_entry(&tmp, n);
|
collapse__insert_entry(&tmp, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
*hists = tmp;
|
self->entries = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* reverse the map, sort on count.
|
* reverse the map, sort on count.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void perf_session__insert_output_hist_entry(struct rb_root *root,
|
static void __hists__insert_output_entry(struct rb_root *entries,
|
||||||
struct hist_entry *he,
|
struct hist_entry *he,
|
||||||
u64 min_callchain_hits)
|
u64 min_callchain_hits)
|
||||||
{
|
{
|
||||||
struct rb_node **p = &root->rb_node;
|
struct rb_node **p = &entries->rb_node;
|
||||||
struct rb_node *parent = NULL;
|
struct rb_node *parent = NULL;
|
||||||
struct hist_entry *iter;
|
struct hist_entry *iter;
|
||||||
|
|
||||||
|
@ -217,10 +216,10 @@ static void perf_session__insert_output_hist_entry(struct rb_root *root,
|
||||||
}
|
}
|
||||||
|
|
||||||
rb_link_node(&he->rb_node, parent, p);
|
rb_link_node(&he->rb_node, parent, p);
|
||||||
rb_insert_color(&he->rb_node, root);
|
rb_insert_color(&he->rb_node, entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
|
u64 hists__output_resort(struct hists *self)
|
||||||
{
|
{
|
||||||
struct rb_root tmp;
|
struct rb_root tmp;
|
||||||
struct rb_node *next;
|
struct rb_node *next;
|
||||||
|
@ -228,23 +227,21 @@ u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples)
|
||||||
u64 min_callchain_hits;
|
u64 min_callchain_hits;
|
||||||
u64 nr_hists = 0;
|
u64 nr_hists = 0;
|
||||||
|
|
||||||
min_callchain_hits =
|
min_callchain_hits = self->stats.total * (callchain_param.min_percent / 100);
|
||||||
total_samples * (callchain_param.min_percent / 100);
|
|
||||||
|
|
||||||
tmp = RB_ROOT;
|
tmp = RB_ROOT;
|
||||||
next = rb_first(hists);
|
next = rb_first(&self->entries);
|
||||||
|
|
||||||
while (next) {
|
while (next) {
|
||||||
n = rb_entry(next, struct hist_entry, rb_node);
|
n = rb_entry(next, struct hist_entry, rb_node);
|
||||||
next = rb_next(&n->rb_node);
|
next = rb_next(&n->rb_node);
|
||||||
|
|
||||||
rb_erase(&n->rb_node, hists);
|
rb_erase(&n->rb_node, &self->entries);
|
||||||
perf_session__insert_output_hist_entry(&tmp, n,
|
__hists__insert_output_entry(&tmp, n, min_callchain_hits);
|
||||||
min_callchain_hits);
|
|
||||||
++nr_hists;
|
++nr_hists;
|
||||||
}
|
}
|
||||||
|
|
||||||
*hists = tmp;
|
self->entries = tmp;
|
||||||
return nr_hists;
|
return nr_hists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -500,12 +497,9 @@ static size_t hist_entry_callchain__fprintf(FILE *fp, struct hist_entry *self,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hist_entry__snprintf(struct hist_entry *self,
|
int hist_entry__snprintf(struct hist_entry *self, char *s, size_t size,
|
||||||
char *s, size_t size,
|
struct hists *pair_hists, bool show_displacement,
|
||||||
struct perf_session *pair_session,
|
long displacement, bool color, u64 session_total)
|
||||||
bool show_displacement,
|
|
||||||
long displacement, bool color,
|
|
||||||
u64 session_total)
|
|
||||||
{
|
{
|
||||||
struct sort_entry *se;
|
struct sort_entry *se;
|
||||||
u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
|
u64 count, total, count_sys, count_us, count_guest_sys, count_guest_us;
|
||||||
|
@ -515,9 +509,9 @@ int hist_entry__snprintf(struct hist_entry *self,
|
||||||
if (symbol_conf.exclude_other && !self->parent)
|
if (symbol_conf.exclude_other && !self->parent)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (pair_session) {
|
if (pair_hists) {
|
||||||
count = self->pair ? self->pair->count : 0;
|
count = self->pair ? self->pair->count : 0;
|
||||||
total = pair_session->events_stats.total;
|
total = pair_hists->stats.total;
|
||||||
count_sys = self->pair ? self->pair->count_sys : 0;
|
count_sys = self->pair ? self->pair->count_sys : 0;
|
||||||
count_us = self->pair ? self->pair->count_us : 0;
|
count_us = self->pair ? self->pair->count_us : 0;
|
||||||
count_guest_sys = self->pair ? self->pair->count_guest_sys : 0;
|
count_guest_sys = self->pair ? self->pair->count_guest_sys : 0;
|
||||||
|
@ -569,7 +563,7 @@ int hist_entry__snprintf(struct hist_entry *self,
|
||||||
ret += snprintf(s + ret, size - ret, "%11lld", count);
|
ret += snprintf(s + ret, size - ret, "%11lld", count);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pair_session) {
|
if (pair_hists) {
|
||||||
char bf[32];
|
char bf[32];
|
||||||
double old_percent = 0, new_percent = 0, diff;
|
double old_percent = 0, new_percent = 0, diff;
|
||||||
|
|
||||||
|
@ -615,14 +609,12 @@ int hist_entry__snprintf(struct hist_entry *self,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int hist_entry__fprintf(struct hist_entry *self,
|
int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
|
||||||
struct perf_session *pair_session,
|
bool show_displacement, long displacement, FILE *fp,
|
||||||
bool show_displacement,
|
|
||||||
long displacement, FILE *fp,
|
|
||||||
u64 session_total)
|
u64 session_total)
|
||||||
{
|
{
|
||||||
char bf[512];
|
char bf[512];
|
||||||
hist_entry__snprintf(self, bf, sizeof(bf), pair_session,
|
hist_entry__snprintf(self, bf, sizeof(bf), pair_hists,
|
||||||
show_displacement, displacement,
|
show_displacement, displacement,
|
||||||
true, session_total);
|
true, session_total);
|
||||||
return fprintf(fp, "%s\n", bf);
|
return fprintf(fp, "%s\n", bf);
|
||||||
|
@ -644,10 +636,8 @@ static size_t hist_entry__fprintf_callchain(struct hist_entry *self, FILE *fp,
|
||||||
left_margin);
|
left_margin);
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t perf_session__fprintf_hists(struct rb_root *hists,
|
size_t hists__fprintf(struct hists *self, struct hists *pair,
|
||||||
struct perf_session *pair,
|
bool show_displacement, FILE *fp)
|
||||||
bool show_displacement, FILE *fp,
|
|
||||||
u64 session_total)
|
|
||||||
{
|
{
|
||||||
struct sort_entry *se;
|
struct sort_entry *se;
|
||||||
struct rb_node *nd;
|
struct rb_node *nd;
|
||||||
|
@ -753,7 +743,7 @@ size_t perf_session__fprintf_hists(struct rb_root *hists,
|
||||||
fprintf(fp, "\n#\n");
|
fprintf(fp, "\n#\n");
|
||||||
|
|
||||||
print_entries:
|
print_entries:
|
||||||
for (nd = rb_first(hists); nd; nd = rb_next(nd)) {
|
for (nd = rb_first(&self->entries); nd; nd = rb_next(nd)) {
|
||||||
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
struct hist_entry *h = rb_entry(nd, struct hist_entry, rb_node);
|
||||||
|
|
||||||
if (show_displacement) {
|
if (show_displacement) {
|
||||||
|
@ -765,10 +755,10 @@ print_entries:
|
||||||
++position;
|
++position;
|
||||||
}
|
}
|
||||||
ret += hist_entry__fprintf(h, pair, show_displacement,
|
ret += hist_entry__fprintf(h, pair, show_displacement,
|
||||||
displacement, fp, session_total);
|
displacement, fp, self->stats.total);
|
||||||
|
|
||||||
if (symbol_conf.use_callchain)
|
if (symbol_conf.use_callchain)
|
||||||
ret += hist_entry__fprintf_callchain(h, fp, session_total);
|
ret += hist_entry__fprintf_callchain(h, fp, self->stats.total);
|
||||||
|
|
||||||
if (h->ms.map == NULL && verbose > 1) {
|
if (h->ms.map == NULL && verbose > 1) {
|
||||||
__map_groups__fprintf_maps(&h->thread->mg,
|
__map_groups__fprintf_maps(&h->thread->mg,
|
||||||
|
|
|
@ -6,34 +6,40 @@
|
||||||
|
|
||||||
extern struct callchain_param callchain_param;
|
extern struct callchain_param callchain_param;
|
||||||
|
|
||||||
struct perf_session;
|
|
||||||
struct hist_entry;
|
struct hist_entry;
|
||||||
struct addr_location;
|
struct addr_location;
|
||||||
struct symbol;
|
struct symbol;
|
||||||
struct rb_root;
|
struct rb_root;
|
||||||
|
|
||||||
struct hist_entry *__perf_session__add_hist_entry(struct rb_root *hists,
|
struct events_stats {
|
||||||
struct addr_location *al,
|
u64 total;
|
||||||
struct symbol *parent,
|
u64 lost;
|
||||||
u64 count);
|
};
|
||||||
|
|
||||||
|
struct hists {
|
||||||
|
struct rb_node rb_node;
|
||||||
|
struct rb_root entries;
|
||||||
|
struct events_stats stats;
|
||||||
|
u64 config;
|
||||||
|
u64 event_stream;
|
||||||
|
u32 type;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct hist_entry *__hists__add_entry(struct hists *self,
|
||||||
|
struct addr_location *al,
|
||||||
|
struct symbol *parent, u64 count);
|
||||||
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
|
extern int64_t hist_entry__cmp(struct hist_entry *, struct hist_entry *);
|
||||||
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
|
extern int64_t hist_entry__collapse(struct hist_entry *, struct hist_entry *);
|
||||||
int hist_entry__fprintf(struct hist_entry *self,
|
int hist_entry__fprintf(struct hist_entry *self, struct hists *pair_hists,
|
||||||
struct perf_session *pair_session,
|
bool show_displacement, long displacement, FILE *fp,
|
||||||
bool show_displacement,
|
u64 total);
|
||||||
long displacement, FILE *fp,
|
int hist_entry__snprintf(struct hist_entry *self, char *bf, size_t size,
|
||||||
u64 session_total);
|
struct hists *pair_hists, bool show_displacement,
|
||||||
int hist_entry__snprintf(struct hist_entry *self,
|
long displacement, bool color, u64 total);
|
||||||
char *bf, size_t size,
|
|
||||||
struct perf_session *pair_session,
|
|
||||||
bool show_displacement, long displacement,
|
|
||||||
bool color, u64 session_total);
|
|
||||||
void hist_entry__free(struct hist_entry *);
|
void hist_entry__free(struct hist_entry *);
|
||||||
|
|
||||||
u64 perf_session__output_resort(struct rb_root *hists, u64 total_samples);
|
u64 hists__output_resort(struct hists *self);
|
||||||
void perf_session__collapse_resort(struct rb_root *hists);
|
void hists__collapse_resort(struct hists *self);
|
||||||
size_t perf_session__fprintf_hists(struct rb_root *hists,
|
size_t hists__fprintf(struct hists *self, struct hists *pair,
|
||||||
struct perf_session *pair,
|
bool show_displacement, FILE *fp);
|
||||||
bool show_displacement, FILE *fp,
|
|
||||||
u64 session_total);
|
|
||||||
#endif /* __PERF_HIST_H */
|
#endif /* __PERF_HIST_H */
|
||||||
|
|
|
@ -89,7 +89,7 @@ struct perf_session *perf_session__new(const char *filename, int mode, bool forc
|
||||||
|
|
||||||
memcpy(self->filename, filename, len);
|
memcpy(self->filename, filename, len);
|
||||||
self->threads = RB_ROOT;
|
self->threads = RB_ROOT;
|
||||||
self->stats_by_id = RB_ROOT;
|
self->hists_tree = RB_ROOT;
|
||||||
self->last_match = NULL;
|
self->last_match = NULL;
|
||||||
self->mmap_window = 32;
|
self->mmap_window = 32;
|
||||||
self->cwd = NULL;
|
self->cwd = NULL;
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#ifndef __PERF_SESSION_H
|
#ifndef __PERF_SESSION_H
|
||||||
#define __PERF_SESSION_H
|
#define __PERF_SESSION_H
|
||||||
|
|
||||||
|
#include "hist.h"
|
||||||
#include "event.h"
|
#include "event.h"
|
||||||
#include "header.h"
|
#include "header.h"
|
||||||
#include "symbol.h"
|
#include "symbol.h"
|
||||||
|
@ -28,11 +29,16 @@ struct perf_session {
|
||||||
struct thread *last_match;
|
struct thread *last_match;
|
||||||
struct machine host_machine;
|
struct machine host_machine;
|
||||||
struct rb_root machines;
|
struct rb_root machines;
|
||||||
struct events_stats events_stats;
|
struct rb_root hists_tree;
|
||||||
struct rb_root stats_by_id;
|
|
||||||
unsigned long event_total[PERF_RECORD_MAX];
|
unsigned long event_total[PERF_RECORD_MAX];
|
||||||
unsigned long unknown_events;
|
unsigned long unknown_events;
|
||||||
struct rb_root hists;
|
/*
|
||||||
|
* FIXME: should point to the first entry in hists_tree and
|
||||||
|
* be a hists instance. Right now its only 'report'
|
||||||
|
* that is using ->hists_tree while all the rest use
|
||||||
|
* ->hists.
|
||||||
|
*/
|
||||||
|
struct hists hists;
|
||||||
u64 sample_type;
|
u64 sample_type;
|
||||||
int fd;
|
int fd;
|
||||||
bool fd_pipe;
|
bool fd_pipe;
|
||||||
|
|
Загрузка…
Ссылка в новой задаче