Update Linux to v5.10.109
Sourced from [1]
[1] https://cdn.kernel.org/pub/linux/kernel/v5.x/linux-5.10.109.tar.xz
Change-Id: I19bca9fc6762d4e63bcf3e4cba88bbe560d9c76c
Signed-off-by: Olivier Deprez <olivier.deprez@arm.com>
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 2656822..cefc715 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -23,6 +23,9 @@
#include "util/time-utils.h"
#include "util/annotate.h"
#include "util/map.h"
+#include "util/spark.h"
+#include "util/block-info.h"
+#include "util/stream.h"
#include <linux/err.h>
#include <linux/zalloc.h>
#include <subcmd/pager.h>
@@ -40,6 +43,7 @@
int range_size;
int range_num;
bool has_br_stack;
+ bool stream;
};
/* Diff command specific HPP columns. */
@@ -53,6 +57,7 @@
PERF_HPP_DIFF__FORMULA,
PERF_HPP_DIFF__DELTA_ABS,
PERF_HPP_DIFF__CYCLES,
+ PERF_HPP_DIFF__CYCLES_HIST,
PERF_HPP_DIFF__MAX_INDEX
};
@@ -69,6 +74,7 @@
struct perf_data data;
int idx;
struct hists *hists;
+ struct evlist_streams *evlist_streams;
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
};
@@ -87,6 +93,7 @@
static bool show_period;
static bool show_formula;
static bool show_baseline_only;
+static bool cycles_hist;
static unsigned int sort_compute = 1;
static s64 compute_wdiff_w1;
@@ -95,8 +102,6 @@
static const char *cpu_list;
static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
-static struct addr_location dummy_al;
-
enum {
COMPUTE_DELTA,
COMPUTE_RATIO,
@@ -104,6 +109,7 @@
COMPUTE_DELTA_ABS,
COMPUTE_CYCLES,
COMPUTE_MAX,
+ COMPUTE_STREAM, /* After COMPUTE_MAX to avoid use current compute arrays */
};
const char *compute_names[COMPUTE_MAX] = {
@@ -164,6 +170,10 @@
[PERF_HPP_DIFF__CYCLES] = {
.name = "[Program Block Range] Cycles Diff",
.width = 70,
+ },
+ [PERF_HPP_DIFF__CYCLES_HIST] = {
+ .name = "stddev/Hist",
+ .width = NUM_SPARKS + 9,
}
};
@@ -387,6 +397,11 @@
struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
struct addr_location al;
struct hists *hists = evsel__hists(evsel);
+ struct hist_entry_iter iter = {
+ .evsel = evsel,
+ .sample = sample,
+ .ops = &hist_iter_normal,
+ };
int ret = -1;
if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
@@ -405,14 +420,8 @@
goto out_put;
}
- if (compute != COMPUTE_CYCLES) {
- if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
- true)) {
- pr_warning("problem incrementing symbol period, "
- "skipping event\n");
- goto out_put;
- }
- } else {
+ switch (compute) {
+ case COMPUTE_CYCLES:
if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
NULL, NULL, sample, true)) {
pr_warning("problem incrementing symbol period, "
@@ -420,7 +429,25 @@
goto out_put;
}
- hist__account_cycles(sample->branch_stack, &al, sample, false);
+ hist__account_cycles(sample->branch_stack, &al, sample, false,
+ NULL);
+ break;
+
+ case COMPUTE_STREAM:
+ if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
+ NULL)) {
+ pr_debug("problem adding hist entry, skipping event\n");
+ goto out_put;
+ }
+ break;
+
+ default:
+ if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
+ true)) {
+ pr_warning("problem incrementing symbol period, "
+ "skipping event\n");
+ goto out_put;
+ }
}
/*
@@ -448,6 +475,7 @@
.fork = perf_event__process_fork,
.lost = perf_event__process_lost,
.namespaces = perf_event__process_namespaces,
+ .cgroup = perf_event__process_cgroup,
.ordered_events = true,
.ordering_requires_timestamps = true,
},
@@ -459,7 +487,7 @@
struct evsel *e;
evlist__for_each_entry(evlist, e) {
- if (perf_evsel__match2(evsel, e))
+ if (evsel__match2(evsel, e))
return e;
}
@@ -530,41 +558,6 @@
}
}
-static int64_t block_cmp(struct perf_hpp_fmt *fmt __maybe_unused,
- struct hist_entry *left, struct hist_entry *right)
-{
- struct block_info *bi_l = left->block_info;
- struct block_info *bi_r = right->block_info;
- int cmp;
-
- if (!bi_l->sym || !bi_r->sym) {
- if (!bi_l->sym && !bi_r->sym)
- return 0;
- else if (!bi_l->sym)
- return -1;
- else
- return 1;
- }
-
- if (bi_l->sym == bi_r->sym) {
- if (bi_l->start == bi_r->start) {
- if (bi_l->end == bi_r->end)
- return 0;
- else
- return (int64_t)(bi_r->end - bi_l->end);
- } else
- return (int64_t)(bi_r->start - bi_l->start);
- } else {
- cmp = strcmp(bi_l->sym->name, bi_r->sym->name);
- return cmp;
- }
-
- if (bi_l->sym->start != bi_r->sym->start)
- return (int64_t)(bi_r->sym->start - bi_l->sym->start);
-
- return (int64_t)(bi_r->sym->end - bi_l->sym->end);
-}
-
static int64_t block_cycles_diff_cmp(struct hist_entry *left,
struct hist_entry *right)
{
@@ -593,87 +586,19 @@
INIT_LIST_HEAD(&bh->block_fmt.list);
INIT_LIST_HEAD(&bh->block_fmt.sort_list);
- bh->block_fmt.cmp = block_cmp;
+ bh->block_fmt.cmp = block_info__cmp;
bh->block_fmt.sort = block_sort;
perf_hpp_list__register_sort_field(&bh->block_list,
&bh->block_fmt);
bh->valid = true;
}
-static void init_block_info(struct block_info *bi, struct symbol *sym,
- struct cyc_hist *ch, int offset)
-{
- bi->sym = sym;
- bi->start = ch->start;
- bi->end = offset;
- bi->cycles = ch->cycles;
- bi->cycles_aggr = ch->cycles_aggr;
- bi->num = ch->num;
- bi->num_aggr = ch->num_aggr;
-}
-
-static int process_block_per_sym(struct hist_entry *he)
-{
- struct annotation *notes;
- struct cyc_hist *ch;
- struct block_hist *bh;
-
- if (!he->ms.map || !he->ms.sym)
- return 0;
-
- notes = symbol__annotation(he->ms.sym);
- if (!notes || !notes->src || !notes->src->cycles_hist)
- return 0;
-
- bh = container_of(he, struct block_hist, he);
- init_block_hist(bh);
-
- ch = notes->src->cycles_hist;
- for (unsigned int i = 0; i < symbol__size(he->ms.sym); i++) {
- if (ch[i].num_aggr) {
- struct block_info *bi;
- struct hist_entry *he_block;
-
- bi = block_info__new();
- if (!bi)
- return -1;
-
- init_block_info(bi, he->ms.sym, &ch[i], i);
- he_block = hists__add_entry_block(&bh->block_hists,
- &dummy_al, bi);
- if (!he_block) {
- block_info__put(bi);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-static int block_pair_cmp(struct hist_entry *a, struct hist_entry *b)
-{
- struct block_info *bi_a = a->block_info;
- struct block_info *bi_b = b->block_info;
- int cmp;
-
- if (!bi_a->sym || !bi_b->sym)
- return -1;
-
- cmp = strcmp(bi_a->sym->name, bi_b->sym->name);
-
- if ((!cmp) && (bi_a->start == bi_b->start) && (bi_a->end == bi_b->end))
- return 0;
-
- return -1;
-}
-
static struct hist_entry *get_block_pair(struct hist_entry *he,
struct hists *hists_pair)
{
struct rb_root_cached *root = hists_pair->entries_in;
struct rb_node *next = rb_first_cached(root);
- int cmp;
+ int64_t cmp;
while (next != NULL) {
struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
@@ -681,7 +606,7 @@
next = rb_next(&he_pair->rb_node_in);
- cmp = block_pair_cmp(he_pair, he);
+ cmp = __block_info__cmp(he_pair, he);
if (!cmp)
return he_pair;
}
@@ -689,6 +614,21 @@
return NULL;
}
+static void init_spark_values(unsigned long *svals, int num)
+{
+ for (int i = 0; i < num; i++)
+ svals[i] = 0;
+}
+
+static void update_spark_value(unsigned long *svals, int num,
+ struct stats *stats, u64 val)
+{
+ int n = stats->n;
+
+ if (n < num)
+ svals[n] = val;
+}
+
static void compute_cycles_diff(struct hist_entry *he,
struct hist_entry *pair)
{
@@ -697,6 +637,26 @@
pair->diff.cycles =
pair->block_info->cycles_aggr / pair->block_info->num_aggr -
he->block_info->cycles_aggr / he->block_info->num_aggr;
+
+ if (!cycles_hist)
+ return;
+
+ init_stats(&pair->diff.stats);
+ init_spark_values(pair->diff.svals, NUM_SPARKS);
+
+ for (int i = 0; i < pair->block_info->num; i++) {
+ u64 val;
+
+ if (i >= he->block_info->num || i >= NUM_SPARKS)
+ break;
+
+ val = llabs(pair->block_info->cycles_spark[i] -
+ he->block_info->cycles_spark[i]);
+
+ update_spark_value(pair->diff.svals, NUM_SPARKS,
+ &pair->diff.stats, val);
+ update_stats(&pair->diff.stats, val);
+ }
}
}
@@ -720,13 +680,6 @@
}
}
-static int filter_cb(struct hist_entry *he, void *arg __maybe_unused)
-{
- /* Skip the calculation of column length in output_resort */
- he->filtered = true;
- return 0;
-}
-
static void hists__precompute(struct hists *hists)
{
struct rb_root_cached *root;
@@ -747,8 +700,11 @@
he = rb_entry(next, struct hist_entry, rb_node_in);
next = rb_next(&he->rb_node_in);
- if (compute == COMPUTE_CYCLES)
- process_block_per_sym(he);
+ if (compute == COMPUTE_CYCLES) {
+ bh = container_of(he, struct block_hist, he);
+ init_block_hist(bh);
+ block_info__process_sym(he, bh, NULL, 0);
+ }
data__for_each_file_new(i, d) {
pair = get_pair_data(he, d);
@@ -767,16 +723,18 @@
compute_wdiff(he, pair);
break;
case COMPUTE_CYCLES:
- process_block_per_sym(pair);
- bh = container_of(he, struct block_hist, he);
pair_bh = container_of(pair, struct block_hist,
he);
+ init_block_hist(pair_bh);
+ block_info__process_sym(pair, pair_bh, NULL, 0);
+
+ bh = container_of(he, struct block_hist, he);
if (bh->valid && pair_bh->valid) {
block_hists_match(&bh->block_hists,
&pair_bh->block_hists);
- hists__output_resort_cb(&pair_bh->block_hists,
- NULL, filter_cb);
+ hists__output_resort(&pair_bh->block_hists,
+ NULL);
}
break;
default:
@@ -1043,7 +1001,7 @@
if (!quiet) {
fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
- perf_evsel__name(evsel_base));
+ evsel__name(evsel_base));
}
first = false;
@@ -1052,16 +1010,61 @@
data__fprintf();
/* Don't sort callchain for perf diff */
- perf_evsel__reset_sample_bit(evsel_base, CALLCHAIN);
+ evsel__reset_sample_bit(evsel_base, CALLCHAIN);
hists__process(hists_base);
}
}
+static int process_base_stream(struct data__file *data_base,
+ struct data__file *data_pair,
+ const char *title __maybe_unused)
+{
+ struct evlist *evlist_base = data_base->session->evlist;
+ struct evlist *evlist_pair = data_pair->session->evlist;
+ struct evsel *evsel_base, *evsel_pair;
+ struct evsel_streams *es_base, *es_pair;
+
+ evlist__for_each_entry(evlist_base, evsel_base) {
+ evsel_pair = evsel_match(evsel_base, evlist_pair);
+ if (!evsel_pair)
+ continue;
+
+ es_base = evsel_streams__entry(data_base->evlist_streams,
+ evsel_base->idx);
+ if (!es_base)
+ return -1;
+
+ es_pair = evsel_streams__entry(data_pair->evlist_streams,
+ evsel_pair->idx);
+ if (!es_pair)
+ return -1;
+
+ evsel_streams__match(es_base, es_pair);
+ evsel_streams__report(es_base, es_pair);
+ }
+
+ return 0;
+}
+
+static void stream_process(void)
+{
+ /*
+ * Stream comparison only supports two data files.
+ * perf.data.old and perf.data. data__files[0] is perf.data.old,
+ * data__files[1] is perf.data.
+ */
+ process_base_stream(&data__files[0], &data__files[1],
+ "# Output based on old perf data:\n#\n");
+}
+
static void data__free(struct data__file *d)
{
int col;
+ if (d->evlist_streams)
+ evlist_streams__delete(d->evlist_streams);
+
for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
struct diff_hpp_fmt *fmt = &d->fmt[col];
@@ -1215,9 +1218,21 @@
if (pdiff.ptime_range)
zfree(&pdiff.ptime_range);
+
+ if (compute == COMPUTE_STREAM) {
+ d->evlist_streams = evlist__create_streams(
+ d->session->evlist, 5);
+ if (!d->evlist_streams) {
+ ret = -ENOMEM;
+ goto out_delete;
+ }
+ }
}
- data_process();
+ if (compute == COMPUTE_STREAM)
+ stream_process();
+ else
+ data_process();
out_delete:
data__for_each_file(i, d) {
@@ -1255,6 +1270,9 @@
"Show period values."),
OPT_BOOLEAN('F', "formula", &show_formula,
"Show formula."),
+ OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
+ "Show cycles histogram and standard deviation "
+ "- WARNING: use only with -c cycles."),
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
"dump raw trace in ASCII"),
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -1287,6 +1305,8 @@
"only consider symbols in these pids"),
OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
"only consider symbols in these tids"),
+ OPT_BOOLEAN(0, "stream", &pdiff.stream,
+ "Enable hot streams comparison."),
OPT_END()
};
@@ -1355,7 +1375,8 @@
end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
he->ms.sym);
- if ((start_line != SRCLINE_UNKNOWN) && (end_line != SRCLINE_UNKNOWN)) {
+ if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
+ (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
start_line, end_line, block_he->diff.cycles);
} else {
@@ -1462,6 +1483,90 @@
return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
}
+static int all_zero(unsigned long *vals, int len)
+{
+ int i;
+
+ for (i = 0; i < len; i++)
+ if (vals[i] != 0)
+ return 0;
+ return 1;
+}
+
+static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
+{
+ int printed;
+
+ if (n <= 1)
+ return 0;
+
+ if (n > NUM_SPARKS)
+ n = NUM_SPARKS;
+ if (all_zero(svals, n))
+ return 0;
+
+ printed = print_spark(bf, size, svals, n);
+ printed += scnprintf(bf + printed, size - printed, " ");
+ return printed;
+}
+
+static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
+ struct perf_hpp *hpp, struct hist_entry *he)
+{
+ struct diff_hpp_fmt *dfmt =
+ container_of(fmt, struct diff_hpp_fmt, fmt);
+ struct hist_entry *pair = get_pair_fmt(he, dfmt);
+ struct block_hist *bh = container_of(he, struct block_hist, he);
+ struct block_hist *bh_pair;
+ struct hist_entry *block_he;
+ char spark[32], buf[128];
+ double r;
+ int ret, pad;
+
+ if (!pair) {
+ if (bh->block_idx)
+ hpp->skip = true;
+
+ goto no_print;
+ }
+
+ bh_pair = container_of(pair, struct block_hist, he);
+
+ block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
+ if (!block_he) {
+ hpp->skip = true;
+ goto no_print;
+ }
+
+ ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
+ block_he->diff.stats.n);
+
+ r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
+ avg_stats(&block_he->diff.stats));
+
+ if (ret) {
+ /*
+ * Padding spaces if number of sparks less than NUM_SPARKS
+ * otherwise the output is not aligned.
+ */
+ pad = NUM_SPARKS - ((ret - 1) / 3);
+ scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
+ ret = scnprintf(hpp->buf, hpp->size, "%*s",
+ dfmt->header_width, buf);
+
+ if (pad) {
+ ret += scnprintf(hpp->buf + ret, hpp->size - ret,
+ "%-*s", pad, " ");
+ }
+
+ return ret;
+ }
+
+no_print:
+ return scnprintf(hpp->buf, hpp->size, "%*s",
+ dfmt->header_width, " ");
+}
+
static void
hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
{
@@ -1536,7 +1641,7 @@
default:
BUG_ON(1);
- };
+ }
}
static void
@@ -1667,6 +1772,10 @@
fmt->color = hpp__color_cycles;
fmt->sort = hist_entry__cmp_nop;
break;
+ case PERF_HPP_DIFF__CYCLES_HIST:
+ fmt->color = hpp__color_cycles_hist;
+ fmt->sort = hist_entry__cmp_nop;
+ break;
default:
fmt->sort = hist_entry__cmp_nop;
break;
@@ -1692,10 +1801,14 @@
* PERF_HPP_DIFF__DELTA
* PERF_HPP_DIFF__RATIO
* PERF_HPP_DIFF__WEIGHTED_DIFF
+ * PERF_HPP_DIFF__CYCLES
*/
data__hpp_register(d, i ? compute_2_hpp[compute] :
PERF_HPP_DIFF__BASELINE);
+ if (cycles_hist && i)
+ data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
+
/*
* And the rest:
*
@@ -1850,6 +1963,12 @@
if (quiet)
perf_quiet_option();
+ if (cycles_hist && (compute != COMPUTE_CYCLES))
+ usage_with_options(diff_usage, options);
+
+ if (pdiff.stream)
+ compute = COMPUTE_STREAM;
+
symbol__annotation_init();
if (symbol__init(NULL) < 0)
@@ -1861,13 +1980,26 @@
if (check_file_brstack() < 0)
return -1;
- if (compute == COMPUTE_CYCLES && !pdiff.has_br_stack)
+ if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
+ && !pdiff.has_br_stack) {
return -1;
+ }
- if (ui_init() < 0)
- return -1;
+ if (compute == COMPUTE_STREAM) {
+ symbol_conf.show_branchflag_count = true;
+ symbol_conf.disable_add2line_warn = true;
+ callchain_param.mode = CHAIN_FLAT;
+ callchain_param.key = CCKEY_SRCLINE;
+ callchain_param.branch_callstack = 1;
+ symbol_conf.use_callchain = true;
+ callchain_register_param(&callchain_param);
+ sort_order = "srcline,symbol,dso";
+ } else {
+ if (ui_init() < 0)
+ return -1;
- sort__mode = SORT_MODE__DIFF;
+ sort__mode = SORT_MODE__DIFF;
+ }
if (setup_sorting(NULL) < 0)
usage_with_options(diff_usage, options);