1 // SPDX-License-Identifier: GPL-2.0
4 #include <linux/compiler.h>
5 #include <linux/perf_event.h>
6 #include <linux/stddef.h>
7 #include <linux/types.h>
9 #include <asm/barrier.h>
12 #include "synthetic-events.h"
16 u64
perf_time_to_tsc(u64 ns
, struct perf_tsc_conversion
*tc
)
20 t
= ns
- tc
->time_zero
;
21 quot
= t
/ tc
->time_mult
;
22 rem
= t
% tc
->time_mult
;
23 return (quot
<< tc
->time_shift
) +
24 (rem
<< tc
->time_shift
) / tc
->time_mult
;
27 u64
tsc_to_perf_time(u64 cyc
, struct perf_tsc_conversion
*tc
)
31 if (tc
->cap_user_time_short
)
32 cyc
= tc
->time_cycles
+
33 ((cyc
- tc
->time_cycles
) & tc
->time_mask
);
35 quot
= cyc
>> tc
->time_shift
;
36 rem
= cyc
& (((u64
)1 << tc
->time_shift
) - 1);
37 return tc
->time_zero
+ quot
* tc
->time_mult
+
38 ((rem
* tc
->time_mult
) >> tc
->time_shift
);
41 int perf_read_tsc_conversion(const struct perf_event_mmap_page
*pc
,
42 struct perf_tsc_conversion
*tc
)
50 tc
->time_mult
= pc
->time_mult
;
51 tc
->time_shift
= pc
->time_shift
;
52 tc
->time_zero
= pc
->time_zero
;
53 tc
->time_cycles
= pc
->time_cycles
;
54 tc
->time_mask
= pc
->time_mask
;
55 tc
->cap_user_time_zero
= pc
->cap_user_time_zero
;
56 tc
->cap_user_time_short
= pc
->cap_user_time_short
;
58 if (pc
->lock
== seq
&& !(seq
& 1))
61 pr_debug("failed to get perf_event_mmap_page lock\n");
66 if (!tc
->cap_user_time_zero
)
72 int perf_event__synth_time_conv(const struct perf_event_mmap_page
*pc
,
73 struct perf_tool
*tool
,
74 perf_event__handler_t process
,
75 struct machine
*machine
)
77 union perf_event event
= {
80 .type
= PERF_RECORD_TIME_CONV
,
81 .size
= sizeof(struct perf_record_time_conv
),
85 struct perf_tsc_conversion tc
;
90 err
= perf_read_tsc_conversion(pc
, &tc
);
91 if (err
== -EOPNOTSUPP
)
96 pr_debug2("Synthesizing TSC conversion information\n");
98 event
.time_conv
.time_mult
= tc
.time_mult
;
99 event
.time_conv
.time_shift
= tc
.time_shift
;
100 event
.time_conv
.time_zero
= tc
.time_zero
;
101 event
.time_conv
.time_cycles
= tc
.time_cycles
;
102 event
.time_conv
.time_mask
= tc
.time_mask
;
103 event
.time_conv
.cap_user_time_zero
= tc
.cap_user_time_zero
;
104 event
.time_conv
.cap_user_time_short
= tc
.cap_user_time_short
;
106 return process(tool
, &event
, NULL
, machine
);
109 u64 __weak
rdtsc(void)