static bool show_baseline_only;
static bool sort_compute;
+static s64 compute_wdiff_w1;
+static s64 compute_wdiff_w2;
+
enum {
COMPUTE_DELTA,
COMPUTE_RATIO,
+ COMPUTE_WEIGHTED_DIFF,
COMPUTE_MAX,
};
const char *compute_names[COMPUTE_MAX] = {
[COMPUTE_DELTA] = "delta",
[COMPUTE_RATIO] = "ratio",
+ [COMPUTE_WEIGHTED_DIFF] = "wdiff",
};
static int compute;
+static int setup_compute_opt_wdiff(char *opt)
+{
+ char *w1_str = opt;
+ char *w2_str;
+
+ int ret = -EINVAL;
+
+ if (!opt)
+ goto out;
+
+ w2_str = strchr(opt, ',');
+ if (!w2_str)
+ goto out;
+
+ *w2_str++ = 0x0;
+ if (!*w2_str)
+ goto out;
+
+ compute_wdiff_w1 = strtol(w1_str, NULL, 10);
+ compute_wdiff_w2 = strtol(w2_str, NULL, 10);
+
+ if (!compute_wdiff_w1 || !compute_wdiff_w2)
+ goto out;
+
+ pr_debug("compute wdiff w1(%" PRId64 ") w2(%" PRId64 ")\n",
+ compute_wdiff_w1, compute_wdiff_w2);
+
+ ret = 0;
+
+ out:
+ if (ret)
+ pr_err("Failed: wrong weight data, use 'wdiff:w1,w2'\n");
+
+ return ret;
+}
+
+static int setup_compute_opt(char *opt)
+{
+ if (compute == COMPUTE_WEIGHTED_DIFF)
+ return setup_compute_opt_wdiff(opt);
+
+ if (opt) {
+ pr_err("Failed: extra option specified '%s'", opt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static int setup_compute(const struct option *opt, const char *str,
int unset __maybe_unused)
{
int *cp = (int *) opt->value;
+ char *cstr = (char *) str;
+ char buf[50];
unsigned i;
+ char *option;
if (!str) {
*cp = COMPUTE_DELTA;
if (*str == '+') {
sort_compute = true;
- str++;
+ cstr = (char *) ++str;
if (!*str)
return 0;
}
+ option = strchr(str, ':');
+ if (option) {
+ unsigned len = option++ - str;
+
+ /*
+ * The str data are not writeable, so we need
+ * to use another buffer.
+ */
+
+ /* No option value is longer. */
+ if (len >= sizeof(buf))
+ return -EINVAL;
+
+ strncpy(buf, str, len);
+ buf[len] = 0x0;
+ cstr = buf;
+ }
+
for (i = 0; i < COMPUTE_MAX; i++)
- if (!strcmp(str, compute_names[i])) {
+ if (!strcmp(cstr, compute_names[i])) {
*cp = i;
- return 0;
+ return setup_compute_opt(option);
}
pr_err("Failed: '%s' is not computation method "
- "(use 'delta' or 'ratio').\n", str);
+ "(use 'delta','ratio' or 'wdiff')\n", str);
return -EINVAL;
}
return he->diff.period_ratio;
}
+s64 perf_diff__compute_wdiff(struct hist_entry *he)
+{
+ struct hist_entry *pair = he->pair;
+ u64 new_period = he->stat.period;
+ u64 old_period = pair ? pair->stat.period : 0;
+
+ he->diff.computed = true;
+
+ if (!pair)
+ he->diff.wdiff = 0;
+ else
+ he->diff.wdiff = new_period * compute_wdiff_w2 -
+ old_period * compute_wdiff_w1;
+
+ return he->diff.wdiff;
+}
+
static int hists__add_entry(struct hists *self,
struct addr_location *al, u64 period)
{
case COMPUTE_RATIO:
perf_diff__compute_ratio(he);
break;
+ case COMPUTE_WEIGHTED_DIFF:
+ perf_diff__compute_wdiff(he);
+ break;
default:
BUG_ON(1);
}
return cmp_doubles(l, r);
}
+ case COMPUTE_WEIGHTED_DIFF:
+ {
+ s64 l = left->diff.wdiff;
+ s64 r = right->diff.wdiff;
+
+ return r - l;
+ }
default:
BUG_ON(1);
}
"Show position displacement relative to baseline"),
OPT_BOOLEAN('b', "baseline-only", &show_baseline_only,
"Show only items with match in baseline"),
- OPT_CALLBACK('c', "compute", &compute, "delta,ratio (default delta)",
+ OPT_CALLBACK('c', "compute", &compute,
+ "delta,ratio,wdiff:w1,w2 (default delta)",
"Entries differential computation selection",
setup_compute),
OPT_BOOLEAN('D', "dump-raw-trace", &dump_trace,
case COMPUTE_RATIO:
perf_hpp__column_enable(PERF_HPP__RATIO, true);
break;
+ case COMPUTE_WEIGHTED_DIFF:
+ perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF, true);
+ break;
default:
BUG_ON(1);
};
return scnprintf(hpp->buf, hpp->size, fmt, buf);
}
+static int hpp__header_wdiff(struct perf_hpp *hpp)
+{
+ const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
+
+ return scnprintf(hpp->buf, hpp->size, fmt, "Weighted diff");
+}
+
+static int hpp__width_wdiff(struct perf_hpp *hpp __maybe_unused)
+{
+ return 14;
+}
+
+static int hpp__entry_wdiff(struct perf_hpp *hpp, struct hist_entry *he)
+{
+ const char *fmt = symbol_conf.field_sep ? "%s" : "%14s";
+ char buf[32] = " ";
+ s64 wdiff;
+
+ if (he->diff.computed)
+ wdiff = he->diff.wdiff;
+ else
+ wdiff = perf_diff__compute_wdiff(he);
+
+ if (wdiff != 0)
+ scnprintf(buf, sizeof(buf), "%14ld", wdiff);
+
+ return scnprintf(hpp->buf, hpp->size, fmt, buf);
+}
+
static int hpp__header_displ(struct perf_hpp *hpp)
{
return scnprintf(hpp->buf, hpp->size, "Displ.");
{ .cond = false, HPP__PRINT_FNS(period) },
{ .cond = false, HPP__PRINT_FNS(delta) },
{ .cond = false, HPP__PRINT_FNS(ratio) },
+ { .cond = false, HPP__PRINT_FNS(wdiff) },
{ .cond = false, HPP__PRINT_FNS(displ) }
};