• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #ifdef CONFIG_TASK_DELAY_ACCT
18 
19 DEFINE_STATIC_KEY_FALSE(delayacct_key);
20 int delayacct_on __read_mostly;	/* Delay accounting turned on/off */
21 struct kmem_cache *delayacct_cache;
22 
set_delayacct(bool enabled)23 static void set_delayacct(bool enabled)
24 {
25 	if (enabled) {
26 		static_branch_enable(&delayacct_key);
27 		delayacct_on = 1;
28 	} else {
29 		delayacct_on = 0;
30 		static_branch_disable(&delayacct_key);
31 	}
32 }
33 
delayacct_setup_enable(char * str)34 static int __init delayacct_setup_enable(char *str)
35 {
36 	delayacct_on = 1;
37 	return 1;
38 }
39 __setup("delayacct", delayacct_setup_enable);
40 
delayacct_init(void)41 void delayacct_init(void)
42 {
43 	delayacct_cache = KMEM_CACHE(task_delay_info, SLAB_PANIC|SLAB_ACCOUNT);
44 	delayacct_tsk_init(&init_task);
45 	set_delayacct(delayacct_on);
46 }
47 
48 #ifdef CONFIG_PROC_SYSCTL
sysctl_delayacct(struct ctl_table * table,int write,void * buffer,size_t * lenp,loff_t * ppos)49 int sysctl_delayacct(struct ctl_table *table, int write, void *buffer,
50 		     size_t *lenp, loff_t *ppos)
51 {
52 	int state = delayacct_on;
53 	struct ctl_table t;
54 	int err;
55 
56 	if (write && !capable(CAP_SYS_ADMIN))
57 		return -EPERM;
58 
59 	t = *table;
60 	t.data = &state;
61 	err = proc_dointvec_minmax(&t, write, buffer, lenp, ppos);
62 	if (err < 0)
63 		return err;
64 	if (write)
65 		set_delayacct(state);
66 	return err;
67 }
68 #endif
69 
__delayacct_tsk_init(struct task_struct * tsk)70 void __delayacct_tsk_init(struct task_struct *tsk)
71 {
72 	tsk->delays = kmem_cache_zalloc(delayacct_cache, GFP_KERNEL);
73 	if (tsk->delays)
74 		raw_spin_lock_init(&tsk->delays->lock);
75 }
76 
77 /*
78  * Finish delay accounting for a statistic using its timestamps (@start),
79  * accumalator (@total) and @count
80  */
delayacct_end(raw_spinlock_t * lock,u64 * start,u64 * total,u32 * count)81 static void delayacct_end(raw_spinlock_t *lock, u64 *start, u64 *total, u32 *count)
82 {
83 	s64 ns = local_clock() - *start;
84 	unsigned long flags;
85 
86 	if (ns > 0) {
87 		raw_spin_lock_irqsave(lock, flags);
88 		*total += ns;
89 		(*count)++;
90 		raw_spin_unlock_irqrestore(lock, flags);
91 	}
92 }
93 
__delayacct_blkio_start(void)94 void __delayacct_blkio_start(void)
95 {
96 	current->delays->blkio_start = local_clock();
97 }
98 
99 /*
100  * We cannot rely on the `current` macro, as we haven't yet switched back to
101  * the process being woken.
102  */
__delayacct_blkio_end(struct task_struct * p)103 void __delayacct_blkio_end(struct task_struct *p)
104 {
105 	struct task_delay_info *delays = p->delays;
106 	u64 *total;
107 	u32 *count;
108 
109 	if (p->delays->flags & DELAYACCT_PF_SWAPIN) {
110 		total = &delays->swapin_delay;
111 		count = &delays->swapin_count;
112 	} else {
113 		total = &delays->blkio_delay;
114 		count = &delays->blkio_count;
115 	}
116 
117 	delayacct_end(&delays->lock, &delays->blkio_start, total, count);
118 }
119 
delayacct_add_tsk(struct taskstats * d,struct task_struct * tsk)120 int delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk)
121 {
122 	u64 utime, stime, stimescaled, utimescaled;
123 	unsigned long long t2, t3;
124 	unsigned long flags, t1;
125 	s64 tmp;
126 
127 	task_cputime(tsk, &utime, &stime);
128 	tmp = (s64)d->cpu_run_real_total;
129 	tmp += utime + stime;
130 	d->cpu_run_real_total = (tmp < (s64)d->cpu_run_real_total) ? 0 : tmp;
131 
132 	task_cputime_scaled(tsk, &utimescaled, &stimescaled);
133 	tmp = (s64)d->cpu_scaled_run_real_total;
134 	tmp += utimescaled + stimescaled;
135 	d->cpu_scaled_run_real_total =
136 		(tmp < (s64)d->cpu_scaled_run_real_total) ? 0 : tmp;
137 
138 	/*
139 	 * No locking available for sched_info (and too expensive to add one)
140 	 * Mitigate by taking snapshot of values
141 	 */
142 	t1 = tsk->sched_info.pcount;
143 	t2 = tsk->sched_info.run_delay;
144 	t3 = tsk->se.sum_exec_runtime;
145 
146 	d->cpu_count += t1;
147 
148 	tmp = (s64)d->cpu_delay_total + t2;
149 	d->cpu_delay_total = (tmp < (s64)d->cpu_delay_total) ? 0 : tmp;
150 
151 	tmp = (s64)d->cpu_run_virtual_total + t3;
152 	d->cpu_run_virtual_total =
153 		(tmp < (s64)d->cpu_run_virtual_total) ?	0 : tmp;
154 
155 	if (!tsk->delays)
156 		return 0;
157 
158 	/* zero XXX_total, non-zero XXX_count implies XXX stat overflowed */
159 
160 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
161 	tmp = d->blkio_delay_total + tsk->delays->blkio_delay;
162 	d->blkio_delay_total = (tmp < d->blkio_delay_total) ? 0 : tmp;
163 	tmp = d->swapin_delay_total + tsk->delays->swapin_delay;
164 	d->swapin_delay_total = (tmp < d->swapin_delay_total) ? 0 : tmp;
165 	tmp = d->freepages_delay_total + tsk->delays->freepages_delay;
166 	d->freepages_delay_total = (tmp < d->freepages_delay_total) ? 0 : tmp;
167 	tmp = d->thrashing_delay_total + tsk->delays->thrashing_delay;
168 	d->thrashing_delay_total = (tmp < d->thrashing_delay_total) ? 0 : tmp;
169 	d->blkio_count += tsk->delays->blkio_count;
170 	d->swapin_count += tsk->delays->swapin_count;
171 	d->freepages_count += tsk->delays->freepages_count;
172 	d->thrashing_count += tsk->delays->thrashing_count;
173 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
174 
175 	return 0;
176 }
177 
__delayacct_blkio_ticks(struct task_struct * tsk)178 __u64 __delayacct_blkio_ticks(struct task_struct *tsk)
179 {
180 	__u64 ret;
181 	unsigned long flags;
182 
183 	raw_spin_lock_irqsave(&tsk->delays->lock, flags);
184 	ret = nsec_to_clock_t(tsk->delays->blkio_delay +
185 				tsk->delays->swapin_delay);
186 	raw_spin_unlock_irqrestore(&tsk->delays->lock, flags);
187 	return ret;
188 }
189 
__delayacct_freepages_start(void)190 void __delayacct_freepages_start(void)
191 {
192 	current->delays->freepages_start = local_clock();
193 }
194 
__delayacct_freepages_end(void)195 void __delayacct_freepages_end(void)
196 {
197 	delayacct_end(&current->delays->lock,
198 		      &current->delays->freepages_start,
199 		      &current->delays->freepages_delay,
200 		      &current->delays->freepages_count);
201 }
202 
__delayacct_thrashing_start(void)203 void __delayacct_thrashing_start(void)
204 {
205 	current->delays->thrashing_start = local_clock();
206 }
207 
__delayacct_thrashing_end(void)208 void __delayacct_thrashing_end(void)
209 {
210 	delayacct_end(&current->delays->lock,
211 		      &current->delays->thrashing_start,
212 		      &current->delays->thrashing_delay,
213 		      &current->delays->thrashing_count);
214 }
215 #else
216 #include <trace/hooks/delayacct.h>
217 
218 int delayacct_enabled __read_mostly;	/* Delay accounting turned on/off */
get_delayacct_enabled(void)219 bool get_delayacct_enabled(void)
220 {
221 	return delayacct_enabled;
222 }
223 
set_delayacct_enabled(bool enabled)224 void set_delayacct_enabled(bool enabled)
225 {
226 	delayacct_enabled = enabled;
227 }
228 EXPORT_SYMBOL_GPL(set_delayacct_enabled);
229 
_trace_android_vh_delayacct_set_flag(struct task_struct * p,int flag)230 void _trace_android_vh_delayacct_set_flag(struct task_struct *p, int flag)
231 {
232 	trace_android_vh_delayacct_set_flag(p, flag);
233 }
234 
_trace_android_vh_delayacct_clear_flag(struct task_struct * p,int flag)235 void _trace_android_vh_delayacct_clear_flag(struct task_struct *p, int flag)
236 {
237 	trace_android_vh_delayacct_clear_flag(p, flag);
238 }
239 
_trace_android_rvh_delayacct_init(void)240 void _trace_android_rvh_delayacct_init(void)
241 {
242 	trace_android_rvh_delayacct_init(NULL);
243 }
244 
_trace_android_rvh_delayacct_tsk_init(struct task_struct * tsk)245 void _trace_android_rvh_delayacct_tsk_init(struct task_struct *tsk)
246 {
247 	trace_android_rvh_delayacct_tsk_init(tsk);
248 }
249 
_trace_android_rvh_delayacct_tsk_free(struct task_struct * tsk)250 void _trace_android_rvh_delayacct_tsk_free(struct task_struct *tsk)
251 {
252 	trace_android_rvh_delayacct_tsk_free(tsk);
253 }
254 
_trace_android_vh_delayacct_blkio_start(void)255 void _trace_android_vh_delayacct_blkio_start(void)
256 {
257 	trace_android_vh_delayacct_blkio_start(NULL);
258 }
259 
_trace_android_vh_delayacct_blkio_end(struct task_struct * p)260 void _trace_android_vh_delayacct_blkio_end(struct task_struct *p)
261 {
262 	trace_android_vh_delayacct_blkio_end(p);
263 }
264 
265 
_trace_android_vh_delayacct_add_tsk(struct taskstats * d,struct task_struct * tsk,int * ret)266 void _trace_android_vh_delayacct_add_tsk(struct taskstats *d, struct task_struct *tsk, int *ret)
267 {
268 	trace_android_vh_delayacct_add_tsk(d, tsk, ret);
269 }
270 
_trace_android_vh_delayacct_blkio_ticks(struct task_struct * tsk,__u64 * ret)271 void _trace_android_vh_delayacct_blkio_ticks(struct task_struct *tsk, __u64 *ret)
272 {
273 	trace_android_vh_delayacct_blkio_ticks(tsk, ret);
274 }
275 
_trace_android_vh_delayacct_is_task_waiting_on_io(struct task_struct * p,int * ret)276 void _trace_android_vh_delayacct_is_task_waiting_on_io(struct task_struct *p, int *ret)
277 {
278 	trace_android_vh_delayacct_is_task_waiting_on_io(p, ret);
279 }
280 
_trace_android_vh_delayacct_freepages_start(void)281 void _trace_android_vh_delayacct_freepages_start(void)
282 {
283 	trace_android_vh_delayacct_freepages_start(NULL);
284 }
285 
_trace_android_vh_delayacct_freepages_end(void)286 void _trace_android_vh_delayacct_freepages_end(void)
287 {
288 	trace_android_vh_delayacct_freepages_end(NULL);
289 }
290 
_trace_android_vh_delayacct_thrashing_start(void)291 void _trace_android_vh_delayacct_thrashing_start(void)
292 {
293 	trace_android_vh_delayacct_thrashing_start(NULL);
294 }
295 
_trace_android_vh_delayacct_thrashing_end(void)296 void _trace_android_vh_delayacct_thrashing_end(void)
297 {
298 	trace_android_vh_delayacct_thrashing_end(NULL);
299 }
300 
301 #endif
302 
303