Use reftime event for initial correlation of perf_clock to
time-of-day. Add timekeeping trace events to event list to
capture jumps in time-of-day.

Signed-off-by: David Ahern <[email protected]>
---
 tools/perf/Documentation/perf-record.txt |    3 +
 tools/perf/builtin-record.c              |  102 +++++++++++++++++++++++++++++-
 2 files changed, 104 insertions(+), 1 deletions(-)

diff --git a/tools/perf/Documentation/perf-record.txt 
b/tools/perf/Documentation/perf-record.txt
index 5a520f8..e4c87ba 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -148,6 +148,9 @@ an empty cgroup (monitor all the time) using, e.g., -G 
foo,,bar. Cgroups must ha
 corresponding events, i.e., they always refer to events defined earlier on the 
command
 line.
 
+--tod::
+Collect data for displaying time-of-day strings when printing events.
+
 SEE ALSO
 --------
 linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 8e2c857..4f8d5f2 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -32,6 +32,9 @@
 
 #define FD(e, x, y) (*(int *)xyarray__entry(e->fd, x, y))
 
+#define TRACE_TOD_SUBSYSTEM      "timekeeping"
+#define TRACE_TOD_SUBSYSTEM_LEN  11
+
 enum write_mode_t {
        WRITE_FORCE,
        WRITE_APPEND
@@ -65,6 +68,8 @@ static bool                   sample_address                  
=  false;
 static bool                    sample_time                     =  false;
 static bool                    no_buildid                      =  false;
 static bool                    no_buildid_cache                =  false;
+static bool                    want_tod                        =  false;
+static u64                     tod_sample_type;
 static struct perf_evlist      *evsel_list;
 
 static long                    samples                         =      0;
@@ -215,6 +220,9 @@ static void config_attr(struct perf_evsel *evsel, struct 
perf_evlist *evlist)
                attr->sample_type       |= PERF_SAMPLE_CPU;
        }
 
+       if (want_tod)
+               attr->sample_type       |= tod_sample_type;
+
        if (nodelay) {
                attr->watermark = 0;
                attr->wakeup_events = 1;
@@ -248,6 +256,86 @@ static bool perf_evlist__equal(struct perf_evlist *evlist,
        return true;
 }
 
+static int perf_event__synthesize_reftime(perf_event__handler_t process)
+{
+       union perf_event ev;
+       struct timespec tp;
+
+       memset(&ev, 0, sizeof(ev));
+
+       if (gettimeofday(&ev.reftime.tv, NULL) != 0) {
+               error("gettimeofday failed.\n");
+               return -1;
+       }
+       if (clock_gettime(CLOCK_MONOTONIC, &tp) != 0) {
+               error("clock_gettime(CLOCK_MONOTONIC) failed.\n");
+               return -1;
+       }
+       ev.reftime.nsec = (u64) tp.tv_sec * NSEC_PER_SEC + (u64) tp.tv_nsec;
+
+       ev.header.type = PERF_RECORD_REFTIME;
+       ev.header.size = sizeof(ev.reftime);
+
+       return process(&ev, NULL, session);
+}
+
+static int add_timeofday_events(void)
+{
+       int rc, i, len;
+       struct perf_event_attr attr;
+       struct perf_evsel *evsel;
+
+       /* events that modify xtime */
+       const char *tod_events[] = {"settimeofday",
+                                   "timekeeping_inject_offset",
+                                   "timekeeping_inject_sleeptime",
+                                   NULL};
+
+       i = 0;
+       rc = -1;
+       while (tod_events[i]) {
+               memset(&attr, 0, sizeof(attr));
+               len = strlen(tod_events[i]);
+
+               if (parse_single_tracepoint_event(TRACE_TOD_SUBSYSTEM,
+                       tod_events[i], len, &attr, NULL) == EVT_FAILED) {
+                       error("Failed to parse event %s\n", tod_events[i]);
+                       goto out;
+               }
+
+               evsel = perf_evsel__new(&attr, evsel_list->nr_entries);
+               if (evsel == NULL)
+                       return -1;
+
+               perf_evlist__add(evsel_list, evsel);
+
+               /* +2 for ':' delimiter and string terminator */
+               evsel->name = calloc(TRACE_TOD_SUBSYSTEM_LEN + len + 2, 1);
+               if (!evsel->name)
+                       return -1;
+
+               sprintf(evsel->name, "timekeeping:%s", tod_events[i]);
+
+               tod_sample_type |= attr.sample_type;
+
+               ++i;
+       }
+
+       /*
+        * right now sample_type for all samples needs to be the same.
+        * tracepoints are collected at sample period 1 and hence do not
+        * request the period with the sample. However, default for record
+        * is cycles at a frequency. So, until this sample_type mess is
+        * fixed....
+        */
+       if (freq)
+               tod_sample_type |= PERF_SAMPLE_PERIOD;
+
+       rc = 0;
+out:
+       return rc;
+}
+
 static void open_counters(struct perf_evlist *evlist)
 {
        struct perf_evsel *pos;
@@ -289,7 +377,8 @@ try_again:
                                 * Old kernel, no attr->sample_id_type_all field
                                 */
                                sample_id_all_avail = false;
-                               if (!sample_time && !raw_samples && 
!time_needed)
+                               if (!sample_time && !raw_samples &&
+                                               !time_needed && !want_tod)
                                        attr->sample_type &= ~PERF_SAMPLE_TIME;
 
                                goto retry_sample_id;
@@ -629,6 +718,11 @@ static int __cmd_record(int argc, const char **argv)
                }
        }
 
+       if (want_tod &&
+           (perf_event__synthesize_reftime(process_synthesized_event) != 0))
+               error("Failed to create reftime event. "
+                     "Cannot generate wall-clock timestamps\n");
+
        machine = perf_session__find_host_machine(session);
        if (!machine) {
                pr_err("Couldn't find native kernel information.\n");
@@ -787,6 +881,8 @@ const struct option record_options[] = {
        OPT_CALLBACK('G', "cgroup", &evsel_list, "name",
                     "monitor event in cgroup name only",
                     parse_cgroups),
+       OPT_BOOLEAN(0, "tod", &want_tod,
+                   "Collect data for time-of-day strings"),
        OPT_END()
 };
 
@@ -842,6 +938,10 @@ int cmd_record(int argc, const char **argv, const char 
*prefix __used)
                goto out_symbol_exit;
        }
 
+       if (want_tod && (add_timeofday_events() != 0))
+               error("Failed to add timekeeping events to event list.\n"
+                     "Cannot generate wall-clock timestamps\n");
+
        if (target_pid != -1)
                target_tid = target_pid;
 
-- 
1.7.5.2

--
To unsubscribe from this list: send the line "unsubscribe linux-perf-users" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to