xref: /linux-6.15/kernel/delayacct.c (revision c5895d3f)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* delayacct.c - per-task delay accounting
3  *
4  * Copyright (C) Shailabh Nagar, IBM Corp. 2006
5  */
6 
7 #include <linux/sched.h>
8 #include <linux/sched/task.h>
9 #include <linux/sched/cputime.h>
10 #include <linux/sched/clock.h>
11 #include <linux/slab.h>
12 #include <linux/taskstats.h>
13 #include <linux/sysctl.h>
14 #include <linux/delayacct.h>
15 #include <linux/module.h>
16 
17 int delayacct_on __read_mostly = 1;	/* Delay accounting turned on/off */
18 struct kmem_cache *delayacct_cache;
19 
20 static int __init delayacct_setup_disable(char *str)
21 {
22 	delayacct_on = 0;
23 	return 1;
24 }
25 __setup("nodelayacct", delayacct_setup_disable);
26 
27 void delayacct_init(void)
28 {
29 	delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT);
30 	delayacct_tsk_init(&init_task);
31 }
32 
33 void __delayacct_tsk_init(struct task_struct *tsk)
34 {
35 	tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL);
36 	if (tsk->delays)
37 		raw_spin_lock_init(&tsk->delays->lock);
38 }
39 
40 /*
41  * Finish delay accounting for a statistic using its timestamps (@start),
42  * accumalator (@total) and @count
43  */
44 static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, u32 *count)
45 {
46 	s64 ns = local_clock() - *start;
47 	unsigned long flags;
48 
49 	if (ns > 0) {
50 		raw_spin_lock_irqsave(lock, flags);
51 		*total += ns;
52 		(*count)++;
53 		raw_spin_unlock_irqrestore(lock, flags);
54 	}
55 }
56 
57 void __delayacct_blkio_start(void)
58 {
59 	current->delays->blkio_start = local_clock();
60 }
61 
62 /*
63  * We cannot rely on the `current` macro, as we haven't yet switched back to
64  * the process being woken.
65  */
66 void __delayacct_blkio_end(struct task_struct *p)
67 {
68 	struct task_delay_info *delays = p->delays;
69 	u64 *total;
70 	u32 *count;
71 
72 	if (p->delays->flags & DELAYACCT_PF_SWAPIN) {
73 		total = &delays->swapin_delay;
74 		count = &delays->swapin_count;
75 	} else {
76 		total = &delays->blkio_delay;
77 		count = &delays->blkio_count;
78 	}
79 
80 	delayacct_end(&delays->lock, &delays->blkio_start, total, count);
81 }
82 
83 int __delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
84 {
85 	u64 utime, stime, stimescaled, utimescaled;
86 	unsigned long long t2, t3;
87 	unsigned long flags, t1;
88 	s64 tmp;
89 
90 	task_cputime(tsk, &utime, &stime);
91 	tmp = (s64)d->cpu_run_real_total;
92 	tmp += utime + stime;
93 	d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
94 
95 	task_cputime_scaled(tsk, &utimescaled, &stimescaled);
96 	tmp = (s64)d->cpu_scaled_run_real_total;
97 	tmp += utimescaled + stimescaled;
98 	d->cpu_scaled_run_real_total =
99 		(tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp;
100 
101 	/*
102 	 * No locking available for sched_info (and too expensive to add one)
103 	 * Mitigate by taking snapshot of values
104 	 */
105 	t1 = tsk->sched_info.pcount;
106 	t2 = tsk->sched_info.run_delay;
107 	t3 = tsk->se.sum_exec_runtime;
108 
109 	d->cpu_count += t1;
110 
111 	tmp = (s64)d->cpu_delay_total + t2;
112 	d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
113 
114 	tmp = (s64)d->cpu_run_virtual_total + t3;
115 	d->cpu_run_virtual_total =
116 		(tmp < (s64)d->cpu_run_virtual_total) ?	0 : tmp;
117 
118 	/* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
119 
120 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
121 	tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
122 	d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp;
123 	tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
124 	d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp;
125 	tmp = d->freepages_delay_total + tsk->delays->freepages_delay;
126 	d->freepages_delay_total = (tmp < d->freepages_delay_total) ? 0 : tmp;
127 	tmp = d->thrashing_delay_total + tsk->delays->thrashing_delay;
128 	d->thrashing_delay_total = (tmp < d->thrashing_delay_total) ? 0 : tmp;
129 	d->blkio_count += tsk->delays->blkio_count;
130 	d->swapin_count += tsk->delays->swapin_count;
131 	d->freepages_count += tsk->delays->freepages_count;
132 	d->thrashing_count += tsk->delays->thrashing_count;
133 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
134 
135 	return 0;
136 }
137 
138 __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
139 {
140 	__u64 ret;
141 	unsigned long flags;
142 
143 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
144 	ret = nsec_to_clock_t(tsk->delays->blkio_delay +
145 				tsk->delays->swapin_delay);
146 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
147 	return ret;
148 }
149 
150 void __delayacct_freepages_start(void)
151 {
152 	current->delays->freepages_start = local_clock();
153 }
154 
155 void __delayacct_freepages_end(void)
156 {
157 	delayacct_end(&current->delays->lock,
158 		      &current->delays->freepages_start,
159 		      &current->delays->freepages_delay,
160 		      &current->delays->freepages_count);
161 }
162 
163 void __delayacct_thrashing_start(void)
164 {
165 	current->delays->thrashing_start = local_clock();
166 }
167 
168 void __delayacct_thrashing_end(void)
169 {
170 	delayacct_end(&current->delays->lock,
171 		      &current->delays->thrashing_start,
172 		      &current->delays->thrashing_delay,
173 		      &current->delays->thrashing_count);
174 }
175