• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* drivers/cpufreq/cpufreq_times.c
2  *
3  * Copyright (C) 2018 Google, Inc.
4  *
5  * This software is licensed under the terms of the GNU General Public
6  * License version 2, as published by the Free Software Foundation, and
7  * may be copied, distributed, and modified under those terms.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  */
15 
16 #include <linux/cpufreq.h>
17 #include <linux/cpufreq_times.h>
18 #include <linux/hashtable.h>
19 #include <linux/init.h>
20 #include <linux/jiffies.h>
21 #include <linux/proc_fs.h>
22 #include <linux/sched.h>
23 #include <linux/seq_file.h>
24 #include <linux/slab.h>
25 #include <linux/spinlock.h>
26 #include <linux/threads.h>
27 
28 #define UID_HASH_BITS 10
29 
30 static DECLARE_HASHTABLE(uid_hash_table, UID_HASH_BITS);
31 
32 static DEFINE_SPINLOCK(task_time_in_state_lock); /* task->time_in_state */
33 static DEFINE_SPINLOCK(uid_lock); /* uid_hash_table */
34 
35 struct concurrent_times {
36 	atomic64_t active[NR_CPUS];
37 	atomic64_t policy[NR_CPUS];
38 };
39 
40 struct uid_entry {
41 	uid_t uid;
42 	unsigned int max_state;
43 	struct hlist_node hash;
44 	struct rcu_head rcu;
45 	struct concurrent_times *concurrent_times;
46 	u64 time_in_state[0];
47 };
48 
49 /**
50  * struct cpu_freqs - per-cpu frequency information
51  * @offset: start of these freqs' stats in task time_in_state array
52  * @max_state: number of entries in freq_table
53  * @last_index: index in freq_table of last frequency switched to
54  * @freq_table: list of available frequencies
55  */
56 struct cpu_freqs {
57 	unsigned int offset;
58 	unsigned int max_state;
59 	unsigned int last_index;
60 	unsigned int freq_table[0];
61 };
62 
63 static struct cpu_freqs *all_freqs[NR_CPUS];
64 
65 static unsigned int next_offset;
66 
67 
68 /* Caller must hold rcu_read_lock() */
find_uid_entry_rcu(uid_t uid)69 static struct uid_entry *find_uid_entry_rcu(uid_t uid)
70 {
71 	struct uid_entry *uid_entry;
72 
73 	hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) {
74 		if (uid_entry->uid == uid)
75 			return uid_entry;
76 	}
77 	return NULL;
78 }
79 
80 /* Caller must hold uid lock */
find_uid_entry_locked(uid_t uid)81 static struct uid_entry *find_uid_entry_locked(uid_t uid)
82 {
83 	struct uid_entry *uid_entry;
84 
85 	hash_for_each_possible(uid_hash_table, uid_entry, hash, uid) {
86 		if (uid_entry->uid == uid)
87 			return uid_entry;
88 	}
89 	return NULL;
90 }
91 
92 /* Caller must hold uid lock */
find_or_register_uid_locked(uid_t uid)93 static struct uid_entry *find_or_register_uid_locked(uid_t uid)
94 {
95 	struct uid_entry *uid_entry, *temp;
96 	struct concurrent_times *times;
97 	unsigned int max_state = READ_ONCE(next_offset);
98 	size_t alloc_size = sizeof(*uid_entry) + max_state *
99 		sizeof(uid_entry->time_in_state[0]);
100 
101 	uid_entry = find_uid_entry_locked(uid);
102 	if (uid_entry) {
103 		if (uid_entry->max_state == max_state)
104 			return uid_entry;
105 		/* uid_entry->time_in_state is too small to track all freqs, so
106 		 * expand it.
107 		 */
108 		temp = __krealloc(uid_entry, alloc_size, GFP_ATOMIC);
109 		if (!temp)
110 			return uid_entry;
111 		temp->max_state = max_state;
112 		memset(temp->time_in_state + uid_entry->max_state, 0,
113 		       (max_state - uid_entry->max_state) *
114 		       sizeof(uid_entry->time_in_state[0]));
115 		if (temp != uid_entry) {
116 			hlist_replace_rcu(&uid_entry->hash, &temp->hash);
117 			kfree_rcu(uid_entry, rcu);
118 		}
119 		return temp;
120 	}
121 
122 	uid_entry = kzalloc(alloc_size, GFP_ATOMIC);
123 	if (!uid_entry)
124 		return NULL;
125 	times = kzalloc(sizeof(*times), GFP_ATOMIC);
126 	if (!times) {
127 		kfree(uid_entry);
128 		return NULL;
129 	}
130 
131 	uid_entry->uid = uid;
132 	uid_entry->max_state = max_state;
133 	uid_entry->concurrent_times = times;
134 
135 	hash_add_rcu(uid_hash_table, &uid_entry->hash, uid);
136 
137 	return uid_entry;
138 }
139 
single_uid_time_in_state_show(struct seq_file * m,void * ptr)140 static int single_uid_time_in_state_show(struct seq_file *m, void *ptr)
141 {
142 	struct uid_entry *uid_entry;
143 	unsigned int i;
144 	uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private);
145 
146 	if (uid == overflowuid)
147 		return -EINVAL;
148 
149 	rcu_read_lock();
150 
151 	uid_entry = find_uid_entry_rcu(uid);
152 	if (!uid_entry) {
153 		rcu_read_unlock();
154 		return 0;
155 	}
156 
157 	for (i = 0; i < uid_entry->max_state; ++i) {
158 		u64 time = nsec_to_clock_t(uid_entry->time_in_state[i]);
159 		seq_write(m, &time, sizeof(time));
160 	}
161 
162 	rcu_read_unlock();
163 
164 	return 0;
165 }
166 
uid_seq_start(struct seq_file * seq,loff_t * pos)167 static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
168 {
169 	if (*pos >= HASH_SIZE(uid_hash_table))
170 		return NULL;
171 
172 	return &uid_hash_table[*pos];
173 }
174 
uid_seq_next(struct seq_file * seq,void * v,loff_t * pos)175 static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
176 {
177 	do {
178 		(*pos)++;
179 
180 		if (*pos >= HASH_SIZE(uid_hash_table))
181 			return NULL;
182 	} while (hlist_empty(&uid_hash_table[*pos]));
183 
184 	return &uid_hash_table[*pos];
185 }
186 
uid_seq_stop(struct seq_file * seq,void * v)187 static void uid_seq_stop(struct seq_file *seq, void *v) { }
188 
uid_time_in_state_seq_show(struct seq_file * m,void * v)189 static int uid_time_in_state_seq_show(struct seq_file *m, void *v)
190 {
191 	struct uid_entry *uid_entry;
192 	struct cpu_freqs *freqs, *last_freqs = NULL;
193 	int i, cpu;
194 
195 	if (v == uid_hash_table) {
196 		seq_puts(m, "uid:");
197 		for_each_possible_cpu(cpu) {
198 			freqs = all_freqs[cpu];
199 			if (!freqs || freqs == last_freqs)
200 				continue;
201 			last_freqs = freqs;
202 			for (i = 0; i < freqs->max_state; i++) {
203 				seq_put_decimal_ull(m, " ",
204 						    freqs->freq_table[i]);
205 			}
206 		}
207 		seq_putc(m, '\n');
208 	}
209 
210 	rcu_read_lock();
211 
212 	hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
213 		if (uid_entry->max_state) {
214 			seq_put_decimal_ull(m, "", uid_entry->uid);
215 			seq_putc(m, ':');
216 		}
217 		for (i = 0; i < uid_entry->max_state; ++i) {
218 			u64 time = nsec_to_clock_t(uid_entry->time_in_state[i]);
219 			seq_put_decimal_ull(m, " ", time);
220 		}
221 		if (uid_entry->max_state)
222 			seq_putc(m, '\n');
223 	}
224 
225 	rcu_read_unlock();
226 	return 0;
227 }
228 
concurrent_time_seq_show(struct seq_file * m,void * v,atomic64_t * (* get_times)(struct concurrent_times *))229 static int concurrent_time_seq_show(struct seq_file *m, void *v,
230 	atomic64_t *(*get_times)(struct concurrent_times *))
231 {
232 	struct uid_entry *uid_entry;
233 	int i, num_possible_cpus = num_possible_cpus();
234 
235 	rcu_read_lock();
236 
237 	hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
238 		atomic64_t *times = get_times(uid_entry->concurrent_times);
239 
240 		seq_put_decimal_ull(m, "", (u64)uid_entry->uid);
241 		seq_putc(m, ':');
242 
243 		for (i = 0; i < num_possible_cpus; ++i) {
244 			u64 time = nsec_to_clock_t(atomic64_read(&times[i]));
245 
246 			seq_put_decimal_ull(m, " ", time);
247 		}
248 		seq_putc(m, '\n');
249 	}
250 
251 	rcu_read_unlock();
252 
253 	return 0;
254 }
255 
get_active_times(struct concurrent_times * times)256 static inline atomic64_t *get_active_times(struct concurrent_times *times)
257 {
258 	return times->active;
259 }
260 
concurrent_active_time_seq_show(struct seq_file * m,void * v)261 static int concurrent_active_time_seq_show(struct seq_file *m, void *v)
262 {
263 	if (v == uid_hash_table) {
264 		seq_put_decimal_ull(m, "cpus: ", num_possible_cpus());
265 		seq_putc(m, '\n');
266 	}
267 
268 	return concurrent_time_seq_show(m, v, get_active_times);
269 }
270 
get_policy_times(struct concurrent_times * times)271 static inline atomic64_t *get_policy_times(struct concurrent_times *times)
272 {
273 	return times->policy;
274 }
275 
concurrent_policy_time_seq_show(struct seq_file * m,void * v)276 static int concurrent_policy_time_seq_show(struct seq_file *m, void *v)
277 {
278 	int i;
279 	struct cpu_freqs *freqs, *last_freqs = NULL;
280 
281 	if (v == uid_hash_table) {
282 		int cnt = 0;
283 
284 		for_each_possible_cpu(i) {
285 			freqs = all_freqs[i];
286 			if (!freqs)
287 				continue;
288 			if (freqs != last_freqs) {
289 				if (last_freqs) {
290 					seq_put_decimal_ull(m, ": ", cnt);
291 					seq_putc(m, ' ');
292 					cnt = 0;
293 				}
294 				seq_put_decimal_ull(m, "policy", i);
295 
296 				last_freqs = freqs;
297 			}
298 			cnt++;
299 		}
300 		if (last_freqs) {
301 			seq_put_decimal_ull(m, ": ", cnt);
302 			seq_putc(m, '\n');
303 		}
304 	}
305 
306 	return concurrent_time_seq_show(m, v, get_policy_times);
307 }
308 
cpufreq_task_times_init(struct task_struct * p)309 void cpufreq_task_times_init(struct task_struct *p)
310 {
311 	unsigned long flags;
312 
313 	spin_lock_irqsave(&task_time_in_state_lock, flags);
314 	p->time_in_state = NULL;
315 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
316 	p->max_state = 0;
317 }
318 
cpufreq_task_times_alloc(struct task_struct * p)319 void cpufreq_task_times_alloc(struct task_struct *p)
320 {
321 	void *temp;
322 	unsigned long flags;
323 	unsigned int max_state = READ_ONCE(next_offset);
324 
325 	/* We use one array to avoid multiple allocs per task */
326 	temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC);
327 	if (!temp)
328 		return;
329 
330 	spin_lock_irqsave(&task_time_in_state_lock, flags);
331 	p->time_in_state = temp;
332 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
333 	p->max_state = max_state;
334 }
335 
336 /* Caller must hold task_time_in_state_lock */
cpufreq_task_times_realloc_locked(struct task_struct * p)337 static int cpufreq_task_times_realloc_locked(struct task_struct *p)
338 {
339 	void *temp;
340 	unsigned int max_state = READ_ONCE(next_offset);
341 
342 	temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC);
343 	if (!temp)
344 		return -ENOMEM;
345 	p->time_in_state = temp;
346 	memset(p->time_in_state + p->max_state, 0,
347 	       (max_state - p->max_state) * sizeof(u64));
348 	p->max_state = max_state;
349 	return 0;
350 }
351 
cpufreq_task_times_exit(struct task_struct * p)352 void cpufreq_task_times_exit(struct task_struct *p)
353 {
354 	unsigned long flags;
355 	void *temp;
356 
357 	if (!p->time_in_state)
358 		return;
359 
360 	spin_lock_irqsave(&task_time_in_state_lock, flags);
361 	temp = p->time_in_state;
362 	p->time_in_state = NULL;
363 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
364 	kfree(temp);
365 }
366 
proc_time_in_state_show(struct seq_file * m,struct pid_namespace * ns,struct pid * pid,struct task_struct * p)367 int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
368 	struct pid *pid, struct task_struct *p)
369 {
370 	unsigned int cpu, i;
371 	u64 cputime;
372 	unsigned long flags;
373 	struct cpu_freqs *freqs;
374 	struct cpu_freqs *last_freqs = NULL;
375 
376 	spin_lock_irqsave(&task_time_in_state_lock, flags);
377 	for_each_possible_cpu(cpu) {
378 		freqs = all_freqs[cpu];
379 		if (!freqs || freqs == last_freqs)
380 			continue;
381 		last_freqs = freqs;
382 
383 		seq_printf(m, "cpu%u\n", cpu);
384 		for (i = 0; i < freqs->max_state; i++) {
385 			cputime = 0;
386 			if (freqs->offset + i < p->max_state &&
387 			    p->time_in_state)
388 				cputime = p->time_in_state[freqs->offset + i];
389 			seq_printf(m, "%u %lu\n", freqs->freq_table[i],
390 				   (unsigned long)nsec_to_clock_t(cputime));
391 		}
392 	}
393 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
394 	return 0;
395 }
396 
cpufreq_acct_update_power(struct task_struct * p,u64 cputime)397 void cpufreq_acct_update_power(struct task_struct *p, u64 cputime)
398 {
399 	unsigned long flags;
400 	unsigned int state;
401 	unsigned int active_cpu_cnt = 0;
402 	unsigned int policy_cpu_cnt = 0;
403 	unsigned int policy_first_cpu;
404 	struct uid_entry *uid_entry;
405 	struct cpu_freqs *freqs = all_freqs[task_cpu(p)];
406 	struct cpufreq_policy *policy;
407 	uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
408 	int cpu = 0;
409 
410 	if (!freqs || is_idle_task(p) || p->flags & PF_EXITING)
411 		return;
412 
413 	state = freqs->offset + READ_ONCE(freqs->last_index);
414 
415 	spin_lock_irqsave(&task_time_in_state_lock, flags);
416 	if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) &&
417 	    p->time_in_state)
418 		p->time_in_state[state] += cputime;
419 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
420 
421 	spin_lock_irqsave(&uid_lock, flags);
422 	uid_entry = find_or_register_uid_locked(uid);
423 	if (uid_entry && state < uid_entry->max_state)
424 		uid_entry->time_in_state[state] += cputime;
425 	spin_unlock_irqrestore(&uid_lock, flags);
426 
427 	rcu_read_lock();
428 	uid_entry = find_uid_entry_rcu(uid);
429 	if (!uid_entry) {
430 		rcu_read_unlock();
431 		return;
432 	}
433 
434 	for_each_possible_cpu(cpu)
435 		if (!idle_cpu(cpu))
436 			++active_cpu_cnt;
437 
438 	atomic64_add(cputime,
439 		     &uid_entry->concurrent_times->active[active_cpu_cnt - 1]);
440 
441 	policy = cpufreq_cpu_get(task_cpu(p));
442 	if (!policy) {
443 		/*
444 		 * This CPU may have just come up and not have a cpufreq policy
445 		 * yet.
446 		 */
447 		rcu_read_unlock();
448 		return;
449 	}
450 
451 	for_each_cpu(cpu, policy->related_cpus)
452 		if (!idle_cpu(cpu))
453 			++policy_cpu_cnt;
454 
455 	policy_first_cpu = cpumask_first(policy->related_cpus);
456 	cpufreq_cpu_put(policy);
457 
458 	atomic64_add(cputime,
459 		     &uid_entry->concurrent_times->policy[policy_first_cpu +
460 							  policy_cpu_cnt - 1]);
461 	rcu_read_unlock();
462 }
463 
cpufreq_times_get_index(struct cpu_freqs * freqs,unsigned int freq)464 static int cpufreq_times_get_index(struct cpu_freqs *freqs, unsigned int freq)
465 {
466 	int index;
467         for (index = 0; index < freqs->max_state; ++index) {
468 		if (freqs->freq_table[index] == freq)
469 			return index;
470         }
471 	return -1;
472 }
473 
cpufreq_times_create_policy(struct cpufreq_policy * policy)474 void cpufreq_times_create_policy(struct cpufreq_policy *policy)
475 {
476 	int cpu, index = 0;
477 	unsigned int count = 0;
478 	struct cpufreq_frequency_table *pos, *table;
479 	struct cpu_freqs *freqs;
480 	void *tmp;
481 
482 	if (all_freqs[policy->cpu])
483 		return;
484 
485 	table = policy->freq_table;
486 	if (!table)
487 		return;
488 
489 	cpufreq_for_each_valid_entry(pos, table)
490 		count++;
491 
492 	tmp =  kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count,
493 		       GFP_KERNEL);
494 	if (!tmp)
495 		return;
496 
497 	freqs = tmp;
498 	freqs->max_state = count;
499 
500 	cpufreq_for_each_valid_entry(pos, table)
501 		freqs->freq_table[index++] = pos->frequency;
502 
503 	index = cpufreq_times_get_index(freqs, policy->cur);
504 	if (index >= 0)
505 		WRITE_ONCE(freqs->last_index, index);
506 
507 	freqs->offset = next_offset;
508 	WRITE_ONCE(next_offset, freqs->offset + count);
509 	for_each_cpu(cpu, policy->related_cpus)
510 		all_freqs[cpu] = freqs;
511 }
512 
uid_entry_reclaim(struct rcu_head * rcu)513 static void uid_entry_reclaim(struct rcu_head *rcu)
514 {
515 	struct uid_entry *uid_entry = container_of(rcu, struct uid_entry, rcu);
516 
517 	kfree(uid_entry->concurrent_times);
518 	kfree(uid_entry);
519 }
520 
cpufreq_task_times_remove_uids(uid_t uid_start,uid_t uid_end)521 void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end)
522 {
523 	struct uid_entry *uid_entry;
524 	struct hlist_node *tmp;
525 	unsigned long flags;
526 
527 	spin_lock_irqsave(&uid_lock, flags);
528 
529 	for (; uid_start <= uid_end; uid_start++) {
530 		hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp,
531 			hash, uid_start) {
532 			if (uid_start == uid_entry->uid) {
533 				hash_del_rcu(&uid_entry->hash);
534 				call_rcu(&uid_entry->rcu, uid_entry_reclaim);
535 			}
536 		}
537 	}
538 
539 	spin_unlock_irqrestore(&uid_lock, flags);
540 }
541 
cpufreq_times_record_transition(struct cpufreq_policy * policy,unsigned int new_freq)542 void cpufreq_times_record_transition(struct cpufreq_policy *policy,
543 	unsigned int new_freq)
544 {
545 	int index;
546 	struct cpu_freqs *freqs = all_freqs[policy->cpu];
547 	if (!freqs)
548 		return;
549 
550 	index = cpufreq_times_get_index(freqs, new_freq);
551 	if (index >= 0)
552 		WRITE_ONCE(freqs->last_index, index);
553 }
554 
555 static const struct seq_operations uid_time_in_state_seq_ops = {
556 	.start = uid_seq_start,
557 	.next = uid_seq_next,
558 	.stop = uid_seq_stop,
559 	.show = uid_time_in_state_seq_show,
560 };
561 
uid_time_in_state_open(struct inode * inode,struct file * file)562 static int uid_time_in_state_open(struct inode *inode, struct file *file)
563 {
564 	return seq_open(file, &uid_time_in_state_seq_ops);
565 }
566 
single_uid_time_in_state_open(struct inode * inode,struct file * file)567 int single_uid_time_in_state_open(struct inode *inode, struct file *file)
568 {
569 	return single_open(file, single_uid_time_in_state_show,
570 			&(inode->i_uid));
571 }
572 
573 static const struct file_operations uid_time_in_state_fops = {
574 	.open		= uid_time_in_state_open,
575 	.read		= seq_read,
576 	.llseek		= seq_lseek,
577 	.release	= seq_release,
578 };
579 
580 static const struct seq_operations concurrent_active_time_seq_ops = {
581 	.start = uid_seq_start,
582 	.next = uid_seq_next,
583 	.stop = uid_seq_stop,
584 	.show = concurrent_active_time_seq_show,
585 };
586 
concurrent_active_time_open(struct inode * inode,struct file * file)587 static int concurrent_active_time_open(struct inode *inode, struct file *file)
588 {
589 	return seq_open(file, &concurrent_active_time_seq_ops);
590 }
591 
592 static const struct file_operations concurrent_active_time_fops = {
593 	.open		= concurrent_active_time_open,
594 	.read		= seq_read,
595 	.llseek		= seq_lseek,
596 	.release	= seq_release,
597 };
598 
599 static const struct seq_operations concurrent_policy_time_seq_ops = {
600 	.start = uid_seq_start,
601 	.next = uid_seq_next,
602 	.stop = uid_seq_stop,
603 	.show = concurrent_policy_time_seq_show,
604 };
605 
concurrent_policy_time_open(struct inode * inode,struct file * file)606 static int concurrent_policy_time_open(struct inode *inode, struct file *file)
607 {
608 	return seq_open(file, &concurrent_policy_time_seq_ops);
609 }
610 
611 static const struct file_operations concurrent_policy_time_fops = {
612 	.open		= concurrent_policy_time_open,
613 	.read		= seq_read,
614 	.llseek		= seq_lseek,
615 	.release	= seq_release,
616 };
617 
cpufreq_times_init(void)618 static int __init cpufreq_times_init(void)
619 {
620 	proc_create_data("uid_time_in_state", 0444, NULL,
621 			 &uid_time_in_state_fops, NULL);
622 
623 	proc_create_data("uid_concurrent_active_time", 0444, NULL,
624 			 &concurrent_active_time_fops, NULL);
625 
626 	proc_create_data("uid_concurrent_policy_time", 0444, NULL,
627 			 &concurrent_policy_time_fops, NULL);
628 
629 	return 0;
630 }
631 
632 early_initcall(cpufreq_times_init);
633