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>
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;
8789static bool show_period ;
8890static bool show_formula ;
8991static bool show_baseline_only ;
92+ static bool cycles_hist ;
9093static unsigned int sort_compute = 1 ;
9194
9295static 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
615625static 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+
692717static 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+
14651597static void
14661598hpp__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 )
0 commit comments