Skip to content

Commit d1e325c

Browse files
olsajiriacmel
authored andcommitted
perf header: Store clock references for -k/--clockid option
Add a new CLOCK_DATA feature that stores reference times when -k/--clockid option is specified. It contains the clock id and its reference time together with wall clock time taken at the 'same time', both values are in nanoseconds. The format of data is as below: struct { u32 version; /* version = 1 */ u32 clockid; u64 wall_clock_ns; u64 clockid_time_ns; }; This clock reference times will be used in following changes to display wall clock for perf events. It's available only for recording with clockid specified, because it's the only case where we can get reference time to wallclock time. It's can't do that with perf clock yet. Committer testing: $ perf record -h -k Usage: perf record [<options>] [<command>] or: perf record [<options>] -- <command> [<options>] -k, --clockid <clockid> clockid to use for events, see clock_gettime() $ perf record -k monotonic sleep 1 [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.017 MB perf.data (8 samples) ] $ perf report --header-only | grep clockid -A1 # event : name = cycles:u, , id = { 88815, 88816, 88817, 88818, 88819, 88820, 88821, 88822 }, size = 120, { sample_period, sample_freq } = 4000, sample_type = IP|TID|TIME|PERIOD, read_format = ID, disabled = 1, inherit = 1, exclude_kernel = 1, mmap = 1, comm = 1, freq = 1, enable_on_exec = 1, task = 1, precise_ip = 3, sample_id_all = 1, exclude_guest = 1, mmap2 = 1, comm_exec = 1, use_clockid = 1, ksymbol = 1, bpf_event = 1, clockid = 1 # CPU_TOPOLOGY info available, use -I to display -- # clockid frequency: 1000 MHz # cpu pmu capabilities: branches=32, max_precise=3, pmu_name=skylake # clockid: monotonic (1) # reference time: 2020-08-06 09:40:21.619290 = 1596717621.619290 (TOD) = 21931.077673635 (monotonic) $ Original-patch-by: David Ahern <[email protected]> Signed-off-by: Jiri Olsa <[email protected]> Tested-by: Arnaldo Carvalho de Melo <[email protected]> Cc: Alexander Shishkin <[email protected]> Cc: Andi Kleen <[email protected]> Cc: David Ahern <[email protected]> Cc: Geneviève Bastien <[email protected]> Cc: Ian Rogers <[email protected]> Cc: Jeremie Galarneau <[email protected]> Cc: Michael Petlan <[email protected]> Cc: Namhyung Kim <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Wang Nan <[email protected]> Link: http://lore.kernel.org/lkml/[email protected] Signed-off-by: Arnaldo Carvalho de Melo <[email protected]>
1 parent cc3365b commit d1e325c

File tree

5 files changed

+180
-0
lines changed

5 files changed

+180
-0
lines changed

tools/perf/Documentation/perf.data-file-format.txt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -389,6 +389,19 @@ struct {
389389
Example:
390390
cpu pmu capabilities: branches=32, max_precise=3, pmu_name=icelake
391391

392+
HEADER_CLOCK_DATA = 29,
393+
394+
Contains clock id and its reference time together with wall clock
395+
time taken at the 'same time', both values are in nanoseconds.
396+
The format of data is as below.
397+
398+
struct {
399+
u32 version; /* version = 1 */
400+
u32 clockid;
401+
u64 wall_clock_ns;
402+
u64 clockid_time_ns;
403+
};
404+
392405
other bits are reserved and should ignored for now
393406
HEADER_FEAT_BITS = 256,
394407

tools/perf/builtin-record.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
#include <linux/time64.h>
7272
#include <linux/zalloc.h>
7373
#include <linux/bitmap.h>
74+
#include <sys/time.h>
7475

7576
struct switch_output {
7677
bool enabled;
@@ -1204,6 +1205,9 @@ static void record__init_features(struct record *rec)
12041205
if (!(rec->opts.use_clockid && rec->opts.clockid_res_ns))
12051206
perf_header__clear_feat(&session->header, HEADER_CLOCKID);
12061207

1208+
if (!rec->opts.use_clockid)
1209+
perf_header__clear_feat(&session->header, HEADER_CLOCK_DATA);
1210+
12071211
perf_header__clear_feat(&session->header, HEADER_DIR_FORMAT);
12081212
if (!record__comp_enabled(rec))
12091213
perf_header__clear_feat(&session->header, HEADER_COMPRESSED);
@@ -1552,6 +1556,40 @@ static int record__setup_sb_evlist(struct record *rec)
15521556
return 0;
15531557
}
15541558

1559+
static int record__init_clock(struct record *rec)
1560+
{
1561+
struct perf_session *session = rec->session;
1562+
struct timespec ref_clockid;
1563+
struct timeval ref_tod;
1564+
u64 ref;
1565+
1566+
if (!rec->opts.use_clockid)
1567+
return 0;
1568+
1569+
session->header.env.clock.clockid = rec->opts.clockid;
1570+
1571+
if (gettimeofday(&ref_tod, NULL) != 0) {
1572+
pr_err("gettimeofday failed, cannot set reference time.\n");
1573+
return -1;
1574+
}
1575+
1576+
if (clock_gettime(rec->opts.clockid, &ref_clockid)) {
1577+
pr_err("clock_gettime failed, cannot set reference time.\n");
1578+
return -1;
1579+
}
1580+
1581+
ref = (u64) ref_tod.tv_sec * NSEC_PER_SEC +
1582+
(u64) ref_tod.tv_usec * NSEC_PER_USEC;
1583+
1584+
session->header.env.clock.tod_ns = ref;
1585+
1586+
ref = (u64) ref_clockid.tv_sec * NSEC_PER_SEC +
1587+
(u64) ref_clockid.tv_nsec;
1588+
1589+
session->header.env.clock.clockid_ns = ref;
1590+
return 0;
1591+
}
1592+
15551593
static int __cmd_record(struct record *rec, int argc, const char **argv)
15561594
{
15571595
int err;
@@ -1632,6 +1670,9 @@ static int __cmd_record(struct record *rec, int argc, const char **argv)
16321670
return -1;
16331671
}
16341672

1673+
if (record__init_clock(rec))
1674+
return -1;
1675+
16351676
record__init_features(rec);
16361677

16371678
if (rec->opts.use_clockid && rec->opts.clockid_res_ns)

tools/perf/util/env.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,18 @@ struct perf_env {
100100
/* For fast cpu to numa node lookup via perf_env__numa_node */
101101
int *numa_map;
102102
int nr_numa_map;
103+
104+
/* For real clock time reference. */
105+
struct {
106+
u64 tod_ns;
107+
u64 clockid_ns;
108+
int clockid;
109+
/*
110+
* enabled is valid for report mode, and is true if above
111+
* values are set, it's set in process_clock_data
112+
*/
113+
bool enabled;
114+
} clock;
103115
};
104116

105117
enum perf_compress_type {

tools/perf/util/header.c

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
#include "util/util.h" // perf_exe()
4747
#include "cputopo.h"
4848
#include "bpf-event.h"
49+
#include "clockid.h"
4950

5051
#include <linux/ctype.h>
5152
#include <internal/lib.h>
@@ -895,6 +896,40 @@ static int write_clockid(struct feat_fd *ff,
895896
sizeof(ff->ph->env.clockid_res_ns));
896897
}
897898

899+
static int write_clock_data(struct feat_fd *ff,
900+
struct evlist *evlist __maybe_unused)
901+
{
902+
u64 *data64;
903+
u32 data32;
904+
int ret;
905+
906+
/* version */
907+
data32 = 1;
908+
909+
ret = do_write(ff, &data32, sizeof(data32));
910+
if (ret < 0)
911+
return ret;
912+
913+
/* clockid */
914+
data32 = ff->ph->env.clock.clockid;
915+
916+
ret = do_write(ff, &data32, sizeof(data32));
917+
if (ret < 0)
918+
return ret;
919+
920+
/* TOD ref time */
921+
data64 = &ff->ph->env.clock.tod_ns;
922+
923+
ret = do_write(ff, data64, sizeof(*data64));
924+
if (ret < 0)
925+
return ret;
926+
927+
/* clockid ref time */
928+
data64 = &ff->ph->env.clock.clockid_ns;
929+
930+
return do_write(ff, data64, sizeof(*data64));
931+
}
932+
898933
static int write_dir_format(struct feat_fd *ff,
899934
struct evlist *evlist __maybe_unused)
900935
{
@@ -1549,6 +1584,49 @@ static void print_clockid(struct feat_fd *ff, FILE *fp)
15491584
ff->ph->env.clockid_res_ns * 1000);
15501585
}
15511586

1587+
static void print_clock_data(struct feat_fd *ff, FILE *fp)
1588+
{
1589+
struct timespec clockid_ns;
1590+
char tstr[64], date[64];
1591+
struct timeval tod_ns;
1592+
clockid_t clockid;
1593+
struct tm ltime;
1594+
u64 ref;
1595+
1596+
if (!ff->ph->env.clock.enabled) {
1597+
fprintf(fp, "# reference time disabled\n");
1598+
return;
1599+
}
1600+
1601+
/* Compute TOD time. */
1602+
ref = ff->ph->env.clock.tod_ns;
1603+
tod_ns.tv_sec = ref / NSEC_PER_SEC;
1604+
ref -= tod_ns.tv_sec * NSEC_PER_SEC;
1605+
tod_ns.tv_usec = ref / NSEC_PER_USEC;
1606+
1607+
/* Compute clockid time. */
1608+
ref = ff->ph->env.clock.clockid_ns;
1609+
clockid_ns.tv_sec = ref / NSEC_PER_SEC;
1610+
ref -= clockid_ns.tv_sec * NSEC_PER_SEC;
1611+
clockid_ns.tv_nsec = ref;
1612+
1613+
clockid = ff->ph->env.clock.clockid;
1614+
1615+
if (localtime_r(&tod_ns.tv_sec, &ltime) == NULL)
1616+
snprintf(tstr, sizeof(tstr), "<error>");
1617+
else {
1618+
strftime(date, sizeof(date), "%F %T", &ltime);
1619+
scnprintf(tstr, sizeof(tstr), "%s.%06d",
1620+
date, (int) tod_ns.tv_usec);
1621+
}
1622+
1623+
fprintf(fp, "# clockid: %s (%u)\n", clockid_name(clockid), clockid);
1624+
fprintf(fp, "# reference time: %s = %ld.%06d (TOD) = %ld.%09ld (%s)\n",
1625+
tstr, tod_ns.tv_sec, (int) tod_ns.tv_usec,
1626+
clockid_ns.tv_sec, clockid_ns.tv_nsec,
1627+
clockid_name(clockid));
1628+
}
1629+
15521630
static void print_dir_format(struct feat_fd *ff, FILE *fp)
15531631
{
15541632
struct perf_session *session;
@@ -2738,6 +2816,40 @@ static int process_clockid(struct feat_fd *ff,
27382816
return 0;
27392817
}
27402818

2819+
static int process_clock_data(struct feat_fd *ff,
2820+
void *_data __maybe_unused)
2821+
{
2822+
u32 data32;
2823+
u64 data64;
2824+
2825+
/* version */
2826+
if (do_read_u32(ff, &data32))
2827+
return -1;
2828+
2829+
if (data32 != 1)
2830+
return -1;
2831+
2832+
/* clockid */
2833+
if (do_read_u32(ff, &data32))
2834+
return -1;
2835+
2836+
ff->ph->env.clock.clockid = data32;
2837+
2838+
/* TOD ref time */
2839+
if (do_read_u64(ff, &data64))
2840+
return -1;
2841+
2842+
ff->ph->env.clock.tod_ns = data64;
2843+
2844+
/* clockid ref time */
2845+
if (do_read_u64(ff, &data64))
2846+
return -1;
2847+
2848+
ff->ph->env.clock.clockid_ns = data64;
2849+
ff->ph->env.clock.enabled = true;
2850+
return 0;
2851+
}
2852+
27412853
static int process_dir_format(struct feat_fd *ff,
27422854
void *_data __maybe_unused)
27432855
{
@@ -3008,6 +3120,7 @@ const struct perf_header_feature_ops feat_ops[HEADER_LAST_FEATURE] = {
30083120
FEAT_OPR(BPF_BTF, bpf_btf, false),
30093121
FEAT_OPR(COMPRESSED, compressed, false),
30103122
FEAT_OPR(CPU_PMU_CAPS, cpu_pmu_caps, false),
3123+
FEAT_OPR(CLOCK_DATA, clock_data, false),
30113124
};
30123125

30133126
struct header_print_data {

tools/perf/util/header.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ enum {
4444
HEADER_BPF_BTF,
4545
HEADER_COMPRESSED,
4646
HEADER_CPU_PMU_CAPS,
47+
HEADER_CLOCK_DATA,
4748
HEADER_LAST_FEATURE,
4849
HEADER_FEAT_BITS = 256,
4950
};

0 commit comments

Comments
 (0)