xref: /linux-6.15/kernel/delayacct.c (revision 1751f872)
17170066eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
2ca74e92bSShailabh Nagar /* delayacct.c - per-task delay accounting
3ca74e92bSShailabh Nagar  *
4ca74e92bSShailabh Nagar  * Copyright (C) Shailabh Nagar, IBM Corp. 2006
5ca74e92bSShailabh Nagar  */
6ca74e92bSShailabh Nagar 
7ca74e92bSShailabh Nagar #include <linux/sched.h>
89164bb4aSIngo Molnar #include <linux/sched/task.h>
932ef5517SIngo Molnar #include <linux/sched/cputime.h>
104b7a08a0SPeter Zijlstra #include <linux/sched/clock.h>
11ca74e92bSShailabh Nagar #include <linux/slab.h>
126952b61dSAlexey Dobriyan #include <linux/taskstats.h>
13ca74e92bSShailabh Nagar #include <linux/sysctl.h>
14ca74e92bSShailabh Nagar #include <linux/delayacct.h>
15c9aaa895SGlauber Costa #include <linux/module.h>
16ca74e92bSShailabh Nagar 
17e4042ad4SPeter Zijlstra DEFINE_STATIC_KEY_FALSE(delayacct_key);
18e4042ad4SPeter Zijlstra int delayacct_on __read_mostly;	/* Delay accounting turned on/off */
19e18b890bSChristoph Lameter struct kmem_cache *delayacct_cache;
20ca74e92bSShailabh Nagar 
set_delayacct(bool enabled)210cd7c741SPeter Zijlstra static void set_delayacct(bool enabled)
220cd7c741SPeter Zijlstra {
230cd7c741SPeter Zijlstra 	if (enabled) {
240cd7c741SPeter Zijlstra 		static_branch_enable(&delayacct_key);
250cd7c741SPeter Zijlstra 		delayacct_on = 1;
260cd7c741SPeter Zijlstra 	} else {
270cd7c741SPeter Zijlstra 		delayacct_on = 0;
280cd7c741SPeter Zijlstra 		static_branch_disable(&delayacct_key);
290cd7c741SPeter Zijlstra 	}
300cd7c741SPeter Zijlstra }
310cd7c741SPeter Zijlstra 
delayacct_setup_enable(char * str)32e4042ad4SPeter Zijlstra static int __init delayacct_setup_enable(char *str)
33ca74e92bSShailabh Nagar {
34e4042ad4SPeter Zijlstra 	delayacct_on = 1;
35ca74e92bSShailabh Nagar 	return 1;
36ca74e92bSShailabh Nagar }
37e4042ad4SPeter Zijlstra __setup("delayacct", delayacct_setup_enable);
38ca74e92bSShailabh Nagar 
delayacct_init(void)39ca74e92bSShailabh Nagar void delayacct_init(void)
40ca74e92bSShailabh Nagar {
415d097056SVladimir Davydov 	delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT);
42ca74e92bSShailabh Nagar 	delayacct_tsk_init(&init_task);
430cd7c741SPeter Zijlstra 	set_delayacct(delayacct_on);
44ca74e92bSShailabh Nagar }
45ca74e92bSShailabh Nagar 
460cd7c741SPeter Zijlstra #ifdef CONFIG_PROC_SYSCTL
sysctl_delayacct(const struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)4778eb4ea2SJoel Granados static int sysctl_delayacct(const struct ctl_table *table, int write, void *buffer,
480cd7c741SPeter Zijlstra 		     size_t *lenp, loff_t *ppos)
490cd7c741SPeter Zijlstra {
500cd7c741SPeter Zijlstra 	int state = delayacct_on;
510cd7c741SPeter Zijlstra 	struct ctl_table t;
520cd7c741SPeter Zijlstra 	int err;
530cd7c741SPeter Zijlstra 
540cd7c741SPeter Zijlstra 	if (write && !capable(CAP_SYS_ADMIN))
550cd7c741SPeter Zijlstra 		return -EPERM;
560cd7c741SPeter Zijlstra 
570cd7c741SPeter Zijlstra 	t = *table;
580cd7c741SPeter Zijlstra 	t.data = &state;
590cd7c741SPeter Zijlstra 	err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
600cd7c741SPeter Zijlstra 	if (err < 0)
610cd7c741SPeter Zijlstra 		return err;
620cd7c741SPeter Zijlstra 	if (write)
630cd7c741SPeter Zijlstra 		set_delayacct(state);
640cd7c741SPeter Zijlstra 	return err;
650cd7c741SPeter Zijlstra }
661186618aStangmeng 
67*1751f872SJoel Granados static const struct ctl_table kern_delayacct_table[] = {
681186618aStangmeng 	{
691186618aStangmeng 		.procname       = "task_delayacct",
701186618aStangmeng 		.data           = NULL,
711186618aStangmeng 		.maxlen         = sizeof(unsigned int),
721186618aStangmeng 		.mode           = 0644,
731186618aStangmeng 		.proc_handler   = sysctl_delayacct,
741186618aStangmeng 		.extra1         = SYSCTL_ZERO,
751186618aStangmeng 		.extra2         = SYSCTL_ONE,
761186618aStangmeng 	},
771186618aStangmeng };
781186618aStangmeng 
kernel_delayacct_sysctls_init(void)791186618aStangmeng static __init int kernel_delayacct_sysctls_init(void)
801186618aStangmeng {
811186618aStangmeng 	register_sysctl_init("kernel", kern_delayacct_table);
821186618aStangmeng 	return 0;
831186618aStangmeng }
841186618aStangmeng late_initcall(kernel_delayacct_sysctls_init);
850cd7c741SPeter Zijlstra #endif
860cd7c741SPeter Zijlstra 
__delayacct_tsk_init(struct task_struct * tsk)87ca74e92bSShailabh Nagar void __delayacct_tsk_init(struct task_struct *tsk)
88ca74e92bSShailabh Nagar {
89e94b1766SChristoph Lameter 	tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL);
90ca74e92bSShailabh Nagar 	if (tsk->delays)
9102acc80dSSebastian Andrzej Siewior 		raw_spin_lock_init(&tsk->delays->lock);
92ca74e92bSShailabh Nagar }
93ca74e92bSShailabh Nagar 
94ca74e92bSShailabh Nagar /*
959667a23dSThomas Gleixner  * Finish delay accounting for a statistic using its timestamps (@start),
96658eb5abSWang Yaxin  * accumulator (@total) and @count
97ca74e92bSShailabh Nagar  */
delayacct_end(raw_spinlock_t * lock,u64 * start,u64 * total,u32 * count,u64 * max,u64 * min)98f65c64f3SWang Yaxin static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, u32 *count, u64 *max, u64 *min)
99ca74e92bSShailabh Nagar {
1004b7a08a0SPeter Zijlstra 	s64 ns = local_clock() - *start;
10164efade1SPeter Zijlstra 	unsigned long flags;
102ca74e92bSShailabh Nagar 
1039667a23dSThomas Gleixner 	if (ns > 0) {
10402acc80dSSebastian Andrzej Siewior 		raw_spin_lock_irqsave(lock, flags);
105ca74e92bSShailabh Nagar 		*total += ns;
106ca74e92bSShailabh Nagar 		(*count)++;
107658eb5abSWang Yaxin 		if (ns > *max)
108658eb5abSWang Yaxin 			*max = ns;
109f65c64f3SWang Yaxin 		if (*min == 0 || ns < *min)
110f65c64f3SWang Yaxin 			*min = ns;
11102acc80dSSebastian Andrzej Siewior 		raw_spin_unlock_irqrestore(lock, flags);
112ca74e92bSShailabh Nagar 	}
1139667a23dSThomas Gleixner }
114ca74e92bSShailabh Nagar 
__delayacct_blkio_start(void)1150ff92245SShailabh Nagar void __delayacct_blkio_start(void)
1160ff92245SShailabh Nagar {
1174b7a08a0SPeter Zijlstra 	current->delays->blkio_start = local_clock();
1180ff92245SShailabh Nagar }
1190ff92245SShailabh Nagar 
120c96f5471SJosh Snyder /*
121c96f5471SJosh Snyder  * We cannot rely on the `current` macro, as we haven't yet switched back to
122c96f5471SJosh Snyder  * the process being woken.
123c96f5471SJosh Snyder  */
__delayacct_blkio_end(struct task_struct * p)124c96f5471SJosh Snyder void __delayacct_blkio_end(struct task_struct *p)
1250ff92245SShailabh Nagar {
126a3d5dc90SYang Yang 	delayacct_end(&p->delays->lock,
127a3d5dc90SYang Yang 		      &p->delays->blkio_start,
128a3d5dc90SYang Yang 		      &p->delays->blkio_delay,
129658eb5abSWang Yaxin 		      &p->delays->blkio_count,
130f65c64f3SWang Yaxin 		      &p->delays->blkio_delay_max,
131f65c64f3SWang Yaxin 		      &p->delays->blkio_delay_min);
1320ff92245SShailabh Nagar }
1336f44993fSShailabh Nagar 
delayacct_add_tsk(struct taskstats * d,struct task_struct * tsk)134e4042ad4SPeter Zijlstra int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
1356f44993fSShailabh Nagar {
136dbf3da1cSFrederic Weisbecker 	u64 utime, stime, stimescaled, utimescaled;
13768f6783dSThomas Gleixner 	unsigned long long t2, t3;
13868f6783dSThomas Gleixner 	unsigned long flags, t1;
13968f6783dSThomas Gleixner 	s64 tmp;
1406f44993fSShailabh Nagar 
141dbf3da1cSFrederic Weisbecker 	task_cputime(tsk, &utime, &stime);
14268f6783dSThomas Gleixner 	tmp = (s64)d->cpu_run_real_total;
143dbf3da1cSFrederic Weisbecker 	tmp += utime + stime;
1446f44993fSShailabh Nagar 	d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
1456f44993fSShailabh Nagar 
146dbf3da1cSFrederic Weisbecker 	task_cputime_scaled(tsk, &utimescaled, &stimescaled);
14768f6783dSThomas Gleixner 	tmp = (s64)d->cpu_scaled_run_real_total;
148dbf3da1cSFrederic Weisbecker 	tmp += utimescaled + stimescaled;
149c66f08beSMichael Neuling 	d->cpu_scaled_run_real_total =
150c66f08beSMichael Neuling 		(tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp;
151c66f08beSMichael Neuling 
1526f44993fSShailabh Nagar 	/*
1536f44993fSShailabh Nagar 	 * No locking available for sched_info (and too expensive to add one)
1546f44993fSShailabh Nagar 	 * Mitigate by taking snapshot of values
1556f44993fSShailabh Nagar 	 */
1562d72376bSIngo Molnar 	t1 = tsk->sched_info.pcount;
1576f44993fSShailabh Nagar 	t2 = tsk->sched_info.run_delay;
1589c2c4802SKen Chen 	t3 = tsk->se.sum_exec_runtime;
1596f44993fSShailabh Nagar 
1606f44993fSShailabh Nagar 	d->cpu_count += t1;
1616f44993fSShailabh Nagar 
162658eb5abSWang Yaxin 	d->cpu_delay_max = tsk->sched_info.max_run_delay;
163f65c64f3SWang Yaxin 	d->cpu_delay_min = tsk->sched_info.min_run_delay;
164172ba844SBalbir Singh 	tmp = (s64)d->cpu_delay_total + t2;
1656f44993fSShailabh Nagar 	d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
166172ba844SBalbir Singh 	tmp = (s64)d->cpu_run_virtual_total + t3;
167658eb5abSWang Yaxin 
1686f44993fSShailabh Nagar 	d->cpu_run_virtual_total =
1696f44993fSShailabh Nagar 		(tmp < (s64)d->cpu_run_virtual_total) ?	0 : tmp;
1706f44993fSShailabh Nagar 
171e4042ad4SPeter Zijlstra 	if (!tsk->delays)
172e4042ad4SPeter Zijlstra 		return 0;
173e4042ad4SPeter Zijlstra 
1746f44993fSShailabh Nagar 	/* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
17502acc80dSSebastian Andrzej Siewior 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
176658eb5abSWang Yaxin 	d->blkio_delay_max = tsk->delays->blkio_delay_max;
177f65c64f3SWang Yaxin 	d->blkio_delay_min = tsk->delays->blkio_delay_min;
1786f44993fSShailabh Nagar 	tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
1796f44993fSShailabh Nagar 	d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp;
180658eb5abSWang Yaxin 	d->swapin_delay_max = tsk->delays->swapin_delay_max;
181f65c64f3SWang Yaxin 	d->swapin_delay_min = tsk->delays->swapin_delay_min;
1826f44993fSShailabh Nagar 	tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
1836f44993fSShailabh Nagar 	d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp;
184658eb5abSWang Yaxin 	d->freepages_delay_max = tsk->delays->freepages_delay_max;
185f65c64f3SWang Yaxin 	d->freepages_delay_min = tsk->delays->freepages_delay_min;
186016ae219SKeika Kobayashi 	tmp = d->freepages_delay_total + tsk->delays->freepages_delay;
187016ae219SKeika Kobayashi 	d->freepages_delay_total = (tmp < d->freepages_delay_total) ? 0 : tmp;
188658eb5abSWang Yaxin 	d->thrashing_delay_max = tsk->delays->thrashing_delay_max;
189f65c64f3SWang Yaxin 	d->thrashing_delay_min = tsk->delays->thrashing_delay_min;
190b1d29ba8SJohannes Weiner 	tmp = d->thrashing_delay_total + tsk->delays->thrashing_delay;
191b1d29ba8SJohannes Weiner 	d->thrashing_delay_total = (tmp < d->thrashing_delay_total) ? 0 : tmp;
192658eb5abSWang Yaxin 	d->compact_delay_max = tsk->delays->compact_delay_max;
193f65c64f3SWang Yaxin 	d->compact_delay_min = tsk->delays->compact_delay_min;
1945bf18281Swangyong 	tmp = d->compact_delay_total + tsk->delays->compact_delay;
1955bf18281Swangyong 	d->compact_delay_total = (tmp < d->compact_delay_total) ? 0 : tmp;
196658eb5abSWang Yaxin 	d->wpcopy_delay_max = tsk->delays->wpcopy_delay_max;
197f65c64f3SWang Yaxin 	d->wpcopy_delay_min = tsk->delays->wpcopy_delay_min;
198662ce1dcSYang Yang 	tmp = d->wpcopy_delay_total + tsk->delays->wpcopy_delay;
199662ce1dcSYang Yang 	d->wpcopy_delay_total = (tmp < d->wpcopy_delay_total) ? 0 : tmp;
200658eb5abSWang Yaxin 	d->irq_delay_max = tsk->delays->irq_delay_max;
201f65c64f3SWang Yaxin 	d->irq_delay_min = tsk->delays->irq_delay_min;
202a3b2aeacSYang Yang 	tmp = d->irq_delay_total + tsk->delays->irq_delay;
203a3b2aeacSYang Yang 	d->irq_delay_total = (tmp < d->irq_delay_total) ? 0 : tmp;
2046f44993fSShailabh Nagar 	d->blkio_count += tsk->delays->blkio_count;
2056f44993fSShailabh Nagar 	d->swapin_count += tsk->delays->swapin_count;
206016ae219SKeika Kobayashi 	d->freepages_count += tsk->delays->freepages_count;
207b1d29ba8SJohannes Weiner 	d->thrashing_count += tsk->delays->thrashing_count;
2085bf18281Swangyong 	d->compact_count += tsk->delays->compact_count;
209662ce1dcSYang Yang 	d->wpcopy_count += tsk->delays->wpcopy_count;
210a3b2aeacSYang Yang 	d->irq_count += tsk->delays->irq_count;
21102acc80dSSebastian Andrzej Siewior 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
2126f44993fSShailabh Nagar 
2136f44993fSShailabh Nagar 	return 0;
2146f44993fSShailabh Nagar }
21525890454SShailabh Nagar 
__delayacct_blkio_ticks(struct task_struct * tsk)21625890454SShailabh Nagar __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
21725890454SShailabh Nagar {
21825890454SShailabh Nagar 	__u64 ret;
21964efade1SPeter Zijlstra 	unsigned long flags;
22025890454SShailabh Nagar 
22102acc80dSSebastian Andrzej Siewior 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
222a3d5dc90SYang Yang 	ret = nsec_to_clock_t(tsk->delays->blkio_delay);
22302acc80dSSebastian Andrzej Siewior 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
22425890454SShailabh Nagar 	return ret;
22525890454SShailabh Nagar }
22625890454SShailabh Nagar 
__delayacct_freepages_start(void)227873b4771SKeika Kobayashi void __delayacct_freepages_start(void)
228873b4771SKeika Kobayashi {
2294b7a08a0SPeter Zijlstra 	current->delays->freepages_start = local_clock();
230873b4771SKeika Kobayashi }
231873b4771SKeika Kobayashi 
__delayacct_freepages_end(void)232873b4771SKeika Kobayashi void __delayacct_freepages_end(void)
233873b4771SKeika Kobayashi {
2344b7a08a0SPeter Zijlstra 	delayacct_end(&current->delays->lock,
235c96f5471SJosh Snyder 		      &current->delays->freepages_start,
236873b4771SKeika Kobayashi 		      &current->delays->freepages_delay,
237658eb5abSWang Yaxin 		      &current->delays->freepages_count,
238f65c64f3SWang Yaxin 		      &current->delays->freepages_delay_max,
239f65c64f3SWang Yaxin 		      &current->delays->freepages_delay_min);
240873b4771SKeika Kobayashi }
241873b4771SKeika Kobayashi 
__delayacct_thrashing_start(bool * in_thrashing)242aa1cf99bSYang Yang void __delayacct_thrashing_start(bool *in_thrashing)
243b1d29ba8SJohannes Weiner {
244aa1cf99bSYang Yang 	*in_thrashing = !!current->in_thrashing;
245aa1cf99bSYang Yang 	if (*in_thrashing)
246aa1cf99bSYang Yang 		return;
247aa1cf99bSYang Yang 
248aa1cf99bSYang Yang 	current->in_thrashing = 1;
2494b7a08a0SPeter Zijlstra 	current->delays->thrashing_start = local_clock();
250b1d29ba8SJohannes Weiner }
251b1d29ba8SJohannes Weiner 
__delayacct_thrashing_end(bool * in_thrashing)252aa1cf99bSYang Yang void __delayacct_thrashing_end(bool *in_thrashing)
253b1d29ba8SJohannes Weiner {
254aa1cf99bSYang Yang 	if (*in_thrashing)
255aa1cf99bSYang Yang 		return;
256aa1cf99bSYang Yang 
257aa1cf99bSYang Yang 	current->in_thrashing = 0;
258b1d29ba8SJohannes Weiner 	delayacct_end(&current->delays->lock,
259b1d29ba8SJohannes Weiner 		      &current->delays->thrashing_start,
260b1d29ba8SJohannes Weiner 		      &current->delays->thrashing_delay,
261658eb5abSWang Yaxin 		      &current->delays->thrashing_count,
262f65c64f3SWang Yaxin 		      &current->delays->thrashing_delay_max,
263f65c64f3SWang Yaxin 		      &current->delays->thrashing_delay_min);
264b1d29ba8SJohannes Weiner }
265a3d5dc90SYang Yang 
__delayacct_swapin_start(void)266a3d5dc90SYang Yang void __delayacct_swapin_start(void)
267a3d5dc90SYang Yang {
268a3d5dc90SYang Yang 	current->delays->swapin_start = local_clock();
269a3d5dc90SYang Yang }
270a3d5dc90SYang Yang 
__delayacct_swapin_end(void)271a3d5dc90SYang Yang void __delayacct_swapin_end(void)
272a3d5dc90SYang Yang {
273a3d5dc90SYang Yang 	delayacct_end(&current->delays->lock,
274a3d5dc90SYang Yang 		      &current->delays->swapin_start,
275a3d5dc90SYang Yang 		      &current->delays->swapin_delay,
276658eb5abSWang Yaxin 		      &current->delays->swapin_count,
277f65c64f3SWang Yaxin 		      &current->delays->swapin_delay_max,
278f65c64f3SWang Yaxin 		      &current->delays->swapin_delay_min);
279a3d5dc90SYang Yang }
2805bf18281Swangyong 
__delayacct_compact_start(void)2815bf18281Swangyong void __delayacct_compact_start(void)
2825bf18281Swangyong {
2835bf18281Swangyong 	current->delays->compact_start = local_clock();
2845bf18281Swangyong }
2855bf18281Swangyong 
__delayacct_compact_end(void)2865bf18281Swangyong void __delayacct_compact_end(void)
2875bf18281Swangyong {
2885bf18281Swangyong 	delayacct_end(&current->delays->lock,
2895bf18281Swangyong 		      &current->delays->compact_start,
2905bf18281Swangyong 		      &current->delays->compact_delay,
291658eb5abSWang Yaxin 		      &current->delays->compact_count,
292f65c64f3SWang Yaxin 		      &current->delays->compact_delay_max,
293f65c64f3SWang Yaxin 		      &current->delays->compact_delay_min);
2945bf18281Swangyong }
295662ce1dcSYang Yang 
__delayacct_wpcopy_start(void)296662ce1dcSYang Yang void __delayacct_wpcopy_start(void)
297662ce1dcSYang Yang {
298662ce1dcSYang Yang 	current->delays->wpcopy_start = local_clock();
299662ce1dcSYang Yang }
300662ce1dcSYang Yang 
__delayacct_wpcopy_end(void)301662ce1dcSYang Yang void __delayacct_wpcopy_end(void)
302662ce1dcSYang Yang {
303662ce1dcSYang Yang 	delayacct_end(&current->delays->lock,
304662ce1dcSYang Yang 		      &current->delays->wpcopy_start,
305662ce1dcSYang Yang 		      &current->delays->wpcopy_delay,
306658eb5abSWang Yaxin 		      &current->delays->wpcopy_count,
307f65c64f3SWang Yaxin 		      &current->delays->wpcopy_delay_max,
308f65c64f3SWang Yaxin 		      &current->delays->wpcopy_delay_min);
309662ce1dcSYang Yang }
310a3b2aeacSYang Yang 
__delayacct_irq(struct task_struct * task,u32 delta)311a3b2aeacSYang Yang void __delayacct_irq(struct task_struct *task, u32 delta)
312a3b2aeacSYang Yang {
313a3b2aeacSYang Yang 	unsigned long flags;
314a3b2aeacSYang Yang 
315a3b2aeacSYang Yang 	raw_spin_lock_irqsave(&task->delays->lock, flags);
316a3b2aeacSYang Yang 	task->delays->irq_delay += delta;
317a3b2aeacSYang Yang 	task->delays->irq_count++;
318658eb5abSWang Yaxin 	if (delta > task->delays->irq_delay_max)
319658eb5abSWang Yaxin 		task->delays->irq_delay_max = delta;
320f65c64f3SWang Yaxin 	if (delta && (!task->delays->irq_delay_min || delta < task->delays->irq_delay_min))
321f65c64f3SWang Yaxin 		task->delays->irq_delay_min = delta;
322a3b2aeacSYang Yang 	raw_spin_unlock_irqrestore(&task->delays->lock, flags);
323a3b2aeacSYang Yang }
324a3b2aeacSYang Yang 
325