Skip to content

Commit 1b86abc

Browse files
Peter Zijlstrawilldeacon
authored andcommitted
sched_clock: Expose struct clock_read_data
In order to support perf_event_mmap_page::cap_time features, an architecture needs, aside from a userspace readable counter register, to expose the exact clock data so that userspace can convert the counter register into a correct timestamp. Provide struct clock_read_data and two (seqcount) helpers so that architectures (arm64 in specific) can expose the numbers to userspace. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Signed-off-by: Leo Yan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent 539707c commit 1b86abc

File tree

2 files changed

+41
-28
lines changed

2 files changed

+41
-28
lines changed

include/linux/sched_clock.h

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,34 @@
66
#define LINUX_SCHED_CLOCK
77

88
#ifdef CONFIG_GENERIC_SCHED_CLOCK
9+
/**
10+
* struct clock_read_data - data required to read from sched_clock()
11+
*
12+
* @epoch_ns: sched_clock() value at last update
13+
* @epoch_cyc: Clock cycle value at last update.
14+
* @sched_clock_mask: Bitmask for two's complement subtraction of non 64bit
15+
* clocks.
16+
* @read_sched_clock: Current clock source (or dummy source when suspended).
17+
* @mult: Multipler for scaled math conversion.
18+
* @shift: Shift value for scaled math conversion.
19+
*
20+
* Care must be taken when updating this structure; it is read by
21+
* some very hot code paths. It occupies <=40 bytes and, when combined
22+
* with the seqcount used to synchronize access, comfortably fits into
23+
* a 64 byte cache line.
24+
*/
25+
struct clock_read_data {
26+
u64 epoch_ns;
27+
u64 epoch_cyc;
28+
u64 sched_clock_mask;
29+
u64 (*read_sched_clock)(void);
30+
u32 mult;
31+
u32 shift;
32+
};
33+
34+
extern struct clock_read_data *sched_clock_read_begin(unsigned int *seq);
35+
extern int sched_clock_read_retry(unsigned int seq);
36+
937
extern void generic_sched_clock_init(void);
1038

1139
extern void sched_clock_register(u64 (*read)(void), int bits,

kernel/time/sched_clock.c

Lines changed: 13 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,6 @@
1919

2020
#include "timekeeping.h"
2121

22-
/**
23-
* struct clock_read_data - data required to read from sched_clock()
24-
*
25-
* @epoch_ns: sched_clock() value at last update
26-
* @epoch_cyc: Clock cycle value at last update.
27-
* @sched_clock_mask: Bitmask for two's complement subtraction of non 64bit
28-
* clocks.
29-
* @read_sched_clock: Current clock source (or dummy source when suspended).
30-
* @mult: Multipler for scaled math conversion.
31-
* @shift: Shift value for scaled math conversion.
32-
*
33-
* Care must be taken when updating this structure; it is read by
34-
* some very hot code paths. It occupies <=40 bytes and, when combined
35-
* with the seqcount used to synchronize access, comfortably fits into
36-
* a 64 byte cache line.
37-
*/
38-
struct clock_read_data {
39-
u64 epoch_ns;
40-
u64 epoch_cyc;
41-
u64 sched_clock_mask;
42-
u64 (*read_sched_clock)(void);
43-
u32 mult;
44-
u32 shift;
45-
};
46-
4722
/**
4823
* struct clock_data - all data needed for sched_clock() (including
4924
* registration of a new clock source)
@@ -93,20 +68,30 @@ static inline u64 notrace cyc_to_ns(u64 cyc, u32 mult, u32 shift)
9368
return (cyc * mult) >> shift;
9469
}
9570

71+
struct clock_read_data *sched_clock_read_begin(unsigned int *seq)
72+
{
73+
*seq = raw_read_seqcount(&cd.seq);
74+
return cd.read_data + (*seq & 1);
75+
}
76+
77+
int sched_clock_read_retry(unsigned int seq)
78+
{
79+
return read_seqcount_retry(&cd.seq, seq);
80+
}
81+
9682
unsigned long long notrace sched_clock(void)
9783
{
9884
u64 cyc, res;
9985
unsigned int seq;
10086
struct clock_read_data *rd;
10187

10288
do {
103-
seq = raw_read_seqcount(&cd.seq);
104-
rd = cd.read_data + (seq & 1);
89+
rd = sched_clock_read_begin(&seq);
10590

10691
cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
10792
rd->sched_clock_mask;
10893
res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
109-
} while (read_seqcount_retry(&cd.seq, seq));
94+
} while (sched_clock_read_retry(seq));
11095

11196
return res;
11297
}

0 commit comments

Comments
 (0)