xref: /linux-6.15/kernel/time/sched_clock.c (revision f66b0acf)
135728b82SThomas Gleixner // SPDX-License-Identifier: GPL-2.0
238ff87f7SStephen Boyd /*
358c5fc2bSThomas Gleixner  * Generic sched_clock() support, to extend low level hardware time
458c5fc2bSThomas Gleixner  * counters to full 64-bit ns values.
538ff87f7SStephen Boyd  */
638ff87f7SStephen Boyd #include <linux/clocksource.h>
738ff87f7SStephen Boyd #include <linux/init.h>
838ff87f7SStephen Boyd #include <linux/jiffies.h>
9a08ca5d1SStephen Boyd #include <linux/ktime.h>
1038ff87f7SStephen Boyd #include <linux/kernel.h>
1192067440SMaciej W. Rozycki #include <linux/math.h>
1238ff87f7SStephen Boyd #include <linux/moduleparam.h>
1338ff87f7SStephen Boyd #include <linux/sched.h>
14e6017571SIngo Molnar #include <linux/sched/clock.h>
1538ff87f7SStephen Boyd #include <linux/syscore_ops.h>
16a08ca5d1SStephen Boyd #include <linux/hrtimer.h>
1738ff87f7SStephen Boyd #include <linux/sched_clock.h>
1885c3d2ddSStephen Boyd #include <linux/seqlock.h>
19e7e3ff1bSStephen Boyd #include <linux/bitops.h>
2038ff87f7SStephen Boyd 
21086ee46bSBen Dooks (Codethink) #include "timekeeping.h"
22086ee46bSBen Dooks (Codethink) 
23cf7c9c17SDaniel Thompson /**
2432fea568SIngo Molnar  * struct clock_data - all data needed for sched_clock() (including
25cf7c9c17SDaniel Thompson  *                     registration of a new clock source)
26cf7c9c17SDaniel Thompson  *
271809bfa4SDaniel Thompson  * @seq:		Sequence counter for protecting updates. The lowest
281809bfa4SDaniel Thompson  *			bit is the index for @read_data.
29cf7c9c17SDaniel Thompson  * @read_data:		Data required to read from sched_clock.
3032fea568SIngo Molnar  * @wrap_kt:		Duration for which clock can run before wrapping.
3132fea568SIngo Molnar  * @rate:		Tick rate of the registered clock.
3232fea568SIngo Molnar  * @actual_read_sched_clock: Registered hardware level clock read function.
33cf7c9c17SDaniel Thompson  *
34cf7c9c17SDaniel Thompson  * The ordering of this structure has been chosen to optimize cache
3532fea568SIngo Molnar  * performance. In particular 'seq' and 'read_data[0]' (combined) should fit
3632fea568SIngo Molnar  * into a single 64-byte cache line.
37cf7c9c17SDaniel Thompson  */
38cf7c9c17SDaniel Thompson struct clock_data {
39a690ed07SAhmed S. Darwish 	seqcount_latch_t	seq;
401809bfa4SDaniel Thompson 	struct clock_read_data	read_data[2];
41cf7c9c17SDaniel Thompson 	ktime_t			wrap_kt;
42cf7c9c17SDaniel Thompson 	unsigned long		rate;
4332fea568SIngo Molnar 
4413dbeb38SDaniel Thompson 	u64 (*actual_read_sched_clock)(void);
45cf7c9c17SDaniel Thompson };
46cf7c9c17SDaniel Thompson 
47a08ca5d1SStephen Boyd static struct hrtimer sched_clock_timer;
4838ff87f7SStephen Boyd static int irqtime = -1;
4938ff87f7SStephen Boyd 
5038ff87f7SStephen Boyd core_param(irqtime, irqtime, int, 0400);
5138ff87f7SStephen Boyd 
jiffy_sched_clock_read(void)52e7e3ff1bSStephen Boyd static u64 notrace jiffy_sched_clock_read(void)
5338ff87f7SStephen Boyd {
54e7e3ff1bSStephen Boyd 	/*
55e7e3ff1bSStephen Boyd 	 * We don't need to use get_jiffies_64 on 32-bit arches here
56e7e3ff1bSStephen Boyd 	 * because we register with BITS_PER_LONG
57e7e3ff1bSStephen Boyd 	 */
58e7e3ff1bSStephen Boyd 	return (u64)(jiffies - INITIAL_JIFFIES);
5938ff87f7SStephen Boyd }
6038ff87f7SStephen Boyd 
61cf7c9c17SDaniel Thompson static struct clock_data cd ____cacheline_aligned = {
621809bfa4SDaniel Thompson 	.read_data[0] = { .mult = NSEC_PER_SEC / HZ,
63cf7c9c17SDaniel Thompson 			  .read_sched_clock = jiffy_sched_clock_read, },
6413dbeb38SDaniel Thompson 	.actual_read_sched_clock = jiffy_sched_clock_read,
65cf7c9c17SDaniel Thompson };
6638ff87f7SStephen Boyd 
cyc_to_ns(u64 cyc,u32 mult,u32 shift)675949a68cSPeter Zijlstra static __always_inline u64 cyc_to_ns(u64 cyc, u32 mult, u32 shift)
6838ff87f7SStephen Boyd {
6938ff87f7SStephen Boyd 	return (cyc * mult) >> shift;
7038ff87f7SStephen Boyd }
7138ff87f7SStephen Boyd 
sched_clock_read_begin(unsigned int * seq)724cd2bb12SQuanyang Wang notrace struct clock_read_data *sched_clock_read_begin(unsigned int *seq)
731b86abc1SPeter Zijlstra {
7493190bc3SMarco Elver 	*seq = read_seqcount_latch(&cd.seq);
751b86abc1SPeter Zijlstra 	return cd.read_data + (*seq & 1);
761b86abc1SPeter Zijlstra }
771b86abc1SPeter Zijlstra 
sched_clock_read_retry(unsigned int seq)784cd2bb12SQuanyang Wang notrace int sched_clock_read_retry(unsigned int seq)
791b86abc1SPeter Zijlstra {
8093190bc3SMarco Elver 	return read_seqcount_latch_retry(&cd.seq, seq);
811b86abc1SPeter Zijlstra }
821b86abc1SPeter Zijlstra 
__sched_clock(void)838ab40fc2SMarco Elver static __always_inline unsigned long long __sched_clock(void)
8438ff87f7SStephen Boyd {
851809bfa4SDaniel Thompson 	struct clock_read_data *rd;
865949a68cSPeter Zijlstra 	unsigned int seq;
875949a68cSPeter Zijlstra 	u64 cyc, res;
88336ae118SStephen Boyd 
8938ff87f7SStephen Boyd 	do {
905949a68cSPeter Zijlstra 		seq = raw_read_seqcount_latch(&cd.seq);
915949a68cSPeter Zijlstra 		rd = cd.read_data + (seq & 1);
928710e914SDaniel Thompson 
9313dbeb38SDaniel Thompson 		cyc = (rd->read_sched_clock() - rd->epoch_cyc) &
9413dbeb38SDaniel Thompson 		      rd->sched_clock_mask;
9513dbeb38SDaniel Thompson 		res = rd->epoch_ns + cyc_to_ns(cyc, rd->mult, rd->shift);
965949a68cSPeter Zijlstra 	} while (raw_read_seqcount_latch_retry(&cd.seq, seq));
9738ff87f7SStephen Boyd 
988710e914SDaniel Thompson 	return res;
9938ff87f7SStephen Boyd }
10038ff87f7SStephen Boyd 
sched_clock_noinstr(void)1018ab40fc2SMarco Elver unsigned long long noinstr sched_clock_noinstr(void)
1028ab40fc2SMarco Elver {
1038ab40fc2SMarco Elver 	return __sched_clock();
1048ab40fc2SMarco Elver }
1058ab40fc2SMarco Elver 
sched_clock(void)1065949a68cSPeter Zijlstra unsigned long long notrace sched_clock(void)
1075949a68cSPeter Zijlstra {
1085949a68cSPeter Zijlstra 	unsigned long long ns;
1095949a68cSPeter Zijlstra 	preempt_disable_notrace();
1108ab40fc2SMarco Elver 	/*
1118ab40fc2SMarco Elver 	 * All of __sched_clock() is a seqcount_latch reader critical section,
1128ab40fc2SMarco Elver 	 * but relies on the raw helpers which are uninstrumented. For KCSAN,
1138ab40fc2SMarco Elver 	 * mark all accesses in __sched_clock() as atomic.
1148ab40fc2SMarco Elver 	 */
1158ab40fc2SMarco Elver 	kcsan_nestable_atomic_begin();
1168ab40fc2SMarco Elver 	ns = __sched_clock();
1178ab40fc2SMarco Elver 	kcsan_nestable_atomic_end();
1185949a68cSPeter Zijlstra 	preempt_enable_notrace();
1195949a68cSPeter Zijlstra 	return ns;
1205949a68cSPeter Zijlstra }
1215949a68cSPeter Zijlstra 
12238ff87f7SStephen Boyd /*
1231809bfa4SDaniel Thompson  * Updating the data required to read the clock.
1241809bfa4SDaniel Thompson  *
12532fea568SIngo Molnar  * sched_clock() will never observe mis-matched data even if called from
1261809bfa4SDaniel Thompson  * an NMI. We do this by maintaining an odd/even copy of the data and
12732fea568SIngo Molnar  * steering sched_clock() to one or the other using a sequence counter.
12832fea568SIngo Molnar  * In order to preserve the data cache profile of sched_clock() as much
1291809bfa4SDaniel Thompson  * as possible the system reverts back to the even copy when the update
1301809bfa4SDaniel Thompson  * completes; the odd copy is used *only* during an update.
1311809bfa4SDaniel Thompson  */
update_clock_read_data(struct clock_read_data * rd)1321809bfa4SDaniel Thompson static void update_clock_read_data(struct clock_read_data *rd)
1331809bfa4SDaniel Thompson {
1341809bfa4SDaniel Thompson 	/* steer readers towards the odd copy */
13593190bc3SMarco Elver 	write_seqcount_latch_begin(&cd.seq);
1361809bfa4SDaniel Thompson 
1371809bfa4SDaniel Thompson 	/* now its safe for us to update the normal (even) copy */
1381809bfa4SDaniel Thompson 	cd.read_data[0] = *rd;
1391809bfa4SDaniel Thompson 
1401809bfa4SDaniel Thompson 	/* switch readers back to the even copy */
14193190bc3SMarco Elver 	write_seqcount_latch(&cd.seq);
1421139c71dSMarco Elver 
1431139c71dSMarco Elver 	/* update the backup (odd) copy with the new data */
1441139c71dSMarco Elver 	cd.read_data[1] = *rd;
14593190bc3SMarco Elver 
14693190bc3SMarco Elver 	write_seqcount_latch_end(&cd.seq);
1471809bfa4SDaniel Thompson }
1481809bfa4SDaniel Thompson 
1491809bfa4SDaniel Thompson /*
15032fea568SIngo Molnar  * Atomically update the sched_clock() epoch.
15138ff87f7SStephen Boyd  */
update_sched_clock(void)1529fee69a8SDaniel Thompson static void update_sched_clock(void)
15338ff87f7SStephen Boyd {
154e7e3ff1bSStephen Boyd 	u64 cyc;
15538ff87f7SStephen Boyd 	u64 ns;
1561809bfa4SDaniel Thompson 	struct clock_read_data rd;
1571809bfa4SDaniel Thompson 
1581809bfa4SDaniel Thompson 	rd = cd.read_data[0];
15938ff87f7SStephen Boyd 
16013dbeb38SDaniel Thompson 	cyc = cd.actual_read_sched_clock();
16132fea568SIngo Molnar 	ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
16285c3d2ddSStephen Boyd 
1631809bfa4SDaniel Thompson 	rd.epoch_ns = ns;
1641809bfa4SDaniel Thompson 	rd.epoch_cyc = cyc;
1651809bfa4SDaniel Thompson 
1661809bfa4SDaniel Thompson 	update_clock_read_data(&rd);
16738ff87f7SStephen Boyd }
16838ff87f7SStephen Boyd 
sched_clock_poll(struct hrtimer * hrt)169a08ca5d1SStephen Boyd static enum hrtimer_restart sched_clock_poll(struct hrtimer *hrt)
17038ff87f7SStephen Boyd {
17138ff87f7SStephen Boyd 	update_sched_clock();
172a08ca5d1SStephen Boyd 	hrtimer_forward_now(hrt, cd.wrap_kt);
17332fea568SIngo Molnar 
174a08ca5d1SStephen Boyd 	return HRTIMER_RESTART;
17538ff87f7SStephen Boyd }
17638ff87f7SStephen Boyd 
17732fea568SIngo Molnar void __init
sched_clock_register(u64 (* read)(void),int bits,unsigned long rate)17832fea568SIngo Molnar sched_clock_register(u64 (*read)(void), int bits, unsigned long rate)
17938ff87f7SStephen Boyd {
1805ae8aabeSStephen Boyd 	u64 res, wrap, new_mask, new_epoch, cyc, ns;
1815ae8aabeSStephen Boyd 	u32 new_mult, new_shift;
18227077455SPaul Cercueil 	unsigned long r, flags;
18338ff87f7SStephen Boyd 	char r_unit;
1841809bfa4SDaniel Thompson 	struct clock_read_data rd;
18538ff87f7SStephen Boyd 
18638ff87f7SStephen Boyd 	if (cd.rate > rate)
18738ff87f7SStephen Boyd 		return;
18838ff87f7SStephen Boyd 
18927077455SPaul Cercueil 	/* Cannot register a sched_clock with interrupts on */
19027077455SPaul Cercueil 	local_irq_save(flags);
19138ff87f7SStephen Boyd 
19232fea568SIngo Molnar 	/* Calculate the mult/shift to convert counter ticks to ns. */
1935ae8aabeSStephen Boyd 	clocks_calc_mult_shift(&new_mult, &new_shift, rate, NSEC_PER_SEC, 3600);
1945ae8aabeSStephen Boyd 
1955ae8aabeSStephen Boyd 	new_mask = CLOCKSOURCE_MASK(bits);
1968710e914SDaniel Thompson 	cd.rate = rate;
1975ae8aabeSStephen Boyd 
19832fea568SIngo Molnar 	/* Calculate how many nanosecs until we risk wrapping */
199fb82fe2fSJohn Stultz 	wrap = clocks_calc_max_nsecs(new_mult, new_shift, 0, new_mask, NULL);
2008710e914SDaniel Thompson 	cd.wrap_kt = ns_to_ktime(wrap);
2015ae8aabeSStephen Boyd 
2021809bfa4SDaniel Thompson 	rd = cd.read_data[0];
2031809bfa4SDaniel Thompson 
20432fea568SIngo Molnar 	/* Update epoch for new counter and update 'epoch_ns' from old counter*/
2055ae8aabeSStephen Boyd 	new_epoch = read();
20613dbeb38SDaniel Thompson 	cyc = cd.actual_read_sched_clock();
20732fea568SIngo Molnar 	ns = rd.epoch_ns + cyc_to_ns((cyc - rd.epoch_cyc) & rd.sched_clock_mask, rd.mult, rd.shift);
20813dbeb38SDaniel Thompson 	cd.actual_read_sched_clock = read;
2095ae8aabeSStephen Boyd 
2101809bfa4SDaniel Thompson 	rd.read_sched_clock	= read;
2111809bfa4SDaniel Thompson 	rd.sched_clock_mask	= new_mask;
2121809bfa4SDaniel Thompson 	rd.mult			= new_mult;
2131809bfa4SDaniel Thompson 	rd.shift		= new_shift;
2141809bfa4SDaniel Thompson 	rd.epoch_cyc		= new_epoch;
2151809bfa4SDaniel Thompson 	rd.epoch_ns		= ns;
21632fea568SIngo Molnar 
2171809bfa4SDaniel Thompson 	update_clock_read_data(&rd);
21838ff87f7SStephen Boyd 
2191b8955bcSDavid Engraf 	if (sched_clock_timer.function != NULL) {
2201b8955bcSDavid Engraf 		/* update timeout for clock wrap */
2212c8bd588SAhmed S. Darwish 		hrtimer_start(&sched_clock_timer, cd.wrap_kt,
2222c8bd588SAhmed S. Darwish 			      HRTIMER_MODE_REL_HARD);
2231b8955bcSDavid Engraf 	}
2241b8955bcSDavid Engraf 
22538ff87f7SStephen Boyd 	r = rate;
22638ff87f7SStephen Boyd 	if (r >= 4000000) {
22792067440SMaciej W. Rozycki 		r = DIV_ROUND_CLOSEST(r, 1000000);
22838ff87f7SStephen Boyd 		r_unit = 'M';
229f4b62e1eSMaciej W. Rozycki 	} else if (r >= 4000) {
23092067440SMaciej W. Rozycki 		r = DIV_ROUND_CLOSEST(r, 1000);
23138ff87f7SStephen Boyd 		r_unit = 'k';
23232fea568SIngo Molnar 	} else {
23338ff87f7SStephen Boyd 		r_unit = ' ';
23432fea568SIngo Molnar 	}
23538ff87f7SStephen Boyd 
23632fea568SIngo Molnar 	/* Calculate the ns resolution of this counter */
2375ae8aabeSStephen Boyd 	res = cyc_to_ns(1ULL, new_mult, new_shift);
2385ae8aabeSStephen Boyd 
239a08ca5d1SStephen Boyd 	pr_info("sched_clock: %u bits at %lu%cHz, resolution %lluns, wraps every %lluns\n",
240a08ca5d1SStephen Boyd 		bits, r, r_unit, res, wrap);
24138ff87f7SStephen Boyd 
24232fea568SIngo Molnar 	/* Enable IRQ time accounting if we have a fast enough sched_clock() */
24338ff87f7SStephen Boyd 	if (irqtime > 0 || (irqtime == -1 && rate >= 1000000))
24438ff87f7SStephen Boyd 		enable_sched_clock_irqtime();
24538ff87f7SStephen Boyd 
24627077455SPaul Cercueil 	local_irq_restore(flags);
24727077455SPaul Cercueil 
248d75f773cSSakari Ailus 	pr_debug("Registered %pS as sched_clock source\n", read);
24938ff87f7SStephen Boyd }
25038ff87f7SStephen Boyd 
generic_sched_clock_init(void)2515d2a4e91SPavel Tatashin void __init generic_sched_clock_init(void)
25238ff87f7SStephen Boyd {
25338ff87f7SStephen Boyd 	/*
25432fea568SIngo Molnar 	 * If no sched_clock() function has been provided at that point,
255b0294f30SRandy Dunlap 	 * make it the final one.
25638ff87f7SStephen Boyd 	 */
25713dbeb38SDaniel Thompson 	if (cd.actual_read_sched_clock == jiffy_sched_clock_read)
258e7e3ff1bSStephen Boyd 		sched_clock_register(jiffy_sched_clock_read, BITS_PER_LONG, HZ);
25938ff87f7SStephen Boyd 
260a08ca5d1SStephen Boyd 	update_sched_clock();
261a08ca5d1SStephen Boyd 
262a08ca5d1SStephen Boyd 	/*
263a08ca5d1SStephen Boyd 	 * Start the timer to keep sched_clock() properly updated and
264a08ca5d1SStephen Boyd 	 * sets the initial epoch.
265a08ca5d1SStephen Boyd 	 */
266*f66b0acfSNam Cao 	hrtimer_setup(&sched_clock_timer, sched_clock_poll, CLOCK_MONOTONIC, HRTIMER_MODE_REL_HARD);
2672c8bd588SAhmed S. Darwish 	hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD);
26838ff87f7SStephen Boyd }
26938ff87f7SStephen Boyd 
27013dbeb38SDaniel Thompson /*
27113dbeb38SDaniel Thompson  * Clock read function for use when the clock is suspended.
27213dbeb38SDaniel Thompson  *
27313dbeb38SDaniel Thompson  * This function makes it appear to sched_clock() as if the clock
27413dbeb38SDaniel Thompson  * stopped counting at its last update.
2751809bfa4SDaniel Thompson  *
2761809bfa4SDaniel Thompson  * This function must only be called from the critical
2771809bfa4SDaniel Thompson  * section in sched_clock(). It relies on the read_seqcount_retry()
2781809bfa4SDaniel Thompson  * at the end of the critical section to be sure we observe the
27932fea568SIngo Molnar  * correct copy of 'epoch_cyc'.
28013dbeb38SDaniel Thompson  */
suspended_sched_clock_read(void)28113dbeb38SDaniel Thompson static u64 notrace suspended_sched_clock_read(void)
28213dbeb38SDaniel Thompson {
28393190bc3SMarco Elver 	unsigned int seq = read_seqcount_latch(&cd.seq);
2841809bfa4SDaniel Thompson 
2851809bfa4SDaniel Thompson 	return cd.read_data[seq & 1].epoch_cyc;
28613dbeb38SDaniel Thompson }
28713dbeb38SDaniel Thompson 
sched_clock_suspend(void)2883f2552f7SChang-An Chen int sched_clock_suspend(void)
28938ff87f7SStephen Boyd {
2901809bfa4SDaniel Thompson 	struct clock_read_data *rd = &cd.read_data[0];
291cf7c9c17SDaniel Thompson 
292f723aa18SStephen Boyd 	update_sched_clock();
293f723aa18SStephen Boyd 	hrtimer_cancel(&sched_clock_timer);
29413dbeb38SDaniel Thompson 	rd->read_sched_clock = suspended_sched_clock_read;
29532fea568SIngo Molnar 
29638ff87f7SStephen Boyd 	return 0;
29738ff87f7SStephen Boyd }
29838ff87f7SStephen Boyd 
sched_clock_resume(void)2993f2552f7SChang-An Chen void sched_clock_resume(void)
30038ff87f7SStephen Boyd {
3011809bfa4SDaniel Thompson 	struct clock_read_data *rd = &cd.read_data[0];
302cf7c9c17SDaniel Thompson 
30313dbeb38SDaniel Thompson 	rd->epoch_cyc = cd.actual_read_sched_clock();
3042c8bd588SAhmed S. Darwish 	hrtimer_start(&sched_clock_timer, cd.wrap_kt, HRTIMER_MODE_REL_HARD);
30513dbeb38SDaniel Thompson 	rd->read_sched_clock = cd.actual_read_sched_clock;
30638ff87f7SStephen Boyd }
30738ff87f7SStephen Boyd 
30838ff87f7SStephen Boyd static struct syscore_ops sched_clock_ops = {
30938ff87f7SStephen Boyd 	.suspend	= sched_clock_suspend,
31038ff87f7SStephen Boyd 	.resume		= sched_clock_resume,
31138ff87f7SStephen Boyd };
31238ff87f7SStephen Boyd 
sched_clock_syscore_init(void)31338ff87f7SStephen Boyd static int __init sched_clock_syscore_init(void)
31438ff87f7SStephen Boyd {
31538ff87f7SStephen Boyd 	register_syscore_ops(&sched_clock_ops);
31632fea568SIngo Molnar 
31738ff87f7SStephen Boyd 	return 0;
31838ff87f7SStephen Boyd }
31938ff87f7SStephen Boyd device_initcall(sched_clock_syscore_init);
320