Skip to content

Commit cebf7d5

Browse files
Jin Yaoacmel
Jin Yao
authored andcommitted
perf diff: Report noisy for cycles diff
This patch prints the stddev and hist for the cycles diff of program block. It can help us to understand if the cycles is noisy or not. This patch is inspired by Andi Kleen's patch: https://lwn.net/Articles/600471/ We create new option '--cycles-hist'. Example: perf record -b ./div perf record -b ./div perf diff -c cycles # Baseline [Program Block Range] Cycles Diff Shared Object Symbol # ........ .......................................................... .... ................. ............................ # 46.72% [div.c:40 -> div.c:40] 0 div [.] main 46.72% [div.c:42 -> div.c:44] 0 div [.] main 46.72% [div.c:42 -> div.c:39] 0 div [.] main 20.54% [random_r.c:357 -> random_r.c:394] 1 libc-2.27.so [.] __random_r 20.54% [random_r.c:357 -> random_r.c:380] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:388] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:391] 0 libc-2.27.so [.] __random_r 17.04% [random.c:288 -> random.c:291] 0 libc-2.27.so [.] __random 17.04% [random.c:291 -> random.c:291] 0 libc-2.27.so [.] __random 17.04% [random.c:293 -> random.c:293] 0 libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:298 -> random.c:298] 0 libc-2.27.so [.] __random 8.40% [div.c:22 -> div.c:25] 0 div [.] compute_flag 8.40% [div.c:27 -> div.c:28] 0 div [.] compute_flag 5.14% [rand.c:26 -> rand.c:27] 0 libc-2.27.so [.] rand 5.14% [rand.c:28 -> rand.c:28] 0 libc-2.27.so [.] rand 2.15% [rand@plt+0 -> rand@plt+0] 0 div [.] rand@plt 0.00% [kernel.kallsyms] [k] __x86_indirect_thunk_rax 0.00% [do_mmap+714 -> do_mmap+732] -10 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+737 -> do_mmap+765] 1 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+262 -> do_mmap+299] 0 [kernel.kallsyms] [k] do_mmap 0.00% [__x86_indirect_thunk_r15+0 -> __x86_indirect_thunk_r15+0] 7 [kernel.kallsyms] [k] __x86_indirect_thunk_r15 0.00% [native_sched_clock+0 -> native_sched_clock+119] -1 [kernel.kallsyms] [k] native_sched_clock 0.00% [native_write_msr+0 -> native_write_msr+16] -13 [kernel.kallsyms] [k] native_write_msr When we enable the option '--cycles-hist', the output is perf diff -c cycles --cycles-hist # Baseline [Program Block Range] Cycles Diff stddev/Hist Shared Object Symbol # ........ .......................................................... .... ................. ................. ............................ # 46.72% [div.c:40 -> div.c:40] 0 ± 37.8% ▁█▁▁██▁█ div [.] main 46.72% [div.c:42 -> div.c:44] 0 ± 49.4% ▁▁▂█▂▂▂▂ div [.] main 46.72% [div.c:42 -> div.c:39] 0 ± 24.1% ▃█▂▄▁▃▂▁ div [.] main 20.54% [random_r.c:357 -> random_r.c:394] 1 ± 33.5% ▅▂▁█▃▁▂▁ libc-2.27.so [.] __random_r 20.54% [random_r.c:357 -> random_r.c:380] 0 ± 39.4% ▁▁█▁██▅▁ libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:388] 0 libc-2.27.so [.] __random_r 20.54% [random_r.c:388 -> random_r.c:391] 0 ± 41.2% ▁▃▁▂█▄▃▁ libc-2.27.so [.] __random_r 17.04% [random.c:288 -> random.c:291] 0 ± 48.8% ▁▁▁▁███▁ libc-2.27.so [.] __random 17.04% [random.c:291 -> random.c:291] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:293 -> random.c:293] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 ±100.0% ▁█▁▁▁▁▁▁ libc-2.27.so [.] __random 17.04% [random.c:295 -> random.c:295] 0 libc-2.27.so [.] __random 17.04% [random.c:298 -> random.c:298] 0 ± 75.6% ▃█▁▁▁▁▁▁ libc-2.27.so [.] __random 8.40% [div.c:22 -> div.c:25] 0 ± 42.1% ▁▃▁▁███▁ div [.] compute_flag 8.40% [div.c:27 -> div.c:28] 0 ± 41.8% ██▁▁▄▁▁▄ div [.] compute_flag 5.14% [rand.c:26 -> rand.c:27] 0 ± 37.8% ▁▁▁████▁ libc-2.27.so [.] rand 5.14% [rand.c:28 -> rand.c:28] 0 libc-2.27.so [.] rand 2.15% [rand@plt+0 -> rand@plt+0] 0 div [.] rand@plt 0.00% [kernel.kallsyms] [k] __x86_indirect_thunk_rax 0.00% [do_mmap+714 -> do_mmap+732] -10 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+737 -> do_mmap+765] 1 [kernel.kallsyms] [k] do_mmap 0.00% [do_mmap+262 -> do_mmap+299] 0 [kernel.kallsyms] [k] do_mmap 0.00% [__x86_indirect_thunk_r15+0 -> __x86_indirect_thunk_r15+0] 7 [kernel.kallsyms] [k] __x86_indirect_thunk_r15 0.00% [native_sched_clock+0 -> native_sched_clock+119] -1 ± 38.5% ▄█▁ [kernel.kallsyms] [k] native_sched_clock 0.00% [native_write_msr+0 -> native_write_msr+16] -13 ± 47.1% ▁█▇▃▁▁ [kernel.kallsyms] [k] native_write_msr v8: --- Rebase to perf/core branch v7: --- 1. v6 got Jiri's ACK. 2. Rebase to latest perf/core branch. v6: --- 1. Jiri provides better code for using data__hpp_register() in ui_init(). Use this code in v6. v5: --- 1. Refine the use of data__hpp_register() in ui_init() according to Jiri's suggestion. v4: --- 1. Rename the new option from '--noisy' to '--cycles-hist' 2. Remove the option '-n'. 3. Only update the spark value and stats when '--cycles-hist' is enabled. 4. Remove the code of printing '..'. v3: --- 1. Move the histogram to a separate column 2. Move the svals[] out of struct stats v2: --- Jiri got a compile error, CC builtin-diff.o builtin-diff.c: In function ‘compute_cycles_diff’: builtin-diff.c:712:10: error: taking the absolute value of unsigned type ‘u64’ {aka ‘long unsigned int’} has no effect [-Werror=absolute-value] 712 | labs(pair->block_info->cycles_spark[i] - | ^~~~ Because the result of u64 - u64 is still u64. Now we change the type of cycles_spark[] to s64. Signed-off-by: Jin Yao <[email protected]> Acked-by: Jiri Olsa <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: Kan Liang <[email protected]> Cc: Peter Zijlstra <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent 5554211 commit cebf7d5

File tree

9 files changed

+203
-0
lines changed

9 files changed

+203
-0
lines changed

tools/perf/Documentation/perf-diff.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,11 @@ OPTIONS
9595
diff.compute config option. See COMPARISON METHODS section for
9696
more info.
9797

98+
--cycles-hist::
99+
Report a histogram and the standard deviation for cycles data.
100+
It can help us to judge if the reported cycles data is noisy or
101+
not. This option should be used with '-c cycles'.
102+
98103
-p::
99104
--period::
100105
Show period values for both compared hist entries.

tools/perf/builtin-diff.c

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "util/time-utils.h"
2424
#include "util/annotate.h"
2525
#include "util/map.h"
26+
#include "util/spark.h"
2627
#include <linux/err.h>
2728
#include <linux/zalloc.h>
2829
#include <subcmd/pager.h>
@@ -53,6 +54,7 @@ enum {
5354
PERF_HPP_DIFF__FORMULA,
5455
PERF_HPP_DIFF__DELTA_ABS,
5556
PERF_HPP_DIFF__CYCLES,
57+
PERF_HPP_DIFF__CYCLES_HIST,
5658

5759
PERF_HPP_DIFF__MAX_INDEX
5860
};
@@ -87,6 +89,7 @@ static bool force;
8789
static bool show_period;
8890
static bool show_formula;
8991
static bool show_baseline_only;
92+
static bool cycles_hist;
9093
static unsigned int sort_compute = 1;
9194

9295
static s64 compute_wdiff_w1;
@@ -164,6 +167,10 @@ static struct header_column {
164167
[PERF_HPP_DIFF__CYCLES] = {
165168
.name = "[Program Block Range] Cycles Diff",
166169
.width = 70,
170+
},
171+
[PERF_HPP_DIFF__CYCLES_HIST] = {
172+
.name = "stddev/Hist",
173+
.width = NUM_SPARKS + 9,
167174
}
168175
};
169176

@@ -610,6 +617,9 @@ static void init_block_info(struct block_info *bi, struct symbol *sym,
610617
bi->cycles_aggr = ch->cycles_aggr;
611618
bi->num = ch->num;
612619
bi->num_aggr = ch->num_aggr;
620+
621+
memcpy(bi->cycles_spark, ch->cycles_spark,
622+
NUM_SPARKS * sizeof(u64));
613623
}
614624

615625
static int process_block_per_sym(struct hist_entry *he)
@@ -689,6 +699,21 @@ static struct hist_entry *get_block_pair(struct hist_entry *he,
689699
return NULL;
690700
}
691701

702+
static void init_spark_values(unsigned long *svals, int num)
703+
{
704+
for (int i = 0; i < num; i++)
705+
svals[i] = 0;
706+
}
707+
708+
static void update_spark_value(unsigned long *svals, int num,
709+
struct stats *stats, u64 val)
710+
{
711+
int n = stats->n;
712+
713+
if (n < num)
714+
svals[n] = val;
715+
}
716+
692717
static void compute_cycles_diff(struct hist_entry *he,
693718
struct hist_entry *pair)
694719
{
@@ -697,6 +722,26 @@ static void compute_cycles_diff(struct hist_entry *he,
697722
pair->diff.cycles =
698723
pair->block_info->cycles_aggr / pair->block_info->num_aggr -
699724
he->block_info->cycles_aggr / he->block_info->num_aggr;
725+
726+
if (!cycles_hist)
727+
return;
728+
729+
init_stats(&pair->diff.stats);
730+
init_spark_values(pair->diff.svals, NUM_SPARKS);
731+
732+
for (int i = 0; i < pair->block_info->num; i++) {
733+
u64 val;
734+
735+
if (i >= he->block_info->num || i >= NUM_SPARKS)
736+
break;
737+
738+
val = labs(pair->block_info->cycles_spark[i] -
739+
he->block_info->cycles_spark[i]);
740+
741+
update_spark_value(pair->diff.svals, NUM_SPARKS,
742+
&pair->diff.stats, val);
743+
update_stats(&pair->diff.stats, val);
744+
}
700745
}
701746
}
702747

@@ -1255,6 +1300,9 @@ static const struct option options[] = {
12551300
"Show period values."),
12561301
OPT_BOOLEAN('F', "formula", &show_formula,
12571302
"Show formula."),
1303+
OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
1304+
"Show cycles histogram and standard deviation "
1305+
"- WARNING: use only with -c cycles."),
12581306
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
12591307
"dump raw trace in ASCII"),
12601308
OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
@@ -1462,6 +1510,90 @@ static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
14621510
return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
14631511
}
14641512

1513+
static int all_zero(unsigned long *vals, int len)
1514+
{
1515+
int i;
1516+
1517+
for (i = 0; i < len; i++)
1518+
if (vals[i] != 0)
1519+
return 0;
1520+
return 1;
1521+
}
1522+
1523+
static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
1524+
{
1525+
int printed;
1526+
1527+
if (n <= 1)
1528+
return 0;
1529+
1530+
if (n > NUM_SPARKS)
1531+
n = NUM_SPARKS;
1532+
if (all_zero(svals, n))
1533+
return 0;
1534+
1535+
printed = print_spark(bf, size, svals, n);
1536+
printed += scnprintf(bf + printed, size - printed, " ");
1537+
return printed;
1538+
}
1539+
1540+
static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
1541+
struct perf_hpp *hpp, struct hist_entry *he)
1542+
{
1543+
struct diff_hpp_fmt *dfmt =
1544+
container_of(fmt, struct diff_hpp_fmt, fmt);
1545+
struct hist_entry *pair = get_pair_fmt(he, dfmt);
1546+
struct block_hist *bh = container_of(he, struct block_hist, he);
1547+
struct block_hist *bh_pair;
1548+
struct hist_entry *block_he;
1549+
char spark[32], buf[128];
1550+
double r;
1551+
int ret, pad;
1552+
1553+
if (!pair) {
1554+
if (bh->block_idx)
1555+
hpp->skip = true;
1556+
1557+
goto no_print;
1558+
}
1559+
1560+
bh_pair = container_of(pair, struct block_hist, he);
1561+
1562+
block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
1563+
if (!block_he) {
1564+
hpp->skip = true;
1565+
goto no_print;
1566+
}
1567+
1568+
ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
1569+
block_he->diff.stats.n);
1570+
1571+
r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
1572+
avg_stats(&block_he->diff.stats));
1573+
1574+
if (ret) {
1575+
/*
1576+
* Padding spaces if number of sparks less than NUM_SPARKS
1577+
* otherwise the output is not aligned.
1578+
*/
1579+
pad = NUM_SPARKS - ((ret - 1) / 3);
1580+
scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
1581+
ret = scnprintf(hpp->buf, hpp->size, "%*s",
1582+
dfmt->header_width, buf);
1583+
1584+
if (pad) {
1585+
ret += scnprintf(hpp->buf + ret, hpp->size - ret,
1586+
"%-*s", pad, " ");
1587+
}
1588+
1589+
return ret;
1590+
}
1591+
1592+
no_print:
1593+
return scnprintf(hpp->buf, hpp->size, "%*s",
1594+
dfmt->header_width, " ");
1595+
}
1596+
14651597
static void
14661598
hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
14671599
{
@@ -1667,6 +1799,10 @@ static void data__hpp_register(struct data__file *d, int idx)
16671799
fmt->color = hpp__color_cycles;
16681800
fmt->sort = hist_entry__cmp_nop;
16691801
break;
1802+
case PERF_HPP_DIFF__CYCLES_HIST:
1803+
fmt->color = hpp__color_cycles_hist;
1804+
fmt->sort = hist_entry__cmp_nop;
1805+
break;
16701806
default:
16711807
fmt->sort = hist_entry__cmp_nop;
16721808
break;
@@ -1692,10 +1828,14 @@ static int ui_init(void)
16921828
* PERF_HPP_DIFF__DELTA
16931829
* PERF_HPP_DIFF__RATIO
16941830
* PERF_HPP_DIFF__WEIGHTED_DIFF
1831+
* PERF_HPP_DIFF__CYCLES
16951832
*/
16961833
data__hpp_register(d, i ? compute_2_hpp[compute] :
16971834
PERF_HPP_DIFF__BASELINE);
16981835

1836+
if (cycles_hist && i)
1837+
data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
1838+
16991839
/*
17001840
* And the rest:
17011841
*
@@ -1850,6 +1990,9 @@ int cmd_diff(int argc, const char **argv)
18501990
if (quiet)
18511991
perf_quiet_option();
18521992

1993+
if (cycles_hist && (compute != COMPUTE_CYCLES))
1994+
usage_with_options(diff_usage, options);
1995+
18531996
symbol__annotation_init();
18541997

18551998
if (symbol__init(NULL) < 0)

tools/perf/util/Build

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ perf-y += cloexec.o
9595
perf-y += call-path.o
9696
perf-y += rwsem.o
9797
perf-y += thread-stack.o
98+
perf-y += spark.o
9899
perf-$(CONFIG_AUXTRACE) += auxtrace.o
99100
perf-$(CONFIG_AUXTRACE) += intel-pt-decoder/
100101
perf-$(CONFIG_AUXTRACE) += intel-pt.o

tools/perf/util/annotate.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -853,6 +853,10 @@ static int __symbol__account_cycles(struct cyc_hist *ch,
853853
ch[offset].start < start)
854854
return 0;
855855
}
856+
857+
if (ch[offset].num < NUM_SPARKS)
858+
ch[offset].cycles_spark[ch[offset].num] = cycles;
859+
856860
ch[offset].have_start = have_start;
857861
ch[offset].start = start;
858862
ch[offset].cycles += cycles;

tools/perf/util/annotate.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <pthread.h>
1212
#include <asm/bug.h>
1313
#include "symbol_conf.h"
14+
#include "spark.h"
1415

1516
struct hist_browser_timer;
1617
struct hist_entry;
@@ -235,6 +236,7 @@ struct cyc_hist {
235236
u64 cycles_aggr;
236237
u64 cycles_max;
237238
u64 cycles_min;
239+
s64 cycles_spark[NUM_SPARKS];
238240
u32 num;
239241
u32 num_aggr;
240242
u8 have_start;

tools/perf/util/sort.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include "callchain.h"
1111
#include "values.h"
1212
#include "hist.h"
13+
#include "stat.h"
14+
#include "spark.h"
1315

1416
struct option;
1517
struct thread;
@@ -71,6 +73,8 @@ struct hist_entry_diff {
7173
/* PERF_HPP_DIFF__CYCLES */
7274
s64 cycles;
7375
};
76+
struct stats stats;
77+
unsigned long svals[NUM_SPARKS];
7478
};
7579

7680
struct hist_entry_ops {

tools/perf/util/spark.c

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
#include <stdio.h>
2+
#include <limits.h>
3+
#include <string.h>
4+
#include <stdlib.h>
5+
#include "spark.h"
6+
#include "stat.h"
7+
8+
#define SPARK_SHIFT 8
9+
10+
/* Print spark lines on outf for numval values in val. */
11+
int print_spark(char *bf, int size, unsigned long *val, int numval)
12+
{
13+
static const char *ticks[NUM_SPARKS] = {
14+
"▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"
15+
};
16+
int i, printed = 0;
17+
unsigned long min = ULONG_MAX, max = 0, f;
18+
19+
for (i = 0; i < numval; i++) {
20+
if (val[i] < min)
21+
min = val[i];
22+
if (val[i] > max)
23+
max = val[i];
24+
}
25+
f = ((max - min) << SPARK_SHIFT) / (NUM_SPARKS - 1);
26+
if (f < 1)
27+
f = 1;
28+
for (i = 0; i < numval; i++) {
29+
printed += scnprintf(bf + printed, size - printed, "%s",
30+
ticks[((val[i] - min) << SPARK_SHIFT) / f]);
31+
}
32+
33+
return printed;
34+
}

tools/perf/util/spark.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#ifndef SPARK_H
2+
#define SPARK_H 1
3+
4+
#define NUM_SPARKS 8
5+
6+
int print_spark(char *bf, int size, unsigned long *val, int numval);
7+
8+
#endif

tools/perf/util/symbol.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <stdio.h>
1212
#include "path.h"
1313
#include "symbol_conf.h"
14+
#include "spark.h"
1415

1516
#ifdef HAVE_LIBELF_SUPPORT
1617
#include <libelf.h>
@@ -111,6 +112,7 @@ struct block_info {
111112
u64 end;
112113
u64 cycles;
113114
u64 cycles_aggr;
115+
s64 cycles_spark[NUM_SPARKS];
114116
int num;
115117
int num_aggr;
116118
refcount_t refcnt;

0 commit comments

Comments
 (0)