From: Andi Kleen <[email protected]>

To process metrics, perf script needs to know the scaling
factors reported by sysfs for events. Save the scaling factors
in the perf.data metadata in a new SCALE header.

Signed-off-by: Andi Kleen <[email protected]>
---
 tools/perf/Documentation/perf.data-file-format.txt |  8 +++
 tools/perf/util/header.c                           | 60 ++++++++++++++++++++++
 tools/perf/util/header.h                           |  1 +
 3 files changed, 69 insertions(+)

diff --git a/tools/perf/Documentation/perf.data-file-format.txt 
b/tools/perf/Documentation/perf.data-file-format.txt
index 15e8b48077ba..dc91d0578f46 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -261,6 +261,14 @@ struct {
        struct perf_header_string map;
 }[number_of_cache_levels];
 
+       HEADER_SCALE = 21,
+
+Save scaling factor of events. One entry for each event in the same
+order as other events in the header.
+
+       u32     nr;
+       double  scale[nr];
+
        other bits are reserved and should ignored for now
        HEADER_FEAT_BITS        = 256,
 
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 605bbd5404fb..4f1d23cfb9b0 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -2147,6 +2147,65 @@ static int process_cache(struct feat_fd *ff, void *data 
__maybe_unused)
        return -1;
 }
 
+static int write_scale(struct feat_fd *ff, struct perf_evlist *evlist)
+{
+       u32 num;
+       struct perf_evsel *evsel;
+
+       num = 0;
+       evlist__for_each_entry (evlist, evsel)
+               num++;
+
+       if (do_write(ff, &num, sizeof num) < 0)
+               return -1;
+       evlist__for_each_entry (evlist, evsel) {
+               if (do_write(ff, &evsel->scale, sizeof(double)) < 0)
+                       return -1;
+       }
+       return 0;
+}
+
+static void print_scale(struct feat_fd *ff, FILE *fp)
+{
+       struct perf_session *session;
+       struct perf_evsel *evsel;
+       int num = 0;
+
+       session = container_of(ff->ph, struct perf_session, header);
+
+       num = 0;
+       evlist__for_each_entry(session->evlist, evsel) {
+               fprintf(fp, "# event %d %s scale %f\n",
+                       num++,
+                       evsel->name,
+                       evsel->scale);
+       }
+}
+
+static int process_scale(struct feat_fd *ff, void *data __maybe_unused)
+{
+       u32 cnt;
+       struct perf_evsel *evsel;
+       struct perf_session *session;
+
+       session = container_of(ff->ph, struct perf_session, header);
+       if (do_read_u32(ff, &cnt))
+               return -1;
+       evlist__for_each_entry(session->evlist, evsel) {
+               if (__do_read(ff, &evsel->scale, sizeof(double)))
+                       return -1;
+               if (ff->ph->needs_swap)
+                       mem_bswap_64(&evsel->scale, sizeof(double));
+               if (--cnt <= 0)
+                       break;
+       }
+       if (cnt) {
+               pr_debug("missing scale descriptors\n");
+               return 1;
+       }
+       return 0;
+}
+
 struct feature_ops {
        int (*write)(struct feat_fd *ff, struct perf_evlist *evlist);
        void (*print)(struct feat_fd *ff, FILE *fp);
@@ -2204,6 +2263,7 @@ static const struct feature_ops 
feat_ops[HEADER_LAST_FEATURE] = {
        FEAT_OPN(AUXTRACE,      auxtrace,       false),
        FEAT_OPN(STAT,          stat,           false),
        FEAT_OPN(CACHE,         cache,          true),
+       FEAT_OPN(SCALE,         scale,          true),
 };
 
 struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f7a16ee527b8..d13d9520191f 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -33,6 +33,7 @@ enum {
        HEADER_AUXTRACE,
        HEADER_STAT,
        HEADER_CACHE,
+       HEADER_SCALE,
        HEADER_LAST_FEATURE,
        HEADER_FEAT_BITS        = 256,
 };
-- 
2.13.6

Reply via email to