perf diff: Fix to work with new hists design
The perf diff command is broken since:
perf hists: Threaded addition and sorting of entries
commit 1980c2ebd7
Several places were broken:
- hists data need to be collected into opened sessions instead
of into events
- session's hists data need to be initialized properly when the
session is created
- hist_entry__pcnt_snprintf: the percentage and displacement
buffer preparation must not use 'ret' because it's used
as a pointer to the final buffer
Signed-off-by: Jiri Olsa <jolsa@redhat.com>
Cc: Corey Ashford <cjashfor@linux.vnet.ibm.com>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Peter Zijlstra <a.p.zijlstra@chello.nl>
Link: http://lkml.kernel.org/r/20120322133726.GB1601@m.brq.redhat.com
Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
parent
5d7be90ed5
commit
4bf9ce1b5e
|
@ -24,6 +24,11 @@ static char diff__default_sort_order[] = "dso,symbol";
|
||||||
static bool force;
|
static bool force;
|
||||||
static bool show_displacement;
|
static bool show_displacement;
|
||||||
|
|
||||||
|
struct perf_diff {
|
||||||
|
struct perf_tool tool;
|
||||||
|
struct perf_session *session;
|
||||||
|
};
|
||||||
|
|
||||||
static int hists__add_entry(struct hists *self,
|
static int hists__add_entry(struct hists *self,
|
||||||
struct addr_location *al, u64 period)
|
struct addr_location *al, u64 period)
|
||||||
{
|
{
|
||||||
|
@ -32,12 +37,14 @@ static int hists__add_entry(struct hists *self,
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int diff__process_sample_event(struct perf_tool *tool __used,
|
static int diff__process_sample_event(struct perf_tool *tool,
|
||||||
union perf_event *event,
|
union perf_event *event,
|
||||||
struct perf_sample *sample,
|
struct perf_sample *sample,
|
||||||
struct perf_evsel *evsel __used,
|
struct perf_evsel *evsel __used,
|
||||||
struct machine *machine)
|
struct machine *machine)
|
||||||
{
|
{
|
||||||
|
struct perf_diff *_diff = container_of(tool, struct perf_diff, tool);
|
||||||
|
struct perf_session *session = _diff->session;
|
||||||
struct addr_location al;
|
struct addr_location al;
|
||||||
|
|
||||||
if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
|
if (perf_event__preprocess_sample(event, machine, &al, sample, NULL) < 0) {
|
||||||
|
@ -49,24 +56,26 @@ static int diff__process_sample_event(struct perf_tool *tool __used,
|
||||||
if (al.filtered || al.sym == NULL)
|
if (al.filtered || al.sym == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (hists__add_entry(&evsel->hists, &al, sample->period)) {
|
if (hists__add_entry(&session->hists, &al, sample->period)) {
|
||||||
pr_warning("problem incrementing symbol period, skipping event\n");
|
pr_warning("problem incrementing symbol period, skipping event\n");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
evsel->hists.stats.total_period += sample->period;
|
session->hists.stats.total_period += sample->period;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct perf_tool perf_diff = {
|
static struct perf_diff diff = {
|
||||||
.sample = diff__process_sample_event,
|
.tool = {
|
||||||
.mmap = perf_event__process_mmap,
|
.sample = diff__process_sample_event,
|
||||||
.comm = perf_event__process_comm,
|
.mmap = perf_event__process_mmap,
|
||||||
.exit = perf_event__process_task,
|
.comm = perf_event__process_comm,
|
||||||
.fork = perf_event__process_task,
|
.exit = perf_event__process_task,
|
||||||
.lost = perf_event__process_lost,
|
.fork = perf_event__process_task,
|
||||||
.ordered_samples = true,
|
.lost = perf_event__process_lost,
|
||||||
.ordering_requires_timestamps = true,
|
.ordered_samples = true,
|
||||||
|
.ordering_requires_timestamps = true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
static void perf_session__insert_hist_entry_by_name(struct rb_root *root,
|
||||||
|
@ -107,12 +116,6 @@ static void hists__resort_entries(struct hists *self)
|
||||||
self->entries = tmp;
|
self->entries = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hists__set_positions(struct hists *self)
|
|
||||||
{
|
|
||||||
hists__output_resort(self);
|
|
||||||
hists__resort_entries(self);
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct hist_entry *hists__find_entry(struct hists *self,
|
static struct hist_entry *hists__find_entry(struct hists *self,
|
||||||
struct hist_entry *he)
|
struct hist_entry *he)
|
||||||
{
|
{
|
||||||
|
@ -146,30 +149,37 @@ static void hists__match(struct hists *older, struct hists *newer)
|
||||||
static int __cmd_diff(void)
|
static int __cmd_diff(void)
|
||||||
{
|
{
|
||||||
int ret, i;
|
int ret, i;
|
||||||
|
#define older (session[0])
|
||||||
|
#define newer (session[1])
|
||||||
struct perf_session *session[2];
|
struct perf_session *session[2];
|
||||||
|
|
||||||
session[0] = perf_session__new(input_old, O_RDONLY, force, false, &perf_diff);
|
older = perf_session__new(input_old, O_RDONLY, force, false,
|
||||||
session[1] = perf_session__new(input_new, O_RDONLY, force, false, &perf_diff);
|
&diff.tool);
|
||||||
|
newer = perf_session__new(input_new, O_RDONLY, force, false,
|
||||||
|
&diff.tool);
|
||||||
if (session[0] == NULL || session[1] == NULL)
|
if (session[0] == NULL || session[1] == NULL)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
for (i = 0; i < 2; ++i) {
|
for (i = 0; i < 2; ++i) {
|
||||||
ret = perf_session__process_events(session[i], &perf_diff);
|
diff.session = session[i];
|
||||||
|
ret = perf_session__process_events(session[i], &diff.tool);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out_delete;
|
goto out_delete;
|
||||||
|
hists__output_resort(&session[i]->hists);
|
||||||
}
|
}
|
||||||
|
|
||||||
hists__output_resort(&session[1]->hists);
|
|
||||||
if (show_displacement)
|
if (show_displacement)
|
||||||
hists__set_positions(&session[0]->hists);
|
hists__resort_entries(&older->hists);
|
||||||
|
|
||||||
hists__match(&session[0]->hists, &session[1]->hists);
|
hists__match(&older->hists, &newer->hists);
|
||||||
hists__fprintf(&session[1]->hists, &session[0]->hists,
|
hists__fprintf(&newer->hists, &older->hists,
|
||||||
show_displacement, true, 0, 0, stdout);
|
show_displacement, true, 0, 0, stdout);
|
||||||
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]);
|
||||||
return ret;
|
return ret;
|
||||||
|
#undef older
|
||||||
|
#undef newer
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char * const diff_usage[] = {
|
static const char * const diff_usage[] = {
|
||||||
|
|
|
@ -34,7 +34,7 @@ int __perf_evsel__sample_size(u64 sample_type)
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hists__init(struct hists *hists)
|
void hists__init(struct hists *hists)
|
||||||
{
|
{
|
||||||
memset(hists, 0, sizeof(*hists));
|
memset(hists, 0, sizeof(*hists));
|
||||||
hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
|
hists->entries_in_array[0] = hists->entries_in_array[1] = RB_ROOT;
|
||||||
|
|
|
@ -170,4 +170,6 @@ static inline int perf_evsel__sample_size(struct perf_evsel *evsel)
|
||||||
return __perf_evsel__sample_size(evsel->attr.sample_type);
|
return __perf_evsel__sample_size(evsel->attr.sample_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hists__init(struct hists *hists);
|
||||||
|
|
||||||
#endif /* __PERF_EVSEL_H */
|
#endif /* __PERF_EVSEL_H */
|
||||||
|
|
|
@ -891,9 +891,9 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
|
||||||
diff = new_percent - old_percent;
|
diff = new_percent - old_percent;
|
||||||
|
|
||||||
if (fabs(diff) >= 0.01)
|
if (fabs(diff) >= 0.01)
|
||||||
ret += scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
|
scnprintf(bf, sizeof(bf), "%+4.2F%%", diff);
|
||||||
else
|
else
|
||||||
ret += scnprintf(bf, sizeof(bf), " ");
|
scnprintf(bf, sizeof(bf), " ");
|
||||||
|
|
||||||
if (sep)
|
if (sep)
|
||||||
ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
|
ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
|
||||||
|
@ -902,9 +902,9 @@ static int hist_entry__pcnt_snprintf(struct hist_entry *he, char *s,
|
||||||
|
|
||||||
if (show_displacement) {
|
if (show_displacement) {
|
||||||
if (displacement)
|
if (displacement)
|
||||||
ret += scnprintf(bf, sizeof(bf), "%+4ld", displacement);
|
scnprintf(bf, sizeof(bf), "%+4ld", displacement);
|
||||||
else
|
else
|
||||||
ret += scnprintf(bf, sizeof(bf), " ");
|
scnprintf(bf, sizeof(bf), " ");
|
||||||
|
|
||||||
if (sep)
|
if (sep)
|
||||||
ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
|
ret += scnprintf(s + ret, size - ret, "%c%s", *sep, bf);
|
||||||
|
|
|
@ -140,6 +140,7 @@ struct perf_session *perf_session__new(const char *filename, int mode,
|
||||||
INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
|
INIT_LIST_HEAD(&self->ordered_samples.sample_cache);
|
||||||
INIT_LIST_HEAD(&self->ordered_samples.to_free);
|
INIT_LIST_HEAD(&self->ordered_samples.to_free);
|
||||||
machine__init(&self->host_machine, "", HOST_KERNEL_ID);
|
machine__init(&self->host_machine, "", HOST_KERNEL_ID);
|
||||||
|
hists__init(&self->hists);
|
||||||
|
|
||||||
if (mode == O_RDONLY) {
|
if (mode == O_RDONLY) {
|
||||||
if (perf_session__open(self, force) < 0)
|
if (perf_session__open(self, force) < 0)
|
||||||
|
|
Loading…
Reference in a new issue