1 // SPDX-License-Identifier: GPL-2.0
6 #include <linux/compiler.h>
7 #include <linux/perf_event.h>
8 #include <linux/stddef.h>
9 #include <linux/types.h>
11 #include <asm/barrier.h>
14 #include "synthetic-events.h"
18 u64
perf_time_to_tsc(u64 ns
, struct perf_tsc_conversion
*tc
)
22 t
= ns
- tc
->time_zero
;
23 quot
= t
/ tc
->time_mult
;
24 rem
= t
% tc
->time_mult
;
25 return (quot
<< tc
->time_shift
) +
26 (rem
<< tc
->time_shift
) / tc
->time_mult
;
29 u64
tsc_to_perf_time(u64 cyc
, struct perf_tsc_conversion
*tc
)
33 if (tc
->cap_user_time_short
)
34 cyc
= tc
->time_cycles
+
35 ((cyc
- tc
->time_cycles
) & tc
->time_mask
);
37 quot
= cyc
>> tc
->time_shift
;
38 rem
= cyc
& (((u64
)1 << tc
->time_shift
) - 1);
39 return tc
->time_zero
+ quot
* tc
->time_mult
+
40 ((rem
* tc
->time_mult
) >> tc
->time_shift
);
43 int perf_read_tsc_conversion(const struct perf_event_mmap_page
*pc
,
44 struct perf_tsc_conversion
*tc
)
52 tc
->time_mult
= pc
->time_mult
;
53 tc
->time_shift
= pc
->time_shift
;
54 tc
->time_zero
= pc
->time_zero
;
55 tc
->time_cycles
= pc
->time_cycles
;
56 tc
->time_mask
= pc
->time_mask
;
57 tc
->cap_user_time_zero
= pc
->cap_user_time_zero
;
58 tc
->cap_user_time_short
= pc
->cap_user_time_short
;
60 if (pc
->lock
== seq
&& !(seq
& 1))
63 pr_debug("failed to get perf_event_mmap_page lock\n");
68 if (!tc
->cap_user_time_zero
)
74 int perf_event__synth_time_conv(const struct perf_event_mmap_page
*pc
,
75 const struct perf_tool
*tool
,
76 perf_event__handler_t process
,
77 struct machine
*machine
)
79 union perf_event event
= {
82 .type
= PERF_RECORD_TIME_CONV
,
83 .size
= sizeof(struct perf_record_time_conv
),
87 struct perf_tsc_conversion tc
;
92 err
= perf_read_tsc_conversion(pc
, &tc
);
93 if (err
== -EOPNOTSUPP
)
98 pr_debug2("Synthesizing TSC conversion information\n");
100 event
.time_conv
.time_mult
= tc
.time_mult
;
101 event
.time_conv
.time_shift
= tc
.time_shift
;
102 event
.time_conv
.time_zero
= tc
.time_zero
;
103 event
.time_conv
.time_cycles
= tc
.time_cycles
;
104 event
.time_conv
.time_mask
= tc
.time_mask
;
105 event
.time_conv
.cap_user_time_zero
= tc
.cap_user_time_zero
;
106 event
.time_conv
.cap_user_time_short
= tc
.cap_user_time_short
;
108 return process(tool
, &event
, NULL
, machine
);
111 u64 __weak
rdtsc(void)
116 size_t perf_event__fprintf_time_conv(union perf_event
*event
, FILE *fp
)
118 struct perf_record_time_conv
*tc
= (struct perf_record_time_conv
*)event
;
121 ret
= fprintf(fp
, "\n... Time Shift %" PRI_lu64
"\n", tc
->time_shift
);
122 ret
+= fprintf(fp
, "... Time Multiplier %" PRI_lu64
"\n", tc
->time_mult
);
123 ret
+= fprintf(fp
, "... Time Zero %" PRI_lu64
"\n", tc
->time_zero
);
126 * The event TIME_CONV was extended for the fields from "time_cycles"
127 * when supported cap_user_time_short, for backward compatibility,
128 * prints the extended fields only if they are contained in the event.
130 if (event_contains(*tc
, time_cycles
)) {
131 ret
+= fprintf(fp
, "... Time Cycles %" PRI_lu64
"\n",
133 ret
+= fprintf(fp
, "... Time Mask %#" PRI_lx64
"\n",
135 ret
+= fprintf(fp
, "... Cap Time Zero %" PRId32
"\n",
136 tc
->cap_user_time_zero
);
137 ret
+= fprintf(fp
, "... Cap Time Short %" PRId32
"\n",
138 tc
->cap_user_time_short
);