• 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/cputime.h>
19 #include <linux/hashtable.h>
20 #include <linux/init.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 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 
freq_index_invalid(unsigned int index)140 static bool freq_index_invalid(unsigned int index)
141 {
142 	unsigned int cpu;
143 	struct cpu_freqs *freqs;
144 
145 	for_each_possible_cpu(cpu) {
146 		freqs = all_freqs[cpu];
147 		if (!freqs || index < freqs->offset ||
148 		    freqs->offset + freqs->max_state <= index)
149 			continue;
150 		return freqs->freq_table[index - freqs->offset] ==
151 			CPUFREQ_ENTRY_INVALID;
152 	}
153 	return true;
154 }
155 
single_uid_time_in_state_show(struct seq_file * m,void * ptr)156 static int single_uid_time_in_state_show(struct seq_file *m, void *ptr)
157 {
158 	struct uid_entry *uid_entry;
159 	unsigned int i;
160 	u64 time;
161 	uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private);
162 
163 	if (uid == overflowuid)
164 		return -EINVAL;
165 
166 	rcu_read_lock();
167 
168 	uid_entry = find_uid_entry_rcu(uid);
169 	if (!uid_entry) {
170 		rcu_read_unlock();
171 		return 0;
172 	}
173 
174 	for (i = 0; i < uid_entry->max_state; ++i) {
175 		if (freq_index_invalid(i))
176 			continue;
177 		time = cputime_to_clock_t(uid_entry->time_in_state[i]);
178 		seq_write(m, &time, sizeof(time));
179 	}
180 
181 	rcu_read_unlock();
182 
183 	return 0;
184 }
185 
uid_seq_start(struct seq_file * seq,loff_t * pos)186 static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
187 {
188 	if (*pos >= HASH_SIZE(uid_hash_table))
189 		return NULL;
190 
191 	return &uid_hash_table[*pos];
192 }
193 
uid_seq_next(struct seq_file * seq,void * v,loff_t * pos)194 static void *uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
195 {
196 	(*pos)++;
197 
198 	if (*pos >= HASH_SIZE(uid_hash_table))
199 		return NULL;
200 
201 	return &uid_hash_table[*pos];
202 }
203 
uid_seq_stop(struct seq_file * seq,void * v)204 static void uid_seq_stop(struct seq_file *seq, void *v) { }
205 
uid_time_in_state_seq_show(struct seq_file * m,void * v)206 static int uid_time_in_state_seq_show(struct seq_file *m, void *v)
207 {
208 	struct uid_entry *uid_entry;
209 	struct cpu_freqs *freqs, *last_freqs = NULL;
210 	int i, cpu;
211 
212 	if (v == uid_hash_table) {
213 		seq_puts(m, "uid:");
214 		for_each_possible_cpu(cpu) {
215 			freqs = all_freqs[cpu];
216 			if (!freqs || freqs == last_freqs)
217 				continue;
218 			last_freqs = freqs;
219 			for (i = 0; i < freqs->max_state; i++) {
220 				if (freqs->freq_table[i] ==
221 				    CPUFREQ_ENTRY_INVALID)
222 					continue;
223 				seq_printf(m, " %d", freqs->freq_table[i]);
224 			}
225 		}
226 		seq_putc(m, '\n');
227 	}
228 
229 	rcu_read_lock();
230 
231 	hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
232 		if (uid_entry->max_state)
233 			seq_printf(m, "%d:", uid_entry->uid);
234 		for (i = 0; i < uid_entry->max_state; ++i) {
235 			if (freq_index_invalid(i))
236 				continue;
237 			seq_printf(m, " %lu", (unsigned long)cputime_to_clock_t(
238 					   uid_entry->time_in_state[i]));
239 		}
240 		if (uid_entry->max_state)
241 			seq_putc(m, '\n');
242 	}
243 
244 	rcu_read_unlock();
245 	return 0;
246 }
247 
concurrent_time_seq_show(struct seq_file * m,void * v,atomic64_t * (* get_times)(struct concurrent_times *))248 static int concurrent_time_seq_show(struct seq_file *m, void *v,
249 	atomic64_t *(*get_times)(struct concurrent_times *))
250 {
251 	struct uid_entry *uid_entry;
252 	int i, num_possible_cpus = num_possible_cpus();
253 
254 	rcu_read_lock();
255 
256 	hlist_for_each_entry_rcu(uid_entry, (struct hlist_head *)v, hash) {
257 		atomic64_t *times = get_times(uid_entry->concurrent_times);
258 
259 		seq_put_decimal_ull(m, "", (u64)uid_entry->uid);
260 		seq_putc(m, ':');
261 
262 		for (i = 0; i < num_possible_cpus; ++i) {
263 			u64 time = cputime_to_clock_t(atomic64_read(&times[i]));
264 
265 			seq_put_decimal_ull(m, " ", time);
266 		}
267 		seq_putc(m, '\n');
268 	}
269 
270 	rcu_read_unlock();
271 
272 	return 0;
273 }
274 
get_active_times(struct concurrent_times * times)275 static inline atomic64_t *get_active_times(struct concurrent_times *times)
276 {
277 	return times->active;
278 }
279 
concurrent_active_time_seq_show(struct seq_file * m,void * v)280 static int concurrent_active_time_seq_show(struct seq_file *m, void *v)
281 {
282 	if (v == uid_hash_table) {
283 		seq_put_decimal_ull(m, "cpus: ", num_possible_cpus());
284 		seq_putc(m, '\n');
285 	}
286 
287 	return concurrent_time_seq_show(m, v, get_active_times);
288 }
289 
get_policy_times(struct concurrent_times * times)290 static inline atomic64_t *get_policy_times(struct concurrent_times *times)
291 {
292 	return times->policy;
293 }
294 
concurrent_policy_time_seq_show(struct seq_file * m,void * v)295 static int concurrent_policy_time_seq_show(struct seq_file *m, void *v)
296 {
297 	int i;
298 	struct cpu_freqs *freqs, *last_freqs = NULL;
299 
300 	if (v == uid_hash_table) {
301 		int cnt = 0;
302 
303 		for_each_possible_cpu(i) {
304 			freqs = all_freqs[i];
305 			if (!freqs)
306 				continue;
307 			if (freqs != last_freqs) {
308 				if (last_freqs) {
309 					seq_put_decimal_ull(m, ": ", cnt);
310 					seq_putc(m, ' ');
311 					cnt = 0;
312 				}
313 				seq_put_decimal_ull(m, "policy", i);
314 
315 				last_freqs = freqs;
316 			}
317 			cnt++;
318 		}
319 		if (last_freqs) {
320 			seq_put_decimal_ull(m, ": ", cnt);
321 			seq_putc(m, '\n');
322 		}
323 	}
324 
325 	return concurrent_time_seq_show(m, v, get_policy_times);
326 }
327 
cpufreq_task_times_init(struct task_struct * p)328 void cpufreq_task_times_init(struct task_struct *p)
329 {
330 	unsigned long flags;
331 
332 	spin_lock_irqsave(&task_time_in_state_lock, flags);
333 	p->time_in_state = NULL;
334 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
335 	p->max_state = 0;
336 }
337 
cpufreq_task_times_alloc(struct task_struct * p)338 void cpufreq_task_times_alloc(struct task_struct *p)
339 {
340 	void *temp;
341 	unsigned long flags;
342 	unsigned int max_state = READ_ONCE(next_offset);
343 
344 	/* We use one array to avoid multiple allocs per task */
345 	temp = kcalloc(max_state, sizeof(p->time_in_state[0]), GFP_ATOMIC);
346 	if (!temp)
347 		return;
348 
349 	spin_lock_irqsave(&task_time_in_state_lock, flags);
350 	p->time_in_state = temp;
351 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
352 	p->max_state = max_state;
353 }
354 
355 /* Caller must hold task_time_in_state_lock */
cpufreq_task_times_realloc_locked(struct task_struct * p)356 static int cpufreq_task_times_realloc_locked(struct task_struct *p)
357 {
358 	void *temp;
359 	unsigned int max_state = READ_ONCE(next_offset);
360 
361 	temp = krealloc(p->time_in_state, max_state * sizeof(u64), GFP_ATOMIC);
362 	if (!temp)
363 		return -ENOMEM;
364 	p->time_in_state = temp;
365 	memset(p->time_in_state + p->max_state, 0,
366 	       (max_state - p->max_state) * sizeof(u64));
367 	p->max_state = max_state;
368 	return 0;
369 }
370 
cpufreq_task_times_exit(struct task_struct * p)371 void cpufreq_task_times_exit(struct task_struct *p)
372 {
373 	unsigned long flags;
374 	void *temp;
375 
376 	if (!p->time_in_state)
377 		return;
378 
379 	spin_lock_irqsave(&task_time_in_state_lock, flags);
380 	temp = p->time_in_state;
381 	p->time_in_state = NULL;
382 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
383 	kfree(temp);
384 }
385 
proc_time_in_state_show(struct seq_file * m,struct pid_namespace * ns,struct pid * pid,struct task_struct * p)386 int proc_time_in_state_show(struct seq_file *m, struct pid_namespace *ns,
387 	struct pid *pid, struct task_struct *p)
388 {
389 	unsigned int cpu, i;
390 	cputime_t cputime;
391 	unsigned long flags;
392 	struct cpu_freqs *freqs;
393 	struct cpu_freqs *last_freqs = NULL;
394 
395 	spin_lock_irqsave(&task_time_in_state_lock, flags);
396 	for_each_possible_cpu(cpu) {
397 		freqs = all_freqs[cpu];
398 		if (!freqs || freqs == last_freqs)
399 			continue;
400 		last_freqs = freqs;
401 
402 		seq_printf(m, "cpu%u\n", cpu);
403 		for (i = 0; i < freqs->max_state; i++) {
404 			if (freqs->freq_table[i] == CPUFREQ_ENTRY_INVALID)
405 				continue;
406 			cputime = 0;
407 			if (freqs->offset + i < p->max_state &&
408 			    p->time_in_state)
409 				cputime = p->time_in_state[freqs->offset + i];
410 			seq_printf(m, "%u %lu\n", freqs->freq_table[i],
411 				   (unsigned long)cputime_to_clock_t(cputime));
412 		}
413 	}
414 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
415 	return 0;
416 }
417 
cpufreq_acct_update_power(struct task_struct * p,cputime_t cputime)418 void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime)
419 {
420 	unsigned long flags;
421 	unsigned int state;
422 	unsigned int active_cpu_cnt = 0;
423 	unsigned int policy_cpu_cnt = 0;
424 	unsigned int policy_first_cpu;
425 	struct uid_entry *uid_entry;
426 	struct cpu_freqs *freqs = all_freqs[task_cpu(p)];
427 	struct cpufreq_policy *policy;
428 	uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
429 	int cpu = 0;
430 
431 	if (!freqs || is_idle_task(p) || p->flags & PF_EXITING)
432 		return;
433 
434 	state = freqs->offset + READ_ONCE(freqs->last_index);
435 
436 	spin_lock_irqsave(&task_time_in_state_lock, flags);
437 	if ((state < p->max_state || !cpufreq_task_times_realloc_locked(p)) &&
438 	    p->time_in_state)
439 		p->time_in_state[state] += cputime;
440 	spin_unlock_irqrestore(&task_time_in_state_lock, flags);
441 
442 	spin_lock_irqsave(&uid_lock, flags);
443 	uid_entry = find_or_register_uid_locked(uid);
444 	if (uid_entry && state < uid_entry->max_state)
445 		uid_entry->time_in_state[state] += cputime;
446 	spin_unlock_irqrestore(&uid_lock, flags);
447 
448 	rcu_read_lock();
449 	uid_entry = find_uid_entry_rcu(uid);
450 	if (!uid_entry) {
451 		rcu_read_unlock();
452 		return;
453 	}
454 
455 	for_each_possible_cpu(cpu)
456 		if (!idle_cpu(cpu))
457 			++active_cpu_cnt;
458 
459 	atomic64_add(cputime,
460 		     &uid_entry->concurrent_times->active[active_cpu_cnt - 1]);
461 
462 	policy = cpufreq_cpu_get(task_cpu(p));
463 	if (!policy) {
464 		/*
465 		 * This CPU may have just come up and not have a cpufreq policy
466 		 * yet.
467 		 */
468 		rcu_read_unlock();
469 		return;
470 	}
471 
472 	for_each_cpu(cpu, policy->related_cpus)
473 		if (!idle_cpu(cpu))
474 			++policy_cpu_cnt;
475 
476 	policy_first_cpu = cpumask_first(policy->related_cpus);
477 	cpufreq_cpu_put(policy);
478 
479 	atomic64_add(cputime,
480 		     &uid_entry->concurrent_times->policy[policy_first_cpu +
481 							  policy_cpu_cnt - 1]);
482 	rcu_read_unlock();
483 }
484 
cpufreq_times_create_policy(struct cpufreq_policy * policy)485 void cpufreq_times_create_policy(struct cpufreq_policy *policy)
486 {
487 	int cpu, index;
488 	unsigned int count = 0;
489 	struct cpufreq_frequency_table *pos, *table;
490 	struct cpu_freqs *freqs;
491 	void *tmp;
492 
493 	if (all_freqs[policy->cpu])
494 		return;
495 
496 	table = cpufreq_frequency_get_table(policy->cpu);
497 	if (!table)
498 		return;
499 
500 	cpufreq_for_each_entry(pos, table)
501 		count++;
502 
503 	tmp =  kzalloc(sizeof(*freqs) + sizeof(freqs->freq_table[0]) * count,
504 		       GFP_KERNEL);
505 	if (!tmp)
506 		return;
507 
508 	freqs = tmp;
509 	freqs->max_state = count;
510 
511 	index = cpufreq_frequency_table_get_index(policy, policy->cur);
512 	if (index >= 0)
513 		WRITE_ONCE(freqs->last_index, index);
514 
515 	cpufreq_for_each_entry(pos, table)
516 		freqs->freq_table[pos - table] = pos->frequency;
517 
518 	freqs->offset = next_offset;
519 	WRITE_ONCE(next_offset, freqs->offset + count);
520 	for_each_cpu(cpu, policy->related_cpus)
521 		all_freqs[cpu] = freqs;
522 }
523 
uid_entry_reclaim(struct rcu_head * rcu)524 static void uid_entry_reclaim(struct rcu_head *rcu)
525 {
526 	struct uid_entry *uid_entry = container_of(rcu, struct uid_entry, rcu);
527 
528 	kfree(uid_entry->concurrent_times);
529 	kfree(uid_entry);
530 }
531 
cpufreq_task_times_remove_uids(uid_t uid_start,uid_t uid_end)532 void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end)
533 {
534 	struct uid_entry *uid_entry;
535 	struct hlist_node *tmp;
536 	unsigned long flags;
537 
538 	spin_lock_irqsave(&uid_lock, flags);
539 
540 	for (; uid_start <= uid_end; uid_start++) {
541 		hash_for_each_possible_safe(uid_hash_table, uid_entry, tmp,
542 			hash, uid_start) {
543 			if (uid_start == uid_entry->uid) {
544 				hash_del_rcu(&uid_entry->hash);
545 				call_rcu(&uid_entry->rcu, uid_entry_reclaim);
546 			}
547 		}
548 	}
549 
550 	spin_unlock_irqrestore(&uid_lock, flags);
551 }
552 
cpufreq_times_record_transition(struct cpufreq_freqs * freq)553 void cpufreq_times_record_transition(struct cpufreq_freqs *freq)
554 {
555 	int index;
556 	struct cpu_freqs *freqs = all_freqs[freq->cpu];
557 	struct cpufreq_policy *policy;
558 
559 	if (!freqs)
560 		return;
561 
562 	policy = cpufreq_cpu_get(freq->cpu);
563 	if (!policy)
564 		return;
565 
566 	index = cpufreq_frequency_table_get_index(policy, freq->new);
567 	if (index >= 0)
568 		WRITE_ONCE(freqs->last_index, index);
569 
570 	cpufreq_cpu_put(policy);
571 }
572 
573 static const struct seq_operations uid_time_in_state_seq_ops = {
574 	.start = uid_seq_start,
575 	.next = uid_seq_next,
576 	.stop = uid_seq_stop,
577 	.show = uid_time_in_state_seq_show,
578 };
579 
uid_time_in_state_open(struct inode * inode,struct file * file)580 static int uid_time_in_state_open(struct inode *inode, struct file *file)
581 {
582 	return seq_open(file, &uid_time_in_state_seq_ops);
583 }
584 
single_uid_time_in_state_open(struct inode * inode,struct file * file)585 int single_uid_time_in_state_open(struct inode *inode, struct file *file)
586 {
587 	return single_open(file, single_uid_time_in_state_show,
588 			&(inode->i_uid));
589 }
590 
591 static const struct file_operations uid_time_in_state_fops = {
592 	.open		= uid_time_in_state_open,
593 	.read		= seq_read,
594 	.llseek		= seq_lseek,
595 	.release	= seq_release,
596 };
597 
598 static const struct seq_operations concurrent_active_time_seq_ops = {
599 	.start = uid_seq_start,
600 	.next = uid_seq_next,
601 	.stop = uid_seq_stop,
602 	.show = concurrent_active_time_seq_show,
603 };
604 
concurrent_active_time_open(struct inode * inode,struct file * file)605 static int concurrent_active_time_open(struct inode *inode, struct file *file)
606 {
607 	return seq_open(file, &concurrent_active_time_seq_ops);
608 }
609 
610 static const struct file_operations concurrent_active_time_fops = {
611 	.open		= concurrent_active_time_open,
612 	.read		= seq_read,
613 	.llseek		= seq_lseek,
614 	.release	= seq_release,
615 };
616 
617 static const struct seq_operations concurrent_policy_time_seq_ops = {
618 	.start = uid_seq_start,
619 	.next = uid_seq_next,
620 	.stop = uid_seq_stop,
621 	.show = concurrent_policy_time_seq_show,
622 };
623 
concurrent_policy_time_open(struct inode * inode,struct file * file)624 static int concurrent_policy_time_open(struct inode *inode, struct file *file)
625 {
626 	return seq_open(file, &concurrent_policy_time_seq_ops);
627 }
628 
629 static const struct file_operations concurrent_policy_time_fops = {
630 	.open		= concurrent_policy_time_open,
631 	.read		= seq_read,
632 	.llseek		= seq_lseek,
633 	.release	= seq_release,
634 };
635 
cpufreq_times_init(void)636 static int __init cpufreq_times_init(void)
637 {
638 	proc_create_data("uid_time_in_state", 0444, NULL,
639 			 &uid_time_in_state_fops, NULL);
640 
641 	proc_create_data("uid_concurrent_active_time", 0444, NULL,
642 			 &concurrent_active_time_fops, NULL);
643 
644 	proc_create_data("uid_concurrent_policy_time", 0444, NULL,
645 			 &concurrent_policy_time_fops, NULL);
646 
647 	return 0;
648 }
649 
650 early_initcall(cpufreq_times_init);
651