Skip to content

Commit 2a09a84

Browse files
Jin Yaoacmel
authored andcommitted
perf diff: Support hot streams comparison
This patch enables perf-diff with "--stream" option. "--stream": Enable hot streams comparison Now let's see example. perf record -b ... Generate perf.data.old with branch data perf record -b ... Generate perf.data with branch data perf diff --stream [ Matched hot streams ] hot chain pair 1: cycles: 1, hits: 27.77% cycles: 1, hits: 9.24% --------------------------- -------------------------- main div.c:39 main div.c:39 main div.c:44 main div.c:44 hot chain pair 2: cycles: 34, hits: 20.06% cycles: 27, hits: 16.98% --------------------------- -------------------------- __random_r random_r.c:360 __random_r random_r.c:360 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:380 __random_r random_r.c:380 __random_r random_r.c:357 __random_r random_r.c:357 __random random.c:293 __random random.c:293 __random random.c:293 __random random.c:293 __random random.c:291 __random random.c:291 __random random.c:291 __random random.c:291 __random random.c:291 __random random.c:291 __random random.c:288 __random random.c:288 rand rand.c:27 rand rand.c:27 rand rand.c:26 rand rand.c:26 rand@plt rand@plt rand@plt rand@plt compute_flag div.c:25 compute_flag div.c:25 compute_flag div.c:22 compute_flag div.c:22 main div.c:40 main div.c:40 main div.c:40 main div.c:40 main div.c:39 main div.c:39 hot chain pair 3: cycles: 9, hits: 4.48% cycles: 6, hits: 4.51% --------------------------- -------------------------- __random_r random_r.c:360 __random_r random_r.c:360 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:380 __random_r random_r.c:380 [ Hot streams in old perf data only ] hot chain 1: cycles: 18, hits: 6.75% -------------------------- __random_r random_r.c:360 __random_r random_r.c:388 __random_r random_r.c:388 __random_r random_r.c:380 __random_r random_r.c:357 __random random.c:293 __random random.c:293 __random random.c:291 __random random.c:291 __random random.c:291 __random random.c:288 rand rand.c:27 rand rand.c:26 rand@plt rand@plt compute_flag div.c:25 compute_flag div.c:22 main div.c:40 hot chain 2: cycles: 29, hits: 2.78% -------------------------- compute_flag div.c:22 main div.c:40 main div.c:40 main div.c:39 [ Hot streams in new perf data only ] hot chain 1: cycles: 4, hits: 4.54% -------------------------- main div.c:42 compute_flag div.c:28 hot chain 2: cycles: 5, hits: 3.51% -------------------------- main div.c:39 main div.c:44 main div.c:42 compute_flag div.c:28 Signed-off-by: Jin Yao <yao.jin@linux.intel.com> Acked-by: Jiri Olsa <jolsa@kernel.org> Link: https://lore.kernel.org/r/20201009022845.13141-8-yao.jin@linux.intel.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
1 parent 5bbd6ba commit 2a09a84

2 files changed

Lines changed: 110 additions & 13 deletions

File tree

tools/perf/Documentation/perf-diff.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,10 @@ OPTIONS
182182
--tid=::
183183
Only diff samples for given thread ID (comma separated list).
184184

185+
--stream::
186+
Enable hot streams comparison. Stream can be a callchain which is
187+
aggregated by the branch records from samples.
188+
185189
COMPARISON
186190
----------
187191
The comparison is governed by the baseline file. The baseline perf.data

tools/perf/builtin-diff.c

Lines changed: 106 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "util/map.h"
2626
#include "util/spark.h"
2727
#include "util/block-info.h"
28+
#include "util/stream.h"
2829
#include <linux/err.h>
2930
#include <linux/zalloc.h>
3031
#include <subcmd/pager.h>
@@ -42,6 +43,7 @@ struct perf_diff {
4243
int range_size;
4344
int range_num;
4445
bool has_br_stack;
46+
bool stream;
4547
};
4648

4749
/* Diff command specific HPP columns. */
@@ -72,6 +74,7 @@ struct data__file {
7274
struct perf_data data;
7375
int idx;
7476
struct hists *hists;
77+
struct evlist_streams *evlist_streams;
7578
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
7679
};
7780

@@ -106,6 +109,7 @@ enum {
106109
COMPUTE_DELTA_ABS,
107110
COMPUTE_CYCLES,
108111
COMPUTE_MAX,
112+
COMPUTE_STREAM, /* After COMPUTE_MAX to avoid use current compute arrays */
109113
};
110114

111115
const char *compute_names[COMPUTE_MAX] = {
@@ -393,6 +397,11 @@ static int diff__process_sample_event(struct perf_tool *tool,
393397
struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
394398
struct addr_location al;
395399
struct hists *hists = evsel__hists(evsel);
400+
struct hist_entry_iter iter = {
401+
.evsel = evsel,
402+
.sample = sample,
403+
.ops = &hist_iter_normal,
404+
};
396405
int ret = -1;
397406

398407
if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
@@ -411,14 +420,8 @@ static int diff__process_sample_event(struct perf_tool *tool,
411420
goto out_put;
412421
}
413422

414-
if (compute != COMPUTE_CYCLES) {
415-
if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
416-
true)) {
417-
pr_warning("problem incrementing symbol period, "
418-
"skipping event\n");
419-
goto out_put;
420-
}
421-
} else {
423+
switch (compute) {
424+
case COMPUTE_CYCLES:
422425
if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
423426
NULL, NULL, sample, true)) {
424427
pr_warning("problem incrementing symbol period, "
@@ -428,6 +431,23 @@ static int diff__process_sample_event(struct perf_tool *tool,
428431

429432
hist__account_cycles(sample->branch_stack, &al, sample, false,
430433
NULL);
434+
break;
435+
436+
case COMPUTE_STREAM:
437+
if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
438+
NULL)) {
439+
pr_debug("problem adding hist entry, skipping event\n");
440+
goto out_put;
441+
}
442+
break;
443+
444+
default:
445+
if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
446+
true)) {
447+
pr_warning("problem incrementing symbol period, "
448+
"skipping event\n");
449+
goto out_put;
450+
}
431451
}
432452

433453
/*
@@ -996,10 +1016,55 @@ static void data_process(void)
9961016
}
9971017
}
9981018

1019+
static int process_base_stream(struct data__file *data_base,
1020+
struct data__file *data_pair,
1021+
const char *title __maybe_unused)
1022+
{
1023+
struct evlist *evlist_base = data_base->session->evlist;
1024+
struct evlist *evlist_pair = data_pair->session->evlist;
1025+
struct evsel *evsel_base, *evsel_pair;
1026+
struct evsel_streams *es_base, *es_pair;
1027+
1028+
evlist__for_each_entry(evlist_base, evsel_base) {
1029+
evsel_pair = evsel_match(evsel_base, evlist_pair);
1030+
if (!evsel_pair)
1031+
continue;
1032+
1033+
es_base = evsel_streams__entry(data_base->evlist_streams,
1034+
evsel_base->idx);
1035+
if (!es_base)
1036+
return -1;
1037+
1038+
es_pair = evsel_streams__entry(data_pair->evlist_streams,
1039+
evsel_pair->idx);
1040+
if (!es_pair)
1041+
return -1;
1042+
1043+
evsel_streams__match(es_base, es_pair);
1044+
evsel_streams__report(es_base, es_pair);
1045+
}
1046+
1047+
return 0;
1048+
}
1049+
1050+
static void stream_process(void)
1051+
{
1052+
/*
1053+
* Stream comparison only supports two data files.
1054+
* perf.data.old and perf.data. data__files[0] is perf.data.old,
1055+
* data__files[1] is perf.data.
1056+
*/
1057+
process_base_stream(&data__files[0], &data__files[1],
1058+
"# Output based on old perf data:\n#\n");
1059+
}
1060+
9991061
static void data__free(struct data__file *d)
10001062
{
10011063
int col;
10021064

1065+
if (d->evlist_streams)
1066+
evlist_streams__delete(d->evlist_streams);
1067+
10031068
for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
10041069
struct diff_hpp_fmt *fmt = &d->fmt[col];
10051070

@@ -1153,9 +1218,19 @@ static int __cmd_diff(void)
11531218

11541219
if (pdiff.ptime_range)
11551220
zfree(&pdiff.ptime_range);
1221+
1222+
if (compute == COMPUTE_STREAM) {
1223+
d->evlist_streams = evlist__create_streams(
1224+
d->session->evlist, 5);
1225+
if (!d->evlist_streams)
1226+
goto out_delete;
1227+
}
11561228
}
11571229

1158-
data_process();
1230+
if (compute == COMPUTE_STREAM)
1231+
stream_process();
1232+
else
1233+
data_process();
11591234

11601235
out_delete:
11611236
data__for_each_file(i, d) {
@@ -1228,6 +1303,8 @@ static const struct option options[] = {
12281303
"only consider symbols in these pids"),
12291304
OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
12301305
"only consider symbols in these tids"),
1306+
OPT_BOOLEAN(0, "stream", &pdiff.stream,
1307+
"Enable hot streams comparison."),
12311308
OPT_END()
12321309
};
12331310

@@ -1887,6 +1964,9 @@ int cmd_diff(int argc, const char **argv)
18871964
if (cycles_hist && (compute != COMPUTE_CYCLES))
18881965
usage_with_options(diff_usage, options);
18891966

1967+
if (pdiff.stream)
1968+
compute = COMPUTE_STREAM;
1969+
18901970
symbol__annotation_init();
18911971

18921972
if (symbol__init(NULL) < 0)
@@ -1898,13 +1978,26 @@ int cmd_diff(int argc, const char **argv)
18981978
if (check_file_brstack() < 0)
18991979
return -1;
19001980

1901-
if (compute == COMPUTE_CYCLES && !pdiff.has_br_stack)
1981+
if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
1982+
&& !pdiff.has_br_stack) {
19021983
return -1;
1984+
}
19031985

1904-
if (ui_init() < 0)
1905-
return -1;
1986+
if (compute == COMPUTE_STREAM) {
1987+
symbol_conf.show_branchflag_count = true;
1988+
symbol_conf.disable_add2line_warn = true;
1989+
callchain_param.mode = CHAIN_FLAT;
1990+
callchain_param.key = CCKEY_SRCLINE;
1991+
callchain_param.branch_callstack = 1;
1992+
symbol_conf.use_callchain = true;
1993+
callchain_register_param(&callchain_param);
1994+
sort_order = "srcline,symbol,dso";
1995+
} else {
1996+
if (ui_init() < 0)
1997+
return -1;
19061998

1907-
sort__mode = SORT_MODE__DIFF;
1999+
sort__mode = SORT_MODE__DIFF;
2000+
}
19082001

19092002
if (setup_sorting(NULL) < 0)
19102003
usage_with_options(diff_usage, options);

0 commit comments

Comments
 (0)