perf diff: Move diff related columns into diff command
[deliverable/linux.git] / tools / perf / builtin-diff.c
index 9574ba18bc7b3d252a28e686118be9ccb1b3a66c..8734f1cee6dc7ed4d2118122cbab4af8d15c3ee8 100644 (file)
 #include "util/util.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;
@@ -60,6 +81,47 @@ const char *compute_names[COMPUTE_MAX] = {
 
 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;
@@ -596,34 +658,246 @@ static const struct option options[] = {
        OPT_END()
 };
 
-static void ui_init(void)
+static double baseline_percent(struct hist_entry *he)
 {
-       /*
-        * Display baseline/delta/ratio
-        * formula/periods columns.
-        */
-       perf_hpp__column_enable(PERF_HPP__BASELINE);
+       struct hists *hists = he->hists;
+       return 100.0 * he->stat.period / hists->stats.total_period;
+}
 
-       switch (compute) {
-       case COMPUTE_DELTA:
-               perf_hpp__column_enable(PERF_HPP__DELTA);
+static int hpp__color_baseline(struct perf_hpp_fmt *fmt,
+                              struct perf_hpp *hpp, struct hist_entry *he)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
+       double percent = baseline_percent(he);
+       char pfmt[20] = " ";
+
+       if (!he->dummy) {
+               scnprintf(pfmt, 20, "%%%d.2f%%%%", dfmt->header_width - 1);
+               return percent_color_snprintf(hpp->buf, hpp->size,
+                                             pfmt, percent);
+       } else
+               return scnprintf(hpp->buf, hpp->size, "%*s",
+                                dfmt->header_width, pfmt);
+}
+
+static int hpp__entry_baseline(struct hist_entry *he, char *buf, size_t size)
+{
+       double percent = baseline_percent(he);
+       const char *fmt = symbol_conf.field_sep ? "%.2f" : "%6.2f%%";
+       int ret = 0;
+
+       if (!he->dummy)
+               ret = scnprintf(buf, size, fmt, percent);
+
+       return ret;
+}
+
+static void
+hpp__entry_unpair(struct hist_entry *he, int idx, char *buf, size_t size)
+{
+       switch (idx) {
+       case PERF_HPP_DIFF__PERIOD_BASELINE:
+               scnprintf(buf, size, "%" PRIu64, he->stat.period);
                break;
-       case COMPUTE_RATIO:
-               perf_hpp__column_enable(PERF_HPP__RATIO);
+
+       default:
                break;
-       case COMPUTE_WEIGHTED_DIFF:
-               perf_hpp__column_enable(PERF_HPP__WEIGHTED_DIFF);
+       }
+}
+
+static void
+hpp__entry_pair(struct hist_entry *he, struct hist_entry *pair,
+               int idx, char *buf, size_t size)
+{
+       double diff;
+       double ratio;
+       s64 wdiff;
+
+       switch (idx) {
+       case PERF_HPP_DIFF__DELTA:
+               if (pair->diff.computed)
+                       diff = pair->diff.period_ratio_delta;
+               else
+                       diff = perf_diff__compute_delta(he, pair);
+
+               if (fabs(diff) >= 0.01)
+                       scnprintf(buf, size, "%+4.2F%%", diff);
+               break;
+
+       case PERF_HPP_DIFF__RATIO:
+               /* No point for ratio number if we are dummy.. */
+               if (he->dummy)
+                       break;
+
+               if (pair->diff.computed)
+                       ratio = pair->diff.period_ratio;
+               else
+                       ratio = perf_diff__compute_ratio(he, pair);
+
+               if (ratio > 0.0)
+                       scnprintf(buf, size, "%14.6F", ratio);
+               break;
+
+       case PERF_HPP_DIFF__WEIGHTED_DIFF:
+               /* No point for wdiff number if we are dummy.. */
+               if (he->dummy)
+                       break;
+
+               if (pair->diff.computed)
+                       wdiff = pair->diff.wdiff;
+               else
+                       wdiff = perf_diff__compute_wdiff(he, pair);
+
+               if (wdiff != 0)
+                       scnprintf(buf, size, "%14ld", wdiff);
+               break;
+
+       case PERF_HPP_DIFF__FORMULA:
+               perf_diff__formula(he, pair, buf, size);
                break;
+
+       case PERF_HPP_DIFF__PERIOD:
+               scnprintf(buf, size, "%" PRIu64, pair->stat.period);
+               break;
+
        default:
                BUG_ON(1);
        };
+}
+
+static void
+__hpp__entry_global(struct hist_entry *he, int idx, char *buf, size_t size)
+{
+       struct hist_entry *pair = hist_entry__next_pair(he);
+
+       /* baseline is special */
+       if (idx == PERF_HPP_DIFF__BASELINE)
+               hpp__entry_baseline(he, buf, size);
+       else {
+               if (pair)
+                       hpp__entry_pair(he, pair, idx, buf, size);
+               else
+                       hpp__entry_unpair(he, idx, buf, size);
+       }
+}
+
+static int hpp__entry_global(struct perf_hpp_fmt *_fmt, struct perf_hpp *hpp,
+                            struct hist_entry *he)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(_fmt, struct diff_hpp_fmt, fmt);
+       char buf[MAX_COL_WIDTH] = " ";
+
+       __hpp__entry_global(he, dfmt->idx, buf, MAX_COL_WIDTH);
+
+       if (symbol_conf.field_sep)
+               return scnprintf(hpp->buf, hpp->size, "%s", buf);
+       else
+               return scnprintf(hpp->buf, hpp->size, "%*s",
+                                dfmt->header_width, buf);
+}
+
+static int hpp__header(struct perf_hpp_fmt *fmt,
+                      struct perf_hpp *hpp)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
+
+       BUG_ON(!dfmt->header);
+       return scnprintf(hpp->buf, hpp->size, dfmt->header);
+}
+
+static int hpp__width(struct perf_hpp_fmt *fmt,
+                     struct perf_hpp *hpp __maybe_unused)
+{
+       struct diff_hpp_fmt *dfmt =
+               container_of(fmt, struct diff_hpp_fmt, fmt);
+
+       BUG_ON(dfmt->header_width <= 0);
+       return dfmt->header_width;
+}
+
+#define hpp__color_global hpp__entry_global
+
+#define FMT(_i, _entry, _color)                                        \
+       [_i] = {                                                \
+               .fmt = {                                        \
+                       .header = hpp__header,                  \
+                       .width  = hpp__width,                   \
+                       .entry  = hpp__entry_ ## _entry,        \
+                       .color  = hpp__color_ ## _color,        \
+               },                                              \
+               .idx = _i,                                      \
+       }
+
+#define FMT_GLOBAL(_i)  FMT(_i, global, global)
+#define FMT_BASELINE(_i) FMT(_i, global, baseline)
+
+static struct diff_hpp_fmt diff_fmt[] = {
+       FMT_BASELINE(PERF_HPP_DIFF__BASELINE),
+       FMT_GLOBAL(PERF_HPP_DIFF__PERIOD),
+       FMT_GLOBAL(PERF_HPP_DIFF__PERIOD_BASELINE),
+       FMT_GLOBAL(PERF_HPP_DIFF__DELTA),
+       FMT_GLOBAL(PERF_HPP_DIFF__RATIO),
+       FMT_GLOBAL(PERF_HPP_DIFF__WEIGHTED_DIFF),
+       FMT_GLOBAL(PERF_HPP_DIFF__FORMULA),
+};
+
+static void init_header(struct diff_hpp_fmt *dfmt)
+{
+#define MAX_HEADER_NAME 100
+       char buf_indent[MAX_HEADER_NAME];
+       char buf[MAX_HEADER_NAME];
+       const char *header = NULL;
+       int width = 0;
+
+       BUG_ON(dfmt->idx >= PERF_HPP_DIFF__MAX_INDEX);
+       header = columns[dfmt->idx].name;
+       width  = columns[dfmt->idx].width;
+
+       /* Only our defined HPP fmts should appear here. */
+       BUG_ON(!header);
+
+#define NAME (data__files_cnt > 2 ? buf : header)
+       dfmt->header_width = width;
+       width = (int) strlen(NAME);
+       if (dfmt->header_width < width)
+               dfmt->header_width = width;
+
+       scnprintf(buf_indent, MAX_HEADER_NAME, "%*s",
+                 dfmt->header_width, NAME);
+
+       dfmt->header = strdup(buf_indent);
+#undef MAX_HEADER_NAME
+#undef NAME
+}
+
+static void column_enable(unsigned col)
+{
+       struct diff_hpp_fmt *dfmt;
+
+       BUG_ON(col >= PERF_HPP_DIFF__MAX_INDEX);
+       dfmt = &diff_fmt[col];
+       init_header(dfmt);
+       perf_hpp__column_register(&dfmt->fmt);
+}
+
+static void ui_init(void)
+{
+       /*
+        * Display baseline/delta/ratio/
+        * formula/periods columns.
+        */
+       column_enable(PERF_HPP_DIFF__BASELINE);
+       column_enable(compute_2_hpp[compute]);
 
        if (show_formula)
-               perf_hpp__column_enable(PERF_HPP__FORMULA);
+               column_enable(PERF_HPP_DIFF__FORMULA);
 
        if (show_period) {
-               perf_hpp__column_enable(PERF_HPP__PERIOD);
-               perf_hpp__column_enable(PERF_HPP__PERIOD_BASELINE);
+               column_enable(PERF_HPP_DIFF__PERIOD);
+               column_enable(PERF_HPP_DIFF__PERIOD_BASELINE);
        }
 }
 
This page took 0.030796 seconds and 5 git commands to generate.