/*
* builtin-diff.c
*
* Builtin diff command: Analyze two perf.data input files, look up and read
* DSOs and symbol information, sort them and produce a diff.
*/
#include "builtin.h"
#include "util/debug.h"
#include "util/event.h"
#include "util/hist.h"
#include "util/evsel.h"
#include "util/evlist.h"
#include "util/session.h"
#include "util/tool.h"
#include "util/sort.h"
#include "util/symbol.h"
#include "util/util.h"
#include "util/data.h"
#include <stdlib.h>
#include <math.h>
/* Diff command specific HPP columns. */
enum {
PERF_HPP_DIFF__BASELINE,
PERF_HPP_DIFF__PERIOD,
PERF_HPP_DIFF__PERIOD_BASELINE,
PERF_HPP_DIFF__DELTA,
PERF_HPP_DIFF__RATIO,
PERF_HPP_DIFF__WEIGHTED_DIFF,
PERF_HPP_DIFF__FORMULA,
PERF_HPP_DIFF__MAX_INDEX
};
struct diff_hpp_fmt {
struct perf_hpp_fmt fmt;
int idx;
char *header;
int header_width;
};
struct data__file {
struct perf_session *session;
struct perf_data_file file;
int idx;
struct hists *hists;
struct diff_hpp_fmt fmt[PERF_HPP_DIFF__MAX_INDEX];
};
static struct data__file *data__files;
static int data__files_cnt;
#define data__for_each_file_start(i, d, s) \
for (i = s, d = &data__files[s]; \
i < data__files_cnt; \
i++, d = &data__files[i])
#define data__for_each_file(i, d) data__for_each_file_start(i, d, 0)
#define data__for_each_file_new(i, d) data__for_each_file_start(i, d, 1)
static char diff__default_sort_order[] = "dso,symbol";
static bool force;
static bool show_period;
static bool show_formula;
static bool show_baseline_only;
static unsigned int 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 compute_2_hpp[COMPUTE_MAX] = {
[COMPUTE_DELTA] = PERF_HPP_DIFF__DELTA,
[COMPUTE_RATIO] = PERF_HPP_DIFF__RATIO,
[COMPUTE_WEIGHTED_DIFF] = PERF_HPP_DIFF__WEIGHTED_DIFF,
};
#define MAX_COL_WIDTH 70
static struct header_column {
const char *name;
int width;
} columns[PERF_HPP_DIFF__MAX_INDEX] = {
[PERF_HPP_DIFF__BASELINE] = {
.name = "Baseline",
},
[PERF_HPP_DIFF__PERIOD] = {
.name = "Period",
.width = 14,
},
[PERF_HPP_DIFF__PERIOD_BASELINE] = {
.name = "Base period",
.width = 14,
},
[PERF_HPP_DIFF__DELTA] = {
.name = "Delta",
.width = 7,
},
[PERF_HPP_DIFF__RATIO] = {
.name = "Ratio",
.width = 14,
},
[PERF_HPP_DIFF__WEIGHTED_DIFF] = {
.name = "Weighted diff",
.width = 14,
},
[PERF_HPP_DIFF__FORMULA] = {
.name = "Formula",
.width = MAX_COL_WIDTH,
}
};
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)