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(¤t->delays->lock,
235c96f5471SJosh Snyder ¤t->delays->freepages_start,
236873b4771SKeika Kobayashi ¤t->delays->freepages_delay,
237658eb5abSWang Yaxin ¤t->delays->freepages_count,
238f65c64f3SWang Yaxin ¤t->delays->freepages_delay_max,
239f65c64f3SWang Yaxin ¤t->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(¤t->delays->lock,
259b1d29ba8SJohannes Weiner ¤t->delays->thrashing_start,
260b1d29ba8SJohannes Weiner ¤t->delays->thrashing_delay,
261658eb5abSWang Yaxin ¤t->delays->thrashing_count,
262f65c64f3SWang Yaxin ¤t->delays->thrashing_delay_max,
263f65c64f3SWang Yaxin ¤t->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(¤t->delays->lock,
274a3d5dc90SYang Yang ¤t->delays->swapin_start,
275a3d5dc90SYang Yang ¤t->delays->swapin_delay,
276658eb5abSWang Yaxin ¤t->delays->swapin_count,
277f65c64f3SWang Yaxin ¤t->delays->swapin_delay_max,
278f65c64f3SWang Yaxin ¤t->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(¤t->delays->lock,
2895bf18281Swangyong ¤t->delays->compact_start,
2905bf18281Swangyong ¤t->delays->compact_delay,
291658eb5abSWang Yaxin ¤t->delays->compact_count,
292f65c64f3SWang Yaxin ¤t->delays->compact_delay_max,
293f65c64f3SWang Yaxin ¤t->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(¤t->delays->lock,
304662ce1dcSYang Yang ¤t->delays->wpcopy_start,
305662ce1dcSYang Yang ¤t->delays->wpcopy_delay,
306658eb5abSWang Yaxin ¤t->delays->wpcopy_count,
307f65c64f3SWang Yaxin ¤t->delays->wpcopy_delay_max,
308f65c64f3SWang Yaxin ¤t->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