[PATCH v2 1/6] perf header: Record first sample time and last sample time in perf file header

From: Jin Yao
Date: Mon Sep 25 2017 - 23:02:17 EST


perf report/script/... have a --time option to limit the time range
of output. That's very useful to slice large traces, e.g. when processing
the output of perf script for some analysis.

But right now --time only supports absolute time. Also there is no fast
way to get the start/end times of a given trace except for looking at it.
This makes it hard to e.g. only decode the first half of the trace, which
is useful for parallelization of scripts

Another problem is that perf records are variable size and there is no
synchronization mechanism. So the only way to find the last sample reliably
would be to walk all samples. But we want to avoid that in perf report/...
because it is already quite expensive. That is why storing the first sample
time and last sample time in perf record is better.

This patch creates a new header feature type HEADER_SAMPLE_TIME and related
ops. Save the first sample time and the last sample time to the feature
section in perf file header.

Signed-off-by: Jin Yao <yao.jin@xxxxxxxxxxxxxxx>
---
tools/perf/Documentation/perf.data-file-format.txt | 4 ++
tools/perf/util/evlist.h | 2 +
tools/perf/util/header.c | 49 ++++++++++++++++++++++
tools/perf/util/header.h | 1 +
tools/perf/util/session.h | 2 +
5 files changed, 58 insertions(+)

diff --git a/tools/perf/Documentation/perf.data-file-format.txt b/tools/perf/Documentation/perf.data-file-format.txt
index e90c59c..d5e3043 100644
--- a/tools/perf/Documentation/perf.data-file-format.txt
+++ b/tools/perf/Documentation/perf.data-file-format.txt
@@ -238,6 +238,10 @@ struct auxtrace_index {
struct auxtrace_index_entry entries[PERF_AUXTRACE_INDEX_ENTRY_COUNT];
};

+ HEADER_SAMPLE_TIME = 21,
+
+Two uint64_t for the time of first sample and the time of last sample.
+
other bits are reserved and should ignored for now
HEADER_FEAT_BITS = 256,

diff --git a/tools/perf/util/evlist.h b/tools/perf/util/evlist.h
index b1c14f1..9ccc2fb 100644
--- a/tools/perf/util/evlist.h
+++ b/tools/perf/util/evlist.h
@@ -99,6 +99,8 @@ struct perf_evlist {
struct perf_evsel *selected;
struct events_stats stats;
struct perf_env *env;
+ u64 first_sample_time;
+ u64 last_sample_time;
};

struct perf_evsel_str_handler {
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 605bbd5..20b5ef9 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -1181,6 +1181,20 @@ static int write_stat(struct feat_fd *ff __maybe_unused,
return 0;
}

+static int write_sample_time(struct feat_fd *ff,
+ struct perf_evlist *evlist)
+{
+ int ret;
+
+ ret = do_write(ff, &evlist->first_sample_time,
+ sizeof(evlist->first_sample_time));
+ if (ret < 0)
+ return ret;
+
+ return do_write(ff, &evlist->last_sample_time,
+ sizeof(evlist->last_sample_time));
+}
+
static void print_hostname(struct feat_fd *ff, FILE *fp)
{
fprintf(fp, "# hostname : %s\n", ff->ph->env.hostname);
@@ -1506,6 +1520,19 @@ static void print_group_desc(struct feat_fd *ff, FILE *fp)
}
}

+static void print_sample_time(struct feat_fd *ff, FILE *fp)
+{
+ struct perf_session *session;
+
+ session = container_of(ff->ph, struct perf_session, header);
+
+ fprintf(fp, "# time of first sample : %" PRIu64 "\n",
+ session->first_sample_time);
+
+ fprintf(fp, "# time of last sample : %" PRIu64 "\n",
+ session->last_sample_time);
+}
+
static int __event_process_build_id(struct build_id_event *bev,
char *filename,
struct perf_session *session)
@@ -2147,6 +2174,27 @@ static int process_cache(struct feat_fd *ff, void *data __maybe_unused)
return -1;
}

+static int process_sample_time(struct feat_fd *ff, void *data __maybe_unused)
+{
+ struct perf_session *session;
+ u64 first_sample_time, last_sample_time;
+ int ret;
+
+ session = container_of(ff->ph, struct perf_session, header);
+
+ ret = do_read_u64(ff, &first_sample_time);
+ if (ret)
+ return -1;
+
+ ret = do_read_u64(ff, &last_sample_time);
+ if (ret)
+ return -1;
+
+ session->first_sample_time = first_sample_time;
+ session->last_sample_time = last_sample_time;
+ 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 +2252,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_OPR(SAMPLE_TIME, sample_time, false),
};

struct header_print_data {
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index f7a16ee..1911831 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_SAMPLE_TIME,
HEADER_LAST_FEATURE,
HEADER_FEAT_BITS = 256,
};
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index 47b5e7d..d118885 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -34,6 +34,8 @@ struct perf_session {
struct ordered_events ordered_events;
struct perf_data_file *file;
struct perf_tool *tool;
+ u64 first_sample_time;
+ u64 last_sample_time;
};

struct perf_tool;
--
2.7.4