^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * builtin-diff.c
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Builtin diff command: Analyze two perf.data input files, look up and read
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * DSOs and symbol information, sort them and produce a diff.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #include "builtin.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include "perf.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include "util/debug.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include "util/event.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "util/hist.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include "util/evsel.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include "util/evlist.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include "util/session.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include "util/tool.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include "util/sort.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include "util/srcline.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) #include "util/symbol.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include "util/data.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include "util/config.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include "util/time-utils.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) #include "util/annotate.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) #include "util/map.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) #include "util/spark.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) #include "util/block-info.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) #include "util/stream.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) #include <linux/err.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) #include <linux/zalloc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) #include <subcmd/pager.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) #include <subcmd/parse-options.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) #include <inttypes.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) #include <math.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) struct perf_diff {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) struct perf_tool tool;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) const char *time_str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) struct perf_time_interval *ptime_range;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) int range_size;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) int range_num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) bool has_br_stack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) bool stream;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) /* Diff command specific HPP columns. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) PERF_HPP_DIFF__BASELINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) PERF_HPP_DIFF__PERIOD,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) PERF_HPP_DIFF__PERIOD_BASELINE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) PERF_HPP_DIFF__DELTA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) PERF_HPP_DIFF__RATIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) PERF_HPP_DIFF__WEIGHTED_DIFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) PERF_HPP_DIFF__FORMULA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) PERF_HPP_DIFF__DELTA_ABS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) PERF_HPP_DIFF__CYCLES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) PERF_HPP_DIFF__CYCLES_HIST,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) PERF_HPP_DIFF__MAX_INDEX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) struct diff_hpp_fmt {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) struct perf_hpp_fmt fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) char *header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) int header_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) struct data__file {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) struct perf_session *session;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) struct perf_data data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) int idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) struct hists *hists;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) struct evlist_streams *evlist_streams;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) static struct data__file *data__files;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) static int data__files_cnt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) #define data__for_each_file_start(i, d, s) \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) for (i = s, d = &data__files[s]; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) i < data__files_cnt; \
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) i++, d = &data__files[i])
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) #define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) #define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) static bool force;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) static bool show_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) static bool show_formula;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static bool show_baseline_only;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) static bool cycles_hist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) static unsigned int sort_compute = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) static s64 compute_wdiff_w1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) static s64 compute_wdiff_w2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) static const char *cpu_list;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) static DECLARE_BITMAP(cpu_bitmap, MAX_NR_CPUS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) enum {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) COMPUTE_DELTA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) COMPUTE_RATIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) COMPUTE_WEIGHTED_DIFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) COMPUTE_DELTA_ABS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) COMPUTE_CYCLES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) COMPUTE_MAX,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) COMPUTE_STREAM, /* After COMPUTE_MAX to avoid use current compute arrays */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) const char *compute_names[COMPUTE_MAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) [COMPUTE_DELTA] = "delta",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) [COMPUTE_DELTA_ABS] = "delta-abs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) [COMPUTE_RATIO] = "ratio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) [COMPUTE_WEIGHTED_DIFF] = "wdiff",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) [COMPUTE_CYCLES] = "cycles",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) static int compute = COMPUTE_DELTA_ABS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) static int compute_2_hpp[COMPUTE_MAX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) [COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) [COMPUTE_DELTA_ABS] = PERF_HPP_DIFF__DELTA_ABS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) [COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) [COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) [COMPUTE_CYCLES] = PERF_HPP_DIFF__CYCLES,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) #define MAX_COL_WIDTH 70
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) static struct header_column {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) const char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) int width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) } columns[PERF_HPP_DIFF__MAX_INDEX] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) [PERF_HPP_DIFF__BASELINE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) .name = "Baseline",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) [PERF_HPP_DIFF__PERIOD] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) .name = "Period",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) .width = 14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) [PERF_HPP_DIFF__PERIOD_BASELINE] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) .name = "Base period",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) .width = 14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) [PERF_HPP_DIFF__DELTA] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) .name = "Delta",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) .width = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) [PERF_HPP_DIFF__DELTA_ABS] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) .name = "Delta Abs",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) .width = 7,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) [PERF_HPP_DIFF__RATIO] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) .name = "Ratio",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) .width = 14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) [PERF_HPP_DIFF__WEIGHTED_DIFF] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) .name = "Weighted diff",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) .width = 14,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) [PERF_HPP_DIFF__FORMULA] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) .name = "Formula",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) .width = MAX_COL_WIDTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) [PERF_HPP_DIFF__CYCLES] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) .name = "[Program Block Range] Cycles Diff",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) .width = 70,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) [PERF_HPP_DIFF__CYCLES_HIST] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) .name = "stddev/Hist",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) .width = NUM_SPARKS + 9,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) static int setup_compute_opt_wdiff(char *opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) char *w1_str = opt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) char *w2_str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) int ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) if (!opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) w2_str = strchr(opt, ',');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) if (!w2_str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) *w2_str++ = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) if (!*w2_str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) compute_wdiff_w1 = strtol(w1_str, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) compute_wdiff_w2 = strtol(w2_str, NULL, 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) if (!compute_wdiff_w1 || !compute_wdiff_w2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) goto out;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) compute_wdiff_w1, compute_wdiff_w2);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) out:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) static int setup_compute_opt(char *opt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) if (compute == COMPUTE_WEIGHTED_DIFF)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) return setup_compute_opt_wdiff(opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) if (opt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) pr_err("Failed: extra option specified '%s'", opt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) static int setup_compute(const struct option *opt, const char *str,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) int unset __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) int *cp = (int *) opt->value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) char *cstr = (char *) str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) char buf[50];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) unsigned i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) char *option;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) if (!str) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) *cp = COMPUTE_DELTA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) option = strchr(str, ':');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) if (option) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) unsigned len = option++ - str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) * The str data are not writeable, so we need
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) * to use another buffer.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) /* No option value is longer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) if (len >= sizeof(buf))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) strncpy(buf, str, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) buf[len] = 0x0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) cstr = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) for (i = 0; i < COMPUTE_MAX; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) if (!strcmp(cstr, compute_names[i])) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) *cp = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) return setup_compute_opt(option);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) pr_err("Failed: '%s' is not computation method "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) "(use 'delta','ratio' or 'wdiff')\n", str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) static double period_percent(struct hist_entry *he, u64 period)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) u64 total = hists__total_period(he->hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) return (period * 100.0) / total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) static double compute_delta(struct hist_entry *he, struct hist_entry *pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) double old_percent = period_percent(he, he->stat.period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) double new_percent = period_percent(pair, pair->stat.period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) pair->diff.period_ratio_delta = new_percent - old_percent;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) pair->diff.computed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) return pair->diff.period_ratio_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) static double compute_ratio(struct hist_entry *he, struct hist_entry *pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) double old_period = he->stat.period ?: 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) double new_period = pair->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) pair->diff.computed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) pair->diff.period_ratio = new_period / old_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) return pair->diff.period_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static s64 compute_wdiff(struct hist_entry *he, struct hist_entry *pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) u64 old_period = he->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) u64 new_period = pair->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) pair->diff.computed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) pair->diff.wdiff = new_period * compute_wdiff_w2 -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) old_period * compute_wdiff_w1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) return pair->diff.wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) static int formula_delta(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) u64 he_total = he->hists->stats.total_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) u64 pair_total = pair->hists->stats.total_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) if (symbol_conf.filter_relative) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) he_total = he->hists->stats.total_non_filtered_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) pair_total = pair->hists->stats.total_non_filtered_period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) return scnprintf(buf, size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) "(%" PRIu64 " * 100 / %" PRIu64 ") - "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) "(%" PRIu64 " * 100 / %" PRIu64 ")",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) pair->stat.period, pair_total,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) he->stat.period, he_total);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) static int formula_ratio(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) double old_period = he->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) double new_period = pair->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) return scnprintf(buf, size, "%.0F / %.0F", new_period, old_period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) static int formula_wdiff(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) u64 old_period = he->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) u64 new_period = pair->stat.period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) return scnprintf(buf, size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) "(%" PRIu64 " * " "%" PRId64 ") - (%" PRIu64 " * " "%" PRId64 ")",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) new_period, compute_wdiff_w2, old_period, compute_wdiff_w1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) static int formula_fprintf(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) switch (compute) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) case COMPUTE_DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) case COMPUTE_DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) return formula_delta(he, pair, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) case COMPUTE_RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) return formula_ratio(he, pair, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) case COMPUTE_WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) return formula_wdiff(he, pair, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) static void *block_hist_zalloc(size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) struct block_hist *bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) bh = zalloc(size + sizeof(*bh));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) if (!bh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) return &bh->he;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) static void block_hist_free(void *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) struct block_hist *bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 380)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 381) bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 382) hists__delete_entries(&bh->block_hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 383) free(bh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 384) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 385)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 386) struct hist_entry_ops block_hist_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 387) .new = block_hist_zalloc,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 388) .free = block_hist_free,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 389) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 390)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 391) static int diff__process_sample_event(struct perf_tool *tool,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 392) union perf_event *event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 393) struct perf_sample *sample,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 394) struct evsel *evsel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 395) struct machine *machine)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 397) struct perf_diff *pdiff = container_of(tool, struct perf_diff, tool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 398) struct addr_location al;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 399) struct hists *hists = evsel__hists(evsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 400) struct hist_entry_iter iter = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 401) .evsel = evsel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 402) .sample = sample,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 403) .ops = &hist_iter_normal,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 404) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 405) int ret = -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 406)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 407) if (perf_time__ranges_skip_sample(pdiff->ptime_range, pdiff->range_num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 408) sample->time)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 409) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 410) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 411)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 412) if (machine__resolve(machine, &al, sample) < 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 413) pr_warning("problem processing %d event, skipping it.\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 414) event->header.type);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 415) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 416) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 417)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 418) if (cpu_list && !test_bit(sample->cpu, cpu_bitmap)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 419) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 420) goto out_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 421) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 423) switch (compute) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 424) case COMPUTE_CYCLES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 425) if (!hists__add_entry_ops(hists, &block_hist_ops, &al, NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 426) NULL, NULL, sample, true)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 427) pr_warning("problem incrementing symbol period, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 428) "skipping event\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 429) goto out_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 430) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 431)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 432) hist__account_cycles(sample->branch_stack, &al, sample, false,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 433) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 434) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 435)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 436) case COMPUTE_STREAM:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 437) if (hist_entry_iter__add(&iter, &al, PERF_MAX_STACK_DEPTH,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 438) NULL)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 439) pr_debug("problem adding hist entry, skipping event\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 440) goto out_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 441) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 442) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 443)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 444) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 445) if (!hists__add_entry(hists, &al, NULL, NULL, NULL, sample,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 446) true)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 447) pr_warning("problem incrementing symbol period, "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 448) "skipping event\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 449) goto out_put;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 450) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 451) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 452)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 453) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 454) * The total_period is updated here before going to the output
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 455) * tree since normally only the baseline hists will call
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 456) * hists__output_resort() and precompute needs the total
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 457) * period in order to sort entries by percentage delta.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 458) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 459) hists->stats.total_period += sample->period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 460) if (!al.filtered)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 461) hists->stats.total_non_filtered_period += sample->period;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 462) ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 463) out_put:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 464) addr_location__put(&al);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 465) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 468) static struct perf_diff pdiff = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 469) .tool = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 470) .sample = diff__process_sample_event,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 471) .mmap = perf_event__process_mmap,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 472) .mmap2 = perf_event__process_mmap2,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 473) .comm = perf_event__process_comm,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 474) .exit = perf_event__process_exit,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 475) .fork = perf_event__process_fork,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 476) .lost = perf_event__process_lost,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 477) .namespaces = perf_event__process_namespaces,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 478) .cgroup = perf_event__process_cgroup,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 479) .ordered_events = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 480) .ordering_requires_timestamps = true,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 481) },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 482) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 483)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 484) static struct evsel *evsel_match(struct evsel *evsel,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 485) struct evlist *evlist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 486) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 487) struct evsel *e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 488)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 489) evlist__for_each_entry(evlist, e) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 490) if (evsel__match2(evsel, e))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 491) return e;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 492) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 493)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 494) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 495) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 496)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 497) static void perf_evlist__collapse_resort(struct evlist *evlist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 498) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 499) struct evsel *evsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 500)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 501) evlist__for_each_entry(evlist, evsel) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 502) struct hists *hists = evsel__hists(evsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 503)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 504) hists__collapse_resort(hists, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 505) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 506) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 508) static struct data__file *fmt_to_data_file(struct perf_hpp_fmt *fmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 509) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 510) struct diff_hpp_fmt *dfmt = container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 511) void *ptr = dfmt - dfmt->idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 512) struct data__file *d = container_of(ptr, struct data__file, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 513)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 514) return d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 515) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 516)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 517) static struct hist_entry*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 518) get_pair_data(struct hist_entry *he, struct data__file *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 519) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 520) if (hist_entry__has_pairs(he)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 521) struct hist_entry *pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 522)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 523) list_for_each_entry(pair, &he->pairs.head, pairs.node)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 524) if (pair->hists == d->hists)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 525) return pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 526) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 527)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 528) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 529) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 530)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 531) static struct hist_entry*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 532) get_pair_fmt(struct hist_entry *he, struct diff_hpp_fmt *dfmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 533) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 534) struct data__file *d = fmt_to_data_file(&dfmt->fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 535)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 536) return get_pair_data(he, d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 537) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 538)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 539) static void hists__baseline_only(struct hists *hists)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 540) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 541) struct rb_root_cached *root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 542) struct rb_node *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 544) if (hists__has(hists, need_collapse))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 545) root = &hists->entries_collapsed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 546) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 547) root = hists->entries_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 548)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 549) next = rb_first_cached(root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 550) while (next != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 551) struct hist_entry *he = rb_entry(next, struct hist_entry, rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 552)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 553) next = rb_next(&he->rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 554) if (!hist_entry__next_pair(he)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 555) rb_erase_cached(&he->rb_node_in, root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 556) hist_entry__delete(he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 557) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 558) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 559) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 560)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 561) static int64_t block_cycles_diff_cmp(struct hist_entry *left,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 562) struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 563) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 564) bool pairs_left = hist_entry__has_pairs(left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 565) bool pairs_right = hist_entry__has_pairs(right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 566) s64 l, r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 567)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 568) if (!pairs_left && !pairs_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 569) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 570)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 571) l = llabs(left->diff.cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 572) r = llabs(right->diff.cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 573) return r - l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 574) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 575)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 576) static int64_t block_sort(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 577) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 578) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 579) return block_cycles_diff_cmp(right, left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 581)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 582) static void init_block_hist(struct block_hist *bh)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 583) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 584) __hists__init(&bh->block_hists, &bh->block_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 585) perf_hpp_list__init(&bh->block_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 586)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 587) INIT_LIST_HEAD(&bh->block_fmt.list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 588) INIT_LIST_HEAD(&bh->block_fmt.sort_list);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 589) bh->block_fmt.cmp = block_info__cmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 590) bh->block_fmt.sort = block_sort;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 591) perf_hpp_list__register_sort_field(&bh->block_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 592) &bh->block_fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 593) bh->valid = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 594) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 595)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 596) static struct hist_entry *get_block_pair(struct hist_entry *he,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 597) struct hists *hists_pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 598) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 599) struct rb_root_cached *root = hists_pair->entries_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 600) struct rb_node *next = rb_first_cached(root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 601) int64_t cmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 602)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 603) while (next != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 604) struct hist_entry *he_pair = rb_entry(next, struct hist_entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 605) rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 606)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 607) next = rb_next(&he_pair->rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 609) cmp = __block_info__cmp(he_pair, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 610) if (!cmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 611) return he_pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 612) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 614) return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 615) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 616)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 617) static void init_spark_values(unsigned long *svals, int num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 618) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 619) for (int i = 0; i < num; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 620) svals[i] = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 621) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 622)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 623) static void update_spark_value(unsigned long *svals, int num,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 624) struct stats *stats, u64 val)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 625) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 626) int n = stats->n;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 627)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 628) if (n < num)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 629) svals[n] = val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 630) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 631)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 632) static void compute_cycles_diff(struct hist_entry *he,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 633) struct hist_entry *pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 634) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 635) pair->diff.computed = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 636) if (pair->block_info->num && he->block_info->num) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 637) pair->diff.cycles =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 638) pair->block_info->cycles_aggr / pair->block_info->num_aggr -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 639) he->block_info->cycles_aggr / he->block_info->num_aggr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 640)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 641) if (!cycles_hist)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 642) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 643)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 644) init_stats(&pair->diff.stats);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 645) init_spark_values(pair->diff.svals, NUM_SPARKS);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 647) for (int i = 0; i < pair->block_info->num; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 648) u64 val;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 649)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 650) if (i >= he->block_info->num || i >= NUM_SPARKS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 651) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 652)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 653) val = llabs(pair->block_info->cycles_spark[i] -
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 654) he->block_info->cycles_spark[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 655)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 656) update_spark_value(pair->diff.svals, NUM_SPARKS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 657) &pair->diff.stats, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 658) update_stats(&pair->diff.stats, val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 659) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 660) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 661) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 662)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 663) static void block_hists_match(struct hists *hists_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 664) struct hists *hists_pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 665) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 666) struct rb_root_cached *root = hists_base->entries_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 667) struct rb_node *next = rb_first_cached(root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 668)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 669) while (next != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 670) struct hist_entry *he = rb_entry(next, struct hist_entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 671) rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 672) struct hist_entry *pair = get_block_pair(he, hists_pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 674) next = rb_next(&he->rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 675)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 676) if (pair) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 677) hist_entry__add_pair(pair, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 678) compute_cycles_diff(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 680) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 681) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 682)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 683) static void hists__precompute(struct hists *hists)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 684) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 685) struct rb_root_cached *root;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 686) struct rb_node *next;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 687)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 688) if (hists__has(hists, need_collapse))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 689) root = &hists->entries_collapsed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 690) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 691) root = hists->entries_in;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 693) next = rb_first_cached(root);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 694) while (next != NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 695) struct block_hist *bh, *pair_bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 696) struct hist_entry *he, *pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 697) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 698) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 700) he = rb_entry(next, struct hist_entry, rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 701) next = rb_next(&he->rb_node_in);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 702)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 703) if (compute == COMPUTE_CYCLES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 704) bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 705) init_block_hist(bh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 706) block_info__process_sym(he, bh, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 707) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 708)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 709) data__for_each_file_new(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 710) pair = get_pair_data(he, d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 711) if (!pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 712) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 713)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 714) switch (compute) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 715) case COMPUTE_DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 716) case COMPUTE_DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 717) compute_delta(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 718) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 719) case COMPUTE_RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 720) compute_ratio(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 721) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 722) case COMPUTE_WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 723) compute_wdiff(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 724) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 725) case COMPUTE_CYCLES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 726) pair_bh = container_of(pair, struct block_hist,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 727) he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 728) init_block_hist(pair_bh);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 729) block_info__process_sym(pair, pair_bh, NULL, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 731) bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 732)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 733) if (bh->valid && pair_bh->valid) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 734) block_hists_match(&bh->block_hists,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 735) &pair_bh->block_hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 736) hists__output_resort(&pair_bh->block_hists,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 737) NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 738) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 739) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 740) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 741) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 742) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 743) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 744) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 745) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 746)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 747) static int64_t cmp_doubles(double l, double r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 748) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 749) if (l > r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 750) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 751) else if (l < r)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 752) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 753) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 754) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 755) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 756)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 757) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 758) __hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 759) int c)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 760) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 761) switch (c) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 762) case COMPUTE_DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 763) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 764) double l = left->diff.period_ratio_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 765) double r = right->diff.period_ratio_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 766)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 767) return cmp_doubles(l, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 768) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 769) case COMPUTE_DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 770) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 771) double l = fabs(left->diff.period_ratio_delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 772) double r = fabs(right->diff.period_ratio_delta);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 773)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 774) return cmp_doubles(l, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 775) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 776) case COMPUTE_RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 777) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 778) double l = left->diff.period_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 779) double r = right->diff.period_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 780)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 781) return cmp_doubles(l, r);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 783) case COMPUTE_WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 784) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 785) s64 l = left->diff.wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 786) s64 r = right->diff.wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 787)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 788) return r - l;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 789) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 790) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 791) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 792) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 793)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 794) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 795) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 797) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 798) hist_entry__cmp_compute(struct hist_entry *left, struct hist_entry *right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 799) int c, int sort_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 800) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 801) bool pairs_left = hist_entry__has_pairs(left);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 802) bool pairs_right = hist_entry__has_pairs(right);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 803) struct hist_entry *p_right, *p_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 804)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 805) if (!pairs_left && !pairs_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 806) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 807)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 808) if (!pairs_left || !pairs_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 809) return pairs_left ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 810)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 811) p_left = get_pair_data(left, &data__files[sort_idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 812) p_right = get_pair_data(right, &data__files[sort_idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 813)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 814) if (!p_left && !p_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 815) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 816)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 817) if (!p_left || !p_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 818) return p_left ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 819)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 820) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 821) * We have 2 entries of same kind, let's
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 822) * make the data comparison.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 823) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 824) return __hist_entry__cmp_compute(p_left, p_right, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 827) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 828) hist_entry__cmp_compute_idx(struct hist_entry *left, struct hist_entry *right,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 829) int c, int sort_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 830) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 831) struct hist_entry *p_right, *p_left;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 832)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 833) p_left = get_pair_data(left, &data__files[sort_idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 834) p_right = get_pair_data(right, &data__files[sort_idx]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 835)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 836) if (!p_left && !p_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 837) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 838)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 839) if (!p_left || !p_right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 840) return p_left ? -1 : 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 841)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 842) if (c != COMPUTE_DELTA && c != COMPUTE_DELTA_ABS) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 843) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 844) * The delta can be computed without the baseline, but
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 845) * others are not. Put those entries which have no
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 846) * values below.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 847) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 848) if (left->dummy && right->dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 849) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 850)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 851) if (left->dummy || right->dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 852) return left->dummy ? 1 : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 853) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 854)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 855) return __hist_entry__cmp_compute(p_left, p_right, c);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 856) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 857)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 858) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 859) hist_entry__cmp_nop(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 860) struct hist_entry *left __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 861) struct hist_entry *right __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 862) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 863) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 864) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 865)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 866) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 867) hist_entry__cmp_baseline(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 868) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 869) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 870) if (left->stat.period == right->stat.period)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 871) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 872) return left->stat.period > right->stat.period ? 1 : -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 873) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 874)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 875) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 876) hist_entry__cmp_delta(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 877) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 878) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 879) struct data__file *d = fmt_to_data_file(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 880)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 881) return hist_entry__cmp_compute(right, left, COMPUTE_DELTA, d->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 882) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 883)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 884) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 885) hist_entry__cmp_delta_abs(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 886) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 887) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 888) struct data__file *d = fmt_to_data_file(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 890) return hist_entry__cmp_compute(right, left, COMPUTE_DELTA_ABS, d->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 891) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 892)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 893) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 894) hist_entry__cmp_ratio(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 895) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 896) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 897) struct data__file *d = fmt_to_data_file(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 898)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 899) return hist_entry__cmp_compute(right, left, COMPUTE_RATIO, d->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 902) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 903) hist_entry__cmp_wdiff(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 904) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 905) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 906) struct data__file *d = fmt_to_data_file(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 907)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 908) return hist_entry__cmp_compute(right, left, COMPUTE_WEIGHTED_DIFF, d->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 909) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 911) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 912) hist_entry__cmp_delta_idx(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 913) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 914) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 915) return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 916) sort_compute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 917) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 918)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 919) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 920) hist_entry__cmp_delta_abs_idx(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 921) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 922) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 923) return hist_entry__cmp_compute_idx(right, left, COMPUTE_DELTA_ABS,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 924) sort_compute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 925) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 926)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 927) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 928) hist_entry__cmp_ratio_idx(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 929) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 930) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 931) return hist_entry__cmp_compute_idx(right, left, COMPUTE_RATIO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 932) sort_compute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 933) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 934)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 935) static int64_t
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 936) hist_entry__cmp_wdiff_idx(struct perf_hpp_fmt *fmt __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 937) struct hist_entry *left, struct hist_entry *right)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 938) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 939) return hist_entry__cmp_compute_idx(right, left, COMPUTE_WEIGHTED_DIFF,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 940) sort_compute);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 941) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 942)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 943) static void hists__process(struct hists *hists)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 944) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 945) if (show_baseline_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 946) hists__baseline_only(hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 947)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 948) hists__precompute(hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 949) hists__output_resort(hists, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 950)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 951) if (compute == COMPUTE_CYCLES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 952) symbol_conf.report_block = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 953)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 954) hists__fprintf(hists, !quiet, 0, 0, 0, stdout,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 955) !symbol_conf.use_callchain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 956) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 957)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 958) static void data__fprintf(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 959) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 960) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 961) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 963) fprintf(stdout, "# Data files:\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 964)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 965) data__for_each_file(i, d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 966) fprintf(stdout, "# [%d] %s %s\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 967) d->idx, d->data.path,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 968) !d->idx ? "(Baseline)" : "");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 969)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 970) fprintf(stdout, "#\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 971) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 972)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 973) static void data_process(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 974) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 975) struct evlist *evlist_base = data__files[0].session->evlist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 976) struct evsel *evsel_base;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 977) bool first = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 978)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 979) evlist__for_each_entry(evlist_base, evsel_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 980) struct hists *hists_base = evsel__hists(evsel_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 981) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 982) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 983)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 984) data__for_each_file_new(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 985) struct evlist *evlist = d->session->evlist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 986) struct evsel *evsel;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 987) struct hists *hists;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 988)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 989) evsel = evsel_match(evsel_base, evlist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 990) if (!evsel)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 991) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 992)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 993) hists = evsel__hists(evsel);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 994) d->hists = hists;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 995)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 996) hists__match(hists_base, hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 997)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 998) if (!show_baseline_only)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 999) hists__link(hists_base, hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1000) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1001)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1002) if (!quiet) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1003) fprintf(stdout, "%s# Event '%s'\n#\n", first ? "" : "\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1004) evsel__name(evsel_base));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1005) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1007) first = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1009) if (verbose > 0 || ((data__files_cnt > 2) && !quiet))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1010) data__fprintf();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1011)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1012) /* Don't sort callchain for perf diff */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1013) evsel__reset_sample_bit(evsel_base, CALLCHAIN);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1014)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1015) hists__process(hists_base);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1016) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1017) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1018)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1019) static int process_base_stream(struct data__file *data_base,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1020) struct data__file *data_pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1021) const char *title __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1022) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1023) struct evlist *evlist_base = data_base->session->evlist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1024) struct evlist *evlist_pair = data_pair->session->evlist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1025) struct evsel *evsel_base, *evsel_pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1026) struct evsel_streams *es_base, *es_pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1027)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1028) evlist__for_each_entry(evlist_base, evsel_base) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1029) evsel_pair = evsel_match(evsel_base, evlist_pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1030) if (!evsel_pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1031) continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1032)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1033) es_base = evsel_streams__entry(data_base->evlist_streams,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1034) evsel_base->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1035) if (!es_base)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1036) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1037)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1038) es_pair = evsel_streams__entry(data_pair->evlist_streams,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1039) evsel_pair->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1040) if (!es_pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1041) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1042)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1043) evsel_streams__match(es_base, es_pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1044) evsel_streams__report(es_base, es_pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1045) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1046)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1047) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1048) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1049)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1050) static void stream_process(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1051) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1052) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1053) * Stream comparison only supports two data files.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1054) * perf.data.old and perf.data. data__files[0] is perf.data.old,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1055) * data__files[1] is perf.data.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1056) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1057) process_base_stream(&data__files[0], &data__files[1],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1058) "# Output based on old perf data:\n#\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1059) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1060)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1061) static void data__free(struct data__file *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1062) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1063) int col;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1064)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1065) if (d->evlist_streams)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1066) evlist_streams__delete(d->evlist_streams);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1067)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1068) for (col = 0; col < PERF_HPP_DIFF__MAX_INDEX; col++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1069) struct diff_hpp_fmt *fmt = &d->fmt[col];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1070)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1071) zfree(&fmt->header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1072) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1073) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1074)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1075) static int abstime_str_dup(char **pstr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1076) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1077) char *str = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1078)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1079) if (pdiff.time_str && strchr(pdiff.time_str, ':')) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1080) str = strdup(pdiff.time_str);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1081) if (!str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1082) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1083) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1084)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1085) *pstr = str;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1086) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1087) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1088)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1089) static int parse_absolute_time(struct data__file *d, char **pstr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1090) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1091) char *p = *pstr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1092) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1093)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1094) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1095) * Absolute timestamp for one file has the format: a.b,c.d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1096) * For multiple files, the format is: a.b,c.d:a.b,c.d
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1097) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1098) p = strchr(*pstr, ':');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1099) if (p) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1100) if (p == *pstr) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1101) pr_err("Invalid time string\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1102) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1104)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1105) *p = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1106) p++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1107) if (*p == 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1108) pr_err("Invalid time string\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1109) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1110) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1113) ret = perf_time__parse_for_ranges(*pstr, d->session,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1114) &pdiff.ptime_range,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1115) &pdiff.range_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1116) &pdiff.range_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1117) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1118) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1119)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1120) if (!p || *p == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1121) *pstr = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1122) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1123) *pstr = p;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1125) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1126) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1127)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1128) static int parse_percent_time(struct data__file *d)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1129) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1130) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1131)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1132) ret = perf_time__parse_for_ranges(pdiff.time_str, d->session,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1133) &pdiff.ptime_range,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1134) &pdiff.range_size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1135) &pdiff.range_num);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1136) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1137) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1138)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1139) static int parse_time_str(struct data__file *d, char *abstime_ostr,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1140) char **pabstime_tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1141) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1142) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1143)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1144) if (abstime_ostr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1145) ret = parse_absolute_time(d, pabstime_tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1146) else if (pdiff.time_str)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1147) ret = parse_percent_time(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1148)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1149) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1150) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1151)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1152) static int check_file_brstack(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1154) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1155) bool has_br_stack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1156) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1158) data__for_each_file(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1159) d->session = perf_session__new(&d->data, false, &pdiff.tool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1160) if (IS_ERR(d->session)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1161) pr_err("Failed to open %s\n", d->data.path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1162) return PTR_ERR(d->session);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1165) has_br_stack = perf_header__has_feat(&d->session->header,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1166) HEADER_BRANCH_STACK);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1167) perf_session__delete(d->session);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1168) if (!has_br_stack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1169) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1172) /* Set only all files having branch stacks */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1173) pdiff.has_br_stack = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1174) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1175) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1177) static int __cmd_diff(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1178) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1179) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1180) int ret, i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1181) char *abstime_ostr, *abstime_tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1182)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1183) ret = abstime_str_dup(&abstime_ostr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1184) if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1185) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1186)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1187) abstime_tmp = abstime_ostr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1188) ret = -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1189)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1190) data__for_each_file(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1191) d->session = perf_session__new(&d->data, false, &pdiff.tool);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1192) if (IS_ERR(d->session)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1193) ret = PTR_ERR(d->session);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1194) pr_err("Failed to open %s\n", d->data.path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1195) goto out_delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1198) if (pdiff.time_str) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1199) ret = parse_time_str(d, abstime_ostr, &abstime_tmp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1200) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1201) goto out_delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1202) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1203)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1204) if (cpu_list) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1205) ret = perf_session__cpu_bitmap(d->session, cpu_list,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1206) cpu_bitmap);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1207) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1208) goto out_delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1209) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1210)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1211) ret = perf_session__process_events(d->session);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1212) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1213) pr_err("Failed to process %s\n", d->data.path);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1214) goto out_delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1215) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1216)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1217) perf_evlist__collapse_resort(d->session->evlist);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1218)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1219) if (pdiff.ptime_range)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1220) zfree(&pdiff.ptime_range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1221)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1222) if (compute == COMPUTE_STREAM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1223) d->evlist_streams = evlist__create_streams(
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1224) d->session->evlist, 5);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1225) if (!d->evlist_streams) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1226) ret = -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1227) goto out_delete;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1228) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1229) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1230) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1231)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1232) if (compute == COMPUTE_STREAM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1233) stream_process();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1234) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1235) data_process();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1236)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1237) out_delete:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1238) data__for_each_file(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1239) perf_session__delete(d->session);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1240) data__free(d);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1241) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1242)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1243) free(data__files);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1244)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1245) if (pdiff.ptime_range)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1246) zfree(&pdiff.ptime_range);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1247)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1248) if (abstime_ostr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1249) free(abstime_ostr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1250)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1251) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1252) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1253)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1254) static const char * const diff_usage[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1255) "perf diff [<options>] [old_file] [new_file]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1256) NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1257) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1258)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1259) static const struct option options[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1260) OPT_INCR('v', "verbose", &verbose,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1261) "be more verbose (show symbol address, etc)"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1262) OPT_BOOLEAN('q', "quiet", &quiet, "Do not show any message"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1263) OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1264) "Show only items with match in baseline"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1265) OPT_CALLBACK('c', "compute", &compute,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1266) "delta,delta-abs,ratio,wdiff:w1,w2 (default delta-abs),cycles",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1267) "Entries differential computation selection",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1268) setup_compute),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1269) OPT_BOOLEAN('p', "period", &show_period,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1270) "Show period values."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1271) OPT_BOOLEAN('F', "formula", &show_formula,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1272) "Show formula."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1273) OPT_BOOLEAN(0, "cycles-hist", &cycles_hist,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1274) "Show cycles histogram and standard deviation "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1275) "- WARNING: use only with -c cycles."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1276) OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1277) "dump raw trace in ASCII"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1278) OPT_BOOLEAN('f', "force", &force, "don't complain, do it"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1279) OPT_STRING(0, "kallsyms", &symbol_conf.kallsyms_name,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1280) "file", "kallsyms pathname"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1281) OPT_BOOLEAN('m', "modules", &symbol_conf.use_modules,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1282) "load module symbols - WARNING: use only with -k and LIVE kernel"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1283) OPT_STRING('d', "dsos", &symbol_conf.dso_list_str, "dso[,dso...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1284) "only consider symbols in these dsos"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1285) OPT_STRING('C', "comms", &symbol_conf.comm_list_str, "comm[,comm...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1286) "only consider symbols in these comms"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1287) OPT_STRING('S', "symbols", &symbol_conf.sym_list_str, "symbol[,symbol...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1288) "only consider these symbols"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1289) OPT_STRING('s', "sort", &sort_order, "key[,key2...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1290) "sort by key(s): pid, comm, dso, symbol, parent, cpu, srcline, ..."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1291) " Please refer the man page for the complete list."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1292) OPT_STRING_NOEMPTY('t', "field-separator", &symbol_conf.field_sep, "separator",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1293) "separator for columns, no spaces will be added between "
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1294) "columns '.' is reserved."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1295) OPT_CALLBACK(0, "symfs", NULL, "directory",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1296) "Look for files with symbols relative to this directory",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1297) symbol__config_symfs),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1298) OPT_UINTEGER('o', "order", &sort_compute, "Specify compute sorting."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1299) OPT_CALLBACK(0, "percentage", NULL, "relative|absolute",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1300) "How to display percentage of filtered entries", parse_filter_percentage),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1301) OPT_STRING(0, "time", &pdiff.time_str, "str",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1302) "Time span (time percent or absolute timestamp)"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1303) OPT_STRING(0, "cpu", &cpu_list, "cpu", "list of cpus to profile"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1304) OPT_STRING(0, "pid", &symbol_conf.pid_list_str, "pid[,pid...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1305) "only consider symbols in these pids"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1306) OPT_STRING(0, "tid", &symbol_conf.tid_list_str, "tid[,tid...]",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1307) "only consider symbols in these tids"),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1308) OPT_BOOLEAN(0, "stream", &pdiff.stream,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1309) "Enable hot streams comparison."),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1310) OPT_END()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1311) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1312)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1313) static double baseline_percent(struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1314) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1315) u64 total = hists__total_period(he->hists);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1316)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1317) return 100.0 * he->stat.period / total;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1318) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1319)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1320) static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1321) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1322) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1323) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1324) container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1325) double percent = baseline_percent(he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1326) char pfmt[20] = " ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1327)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1328) if (!he->dummy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1329) scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1330) return percent_color_snprintf(hpp->buf, hpp->size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1331) pfmt, percent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1332) } else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1333) return scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1334) dfmt->header_width, pfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1335) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1336)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1337) static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1338) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1339) double percent = baseline_percent(he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1340) const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1341) int ret = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1342)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1343) if (!he->dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1344) ret = scnprintf(buf, size, fmt, percent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1345)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1346) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1347) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1348)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1349) static int cycles_printf(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1350) struct perf_hpp *hpp, int width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1351) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1352) struct block_hist *bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1353) struct block_hist *bh_pair = container_of(pair, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1354) struct hist_entry *block_he;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1355) struct block_info *bi;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1356) char buf[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1357) char *start_line, *end_line;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1358)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1359) block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1360) if (!block_he) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1361) hpp->skip = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1362) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1363) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1364)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1365) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1366) * Avoid printing the warning "addr2line_init failed for ..."
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1367) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1368) symbol_conf.disable_add2line_warn = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1369)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1370) bi = block_he->block_info;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1371)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1372) start_line = map__srcline(he->ms.map, bi->sym->start + bi->start,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1373) he->ms.sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1374)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1375) end_line = map__srcline(he->ms.map, bi->sym->start + bi->end,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1376) he->ms.sym);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1377)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1378) if ((strncmp(start_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1379) (strncmp(end_line, SRCLINE_UNKNOWN, strlen(SRCLINE_UNKNOWN)) != 0)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1380) scnprintf(buf, sizeof(buf), "[%s -> %s] %4ld",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1381) start_line, end_line, block_he->diff.cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1382) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1383) scnprintf(buf, sizeof(buf), "[%7lx -> %7lx] %4ld",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1384) bi->start, bi->end, block_he->diff.cycles);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1385) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1386)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1387) free_srcline(start_line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1388) free_srcline(end_line);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1389)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1390) return scnprintf(hpp->buf, hpp->size, "%*s", width, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1391) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1392)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1393) static int __hpp__color_compare(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1394) struct perf_hpp *hpp, struct hist_entry *he,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1395) int comparison_method)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1396) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1397) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1398) container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1399) struct hist_entry *pair = get_pair_fmt(he, dfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1400) double diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1401) s64 wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1402) char pfmt[20] = " ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1403)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1404) if (!pair) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1405) if (comparison_method == COMPUTE_CYCLES) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1406) struct block_hist *bh;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1407)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1408) bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1409) if (bh->block_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1410) hpp->skip = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1411) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1412)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1413) goto no_print;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1414) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1415)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1416) switch (comparison_method) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1417) case COMPUTE_DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1418) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1419) diff = pair->diff.period_ratio_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1420) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1421) diff = compute_delta(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1422)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1423) scnprintf(pfmt, 20, "%%%+d.2f%%%%", dfmt->header_width - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1424) return percent_color_snprintf(hpp->buf, hpp->size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1425) pfmt, diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1426) case COMPUTE_RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1427) if (he->dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1428) goto dummy_print;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1429) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1430) diff = pair->diff.period_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1431) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1432) diff = compute_ratio(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1433)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1434) scnprintf(pfmt, 20, "%%%d.6f", dfmt->header_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1435) return value_color_snprintf(hpp->buf, hpp->size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1436) pfmt, diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1437) case COMPUTE_WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1438) if (he->dummy)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1439) goto dummy_print;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1440) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1441) wdiff = pair->diff.wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1442) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1443) wdiff = compute_wdiff(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1444)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1445) scnprintf(pfmt, 20, "%%14ld", dfmt->header_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1446) return color_snprintf(hpp->buf, hpp->size,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1447) get_percent_color(wdiff),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1448) pfmt, wdiff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1449) case COMPUTE_CYCLES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1450) return cycles_printf(he, pair, hpp, dfmt->header_width);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1451) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1452) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1453) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1454) dummy_print:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1455) return scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1456) dfmt->header_width, "N/A");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1457) no_print:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1458) return scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1459) dfmt->header_width, pfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1460) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1461)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1462) static int hpp__color_delta(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1463) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1464) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1465) return __hpp__color_compare(fmt, hpp, he, COMPUTE_DELTA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1466) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1467)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1468) static int hpp__color_ratio(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1469) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1470) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1471) return __hpp__color_compare(fmt, hpp, he, COMPUTE_RATIO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1472) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1473)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1474) static int hpp__color_wdiff(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1475) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1476) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1477) return __hpp__color_compare(fmt, hpp, he, COMPUTE_WEIGHTED_DIFF);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1478) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1479)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1480) static int hpp__color_cycles(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1481) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1482) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1483) return __hpp__color_compare(fmt, hpp, he, COMPUTE_CYCLES);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1484) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1485)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1486) static int all_zero(unsigned long *vals, int len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1487) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1488) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1489)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1490) for (i = 0; i < len; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1491) if (vals[i] != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1492) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1493) return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1494) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1495)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1496) static int print_cycles_spark(char *bf, int size, unsigned long *svals, u64 n)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1497) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1498) int printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1499)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1500) if (n <= 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1501) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1502)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1503) if (n > NUM_SPARKS)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1504) n = NUM_SPARKS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1505) if (all_zero(svals, n))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1506) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1507)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1508) printed = print_spark(bf, size, svals, n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1509) printed += scnprintf(bf + printed, size - printed, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1510) return printed;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1511) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1512)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1513) static int hpp__color_cycles_hist(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1514) struct perf_hpp *hpp, struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1515) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1516) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1517) container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1518) struct hist_entry *pair = get_pair_fmt(he, dfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1519) struct block_hist *bh = container_of(he, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1520) struct block_hist *bh_pair;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1521) struct hist_entry *block_he;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1522) char spark[32], buf[128];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1523) double r;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1524) int ret, pad;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1525)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1526) if (!pair) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1527) if (bh->block_idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1528) hpp->skip = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1529)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1530) goto no_print;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1531) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1532)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1533) bh_pair = container_of(pair, struct block_hist, he);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1534)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1535) block_he = hists__get_entry(&bh_pair->block_hists, bh->block_idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1536) if (!block_he) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1537) hpp->skip = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1538) goto no_print;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1539) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1540)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1541) ret = print_cycles_spark(spark, sizeof(spark), block_he->diff.svals,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1542) block_he->diff.stats.n);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1543)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1544) r = rel_stddev_stats(stddev_stats(&block_he->diff.stats),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1545) avg_stats(&block_he->diff.stats));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1546)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1547) if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1548) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1549) * Padding spaces if number of sparks less than NUM_SPARKS
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1550) * otherwise the output is not aligned.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1551) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1552) pad = NUM_SPARKS - ((ret - 1) / 3);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1553) scnprintf(buf, sizeof(buf), "%s%5.1f%% %s", "\u00B1", r, spark);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1554) ret = scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1555) dfmt->header_width, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1556)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1557) if (pad) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1558) ret += scnprintf(hpp->buf + ret, hpp->size - ret,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1559) "%-*s", pad, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1560) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1561)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1562) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1563) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1564)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1565) no_print:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1566) return scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1567) dfmt->header_width, " ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1568) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1569)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1570) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1571) hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1572) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1573) switch (idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1574) case PERF_HPP_DIFF__PERIOD_BASELINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1575) scnprintf(buf, size, "%" PRIu64, he->stat.period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1576) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1577)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1578) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1579) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1580) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1581) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1582)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1583) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1584) hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1585) int idx, char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1586) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1587) double diff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1588) double ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1589) s64 wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1590)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1591) switch (idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1592) case PERF_HPP_DIFF__DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1593) case PERF_HPP_DIFF__DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1594) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1595) diff = pair->diff.period_ratio_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1596) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1597) diff = compute_delta(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1598)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1599) scnprintf(buf, size, "%+4.2F%%", diff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1600) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1601)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1602) case PERF_HPP_DIFF__RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1603) /* No point for ratio number if we are dummy.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1604) if (he->dummy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1605) scnprintf(buf, size, "N/A");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1606) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1607) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1608)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1609) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1610) ratio = pair->diff.period_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1611) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1612) ratio = compute_ratio(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1613)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1614) if (ratio > 0.0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1615) scnprintf(buf, size, "%14.6F", ratio);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1616) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1617)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1618) case PERF_HPP_DIFF__WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1619) /* No point for wdiff number if we are dummy.. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1620) if (he->dummy) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1621) scnprintf(buf, size, "N/A");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1622) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1623) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1624)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1625) if (pair->diff.computed)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1626) wdiff = pair->diff.wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1627) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1628) wdiff = compute_wdiff(he, pair);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1629)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1630) if (wdiff != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1631) scnprintf(buf, size, "%14ld", wdiff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1632) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1633)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1634) case PERF_HPP_DIFF__FORMULA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1635) formula_fprintf(he, pair, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1636) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1637)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1638) case PERF_HPP_DIFF__PERIOD:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1639) scnprintf(buf, size, "%" PRIu64, pair->stat.period);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1640) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1641)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1642) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1643) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1644) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1645) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1646)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1647) static void
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1648) __hpp__entry_global(struct hist_entry *he, struct diff_hpp_fmt *dfmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1649) char *buf, size_t size)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1650) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1651) struct hist_entry *pair = get_pair_fmt(he, dfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1652) int idx = dfmt->idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1653)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1654) /* baseline is special */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1655) if (idx == PERF_HPP_DIFF__BASELINE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1656) hpp__entry_baseline(he, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1657) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1658) if (pair)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1659) hpp__entry_pair(he, pair, idx, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1660) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1661) hpp__entry_unpair(he, idx, buf, size);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1662) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1663) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1664)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1665) static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1666) struct hist_entry *he)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1667) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1668) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1669) container_of(_fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1670) char buf[MAX_COL_WIDTH] = " ";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1671)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1672) __hpp__entry_global(he, dfmt, buf, MAX_COL_WIDTH);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1673)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1674) if (symbol_conf.field_sep)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1675) return scnprintf(hpp->buf, hpp->size, "%s", buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1676) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1677) return scnprintf(hpp->buf, hpp->size, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1678) dfmt->header_width, buf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1679) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1680)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1681) static int hpp__header(struct perf_hpp_fmt *fmt, struct perf_hpp *hpp,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1682) struct hists *hists __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1683) int line __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1684) int *span __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1685) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1686) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1687) container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1688)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1689) BUG_ON(!dfmt->header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1690) return scnprintf(hpp->buf, hpp->size, dfmt->header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1691) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1692)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1693) static int hpp__width(struct perf_hpp_fmt *fmt,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1694) struct perf_hpp *hpp __maybe_unused,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1695) struct hists *hists __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1696) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1697) struct diff_hpp_fmt *dfmt =
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1698) container_of(fmt, struct diff_hpp_fmt, fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1699)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1700) BUG_ON(dfmt->header_width <= 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1701) return dfmt->header_width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1702) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1703)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1704) static void init_header(struct data__file *d, struct diff_hpp_fmt *dfmt)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1705) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1706) #define MAX_HEADER_NAME 100
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1707) char buf_indent[MAX_HEADER_NAME];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1708) char buf[MAX_HEADER_NAME];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1709) const char *header = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1710) int width = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1711)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1712) BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1713) header = columns[dfmt->idx].name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1714) width = columns[dfmt->idx].width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1715)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1716) /* Only our defined HPP fmts should appear here. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1717) BUG_ON(!header);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1718)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1719) if (data__files_cnt > 2)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1720) scnprintf(buf, MAX_HEADER_NAME, "%s/%d", header, d->idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1721)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1722) #define NAME (data__files_cnt > 2 ? buf : header)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1723) dfmt->header_width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1724) width = (int) strlen(NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1725) if (dfmt->header_width < width)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1726) dfmt->header_width = width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1727)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1728) scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1729) dfmt->header_width, NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1730)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1731) dfmt->header = strdup(buf_indent);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1732) #undef MAX_HEADER_NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1733) #undef NAME
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1734) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1735)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1736) static void data__hpp_register(struct data__file *d, int idx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1737) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1738) struct diff_hpp_fmt *dfmt = &d->fmt[idx];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1739) struct perf_hpp_fmt *fmt = &dfmt->fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1740)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1741) dfmt->idx = idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1742)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1743) fmt->header = hpp__header;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1744) fmt->width = hpp__width;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1745) fmt->entry = hpp__entry_global;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1746) fmt->cmp = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1747) fmt->collapse = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1748)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1749) /* TODO more colors */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1750) switch (idx) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1751) case PERF_HPP_DIFF__BASELINE:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1752) fmt->color = hpp__color_baseline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1753) fmt->sort = hist_entry__cmp_baseline;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1754) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1755) case PERF_HPP_DIFF__DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1756) fmt->color = hpp__color_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1757) fmt->sort = hist_entry__cmp_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1758) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1759) case PERF_HPP_DIFF__RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1760) fmt->color = hpp__color_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1761) fmt->sort = hist_entry__cmp_ratio;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1762) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1763) case PERF_HPP_DIFF__WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1764) fmt->color = hpp__color_wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1765) fmt->sort = hist_entry__cmp_wdiff;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1766) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1767) case PERF_HPP_DIFF__DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1768) fmt->color = hpp__color_delta;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1769) fmt->sort = hist_entry__cmp_delta_abs;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1770) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1771) case PERF_HPP_DIFF__CYCLES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1772) fmt->color = hpp__color_cycles;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1773) fmt->sort = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1774) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1775) case PERF_HPP_DIFF__CYCLES_HIST:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1776) fmt->color = hpp__color_cycles_hist;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1777) fmt->sort = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1778) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1779) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1780) fmt->sort = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1781) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1782) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1783)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1784) init_header(d, dfmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1785) perf_hpp__column_register(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1786) perf_hpp__register_sort_field(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1787) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1788)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1789) static int ui_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1790) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1791) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1792) struct perf_hpp_fmt *fmt;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1793) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1794)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1795) data__for_each_file(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1796)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1797) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1798) * Baseline or compute realted columns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1799) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1800) * PERF_HPP_DIFF__BASELINE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1801) * PERF_HPP_DIFF__DELTA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1802) * PERF_HPP_DIFF__RATIO
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1803) * PERF_HPP_DIFF__WEIGHTED_DIFF
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1804) * PERF_HPP_DIFF__CYCLES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1805) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1806) data__hpp_register(d, i ? compute_2_hpp[compute] :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1807) PERF_HPP_DIFF__BASELINE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1808)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1809) if (cycles_hist && i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1810) data__hpp_register(d, PERF_HPP_DIFF__CYCLES_HIST);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1811)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1812) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1813) * And the rest:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1814) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1815) * PERF_HPP_DIFF__FORMULA
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1816) * PERF_HPP_DIFF__PERIOD
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1817) * PERF_HPP_DIFF__PERIOD_BASELINE
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1818) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1819) if (show_formula && i)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1820) data__hpp_register(d, PERF_HPP_DIFF__FORMULA);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1821)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1822) if (show_period)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1823) data__hpp_register(d, i ? PERF_HPP_DIFF__PERIOD :
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1824) PERF_HPP_DIFF__PERIOD_BASELINE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1825) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1826)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1827) if (!sort_compute)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1828) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1829)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1830) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1831) * Prepend an fmt to sort on columns at 'sort_compute' first.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1832) * This fmt is added only to the sort list but not to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1833) * output fields list.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1834) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1835) * Note that this column (data) can be compared twice - one
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1836) * for this 'sort_compute' fmt and another for the normal
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1837) * diff_hpp_fmt. But it shouldn't a problem as most entries
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1838) * will be sorted out by first try or baseline and comparing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1839) * is not a costly operation.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1840) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1841) fmt = zalloc(sizeof(*fmt));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1842) if (fmt == NULL) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1843) pr_err("Memory allocation failed\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1844) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1845) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1846)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1847) fmt->cmp = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1848) fmt->collapse = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1849)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1850) switch (compute) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1851) case COMPUTE_DELTA:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1852) fmt->sort = hist_entry__cmp_delta_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1853) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1854) case COMPUTE_RATIO:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1855) fmt->sort = hist_entry__cmp_ratio_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1856) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1857) case COMPUTE_WEIGHTED_DIFF:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1858) fmt->sort = hist_entry__cmp_wdiff_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1859) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1860) case COMPUTE_DELTA_ABS:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1861) fmt->sort = hist_entry__cmp_delta_abs_idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1862) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1863) case COMPUTE_CYCLES:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1864) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1865) * Should set since 'fmt->sort' is called without
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1866) * checking valid during sorting
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1867) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1868) fmt->sort = hist_entry__cmp_nop;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1869) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1870) default:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1871) BUG_ON(1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1872) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1873)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1874) perf_hpp__prepend_sort_field(fmt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1875) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1876) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1877)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1878) static int data_init(int argc, const char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1879) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1880) struct data__file *d;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1881) static const char *defaults[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1882) "perf.data.old",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1883) "perf.data",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1884) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1885) bool use_default = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1886) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1887)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1888) data__files_cnt = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1889)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1890) if (argc) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1891) if (argc == 1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1892) defaults[1] = argv[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1893) else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1894) data__files_cnt = argc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1895) use_default = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1896) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1897) } else if (perf_guest) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1898) defaults[0] = "perf.data.host";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1899) defaults[1] = "perf.data.guest";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1900) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1901)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1902) if (sort_compute >= (unsigned int) data__files_cnt) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1903) pr_err("Order option out of limit.\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1904) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1905) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1906)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1907) data__files = zalloc(sizeof(*data__files) * data__files_cnt);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1908) if (!data__files)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1909) return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1910)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1911) data__for_each_file(i, d) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1912) struct perf_data *data = &d->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1913)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1914) data->path = use_default ? defaults[i] : argv[i];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1915) data->mode = PERF_DATA_MODE_READ,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1916) data->force = force,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1917)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1918) d->idx = i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1919) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1920)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1921) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1922) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1923)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1924) static int diff__config(const char *var, const char *value,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1925) void *cb __maybe_unused)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1926) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1927) if (!strcmp(var, "diff.order")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1928) int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1929) if (perf_config_int(&ret, var, value) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1930) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1931) sort_compute = ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1932) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1933) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1934) if (!strcmp(var, "diff.compute")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1935) if (!strcmp(value, "delta")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1936) compute = COMPUTE_DELTA;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1937) } else if (!strcmp(value, "delta-abs")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1938) compute = COMPUTE_DELTA_ABS;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1939) } else if (!strcmp(value, "ratio")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1940) compute = COMPUTE_RATIO;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1941) } else if (!strcmp(value, "wdiff")) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1942) compute = COMPUTE_WEIGHTED_DIFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1943) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1944) pr_err("Invalid compute method: %s\n", value);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1945) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1946) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1947) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1948)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1949) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1950) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1951)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1952) int cmd_diff(int argc, const char **argv)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1953) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1954) int ret = hists__init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1955)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1956) if (ret < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1957) return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1958)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1959) perf_config(diff__config, NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1960)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1961) argc = parse_options(argc, argv, options, diff_usage, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1962)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1963) if (quiet)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1964) perf_quiet_option();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1965)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1966) if (cycles_hist && (compute != COMPUTE_CYCLES))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1967) usage_with_options(diff_usage, options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1968)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1969) if (pdiff.stream)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1970) compute = COMPUTE_STREAM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1971)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1972) symbol__annotation_init();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1973)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1974) if (symbol__init(NULL) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1975) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1976)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1977) if (data_init(argc, argv) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1978) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1979)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1980) if (check_file_brstack() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1981) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1982)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1983) if ((compute == COMPUTE_CYCLES || compute == COMPUTE_STREAM)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1984) && !pdiff.has_br_stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1985) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1986) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1987)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1988) if (compute == COMPUTE_STREAM) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1989) symbol_conf.show_branchflag_count = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1990) symbol_conf.disable_add2line_warn = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1991) callchain_param.mode = CHAIN_FLAT;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1992) callchain_param.key = CCKEY_SRCLINE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1993) callchain_param.branch_callstack = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1994) symbol_conf.use_callchain = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1995) callchain_register_param(&callchain_param);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1996) sort_order = "srcline,symbol,dso";
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1997) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1998) if (ui_init() < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1999) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2000)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2001) sort__mode = SORT_MODE__DIFF;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2002) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2003)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2004) if (setup_sorting(NULL) < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2005) usage_with_options(diff_usage, options);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2006)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2007) setup_pager();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2008)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2009) sort__setup_elide(NULL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2010)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2011) return __cmd_diff();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2012) }