diff options
author | Connor O'Brien <connoro@google.com> | 2018-01-22 18:28:08 -0800 |
---|---|---|
committer | Connor O'Brien <connoro@google.com> | 2018-03-06 20:40:13 +0000 |
commit | ea0dbcb473aab21f18b4f5e0fe6bb5dd4fc74459 (patch) | |
tree | 095418cbc972a43700705ddeab6fe644b44e9963 | |
parent | 552095deb5650aa958cb29c6ae712728d38c4a5a (diff) |
ANDROID: cpufreq: Add time_in_state to /proc/uid directories
Add per-uid files that report the data in binary format rather than
text, to allow faster reading & parsing by userspace.
Signed-off-by: Connor O'Brien <connoro@google.com>
Bug: 72339335
Test: compare values to those reported in /proc/uid_time_in_state
Change-Id: I463039ea7f17b842be4c70024fe772539fe2ce02
-rw-r--r-- | drivers/cpufreq/cpufreq_times.c | 49 | ||||
-rw-r--r-- | fs/proc/uid.c | 16 | ||||
-rw-r--r-- | include/linux/cpufreq_times.h | 1 |
3 files changed, 65 insertions, 1 deletions
diff --git a/drivers/cpufreq/cpufreq_times.c b/drivers/cpufreq/cpufreq_times.c index 8e1a97e5728d..b74017f06a8e 100644 --- a/drivers/cpufreq/cpufreq_times.c +++ b/drivers/cpufreq/cpufreq_times.c @@ -58,6 +58,19 @@ static struct cpu_freqs *all_freqs[NR_CPUS]; static unsigned int next_offset; + +/* Caller must hold rcu_read_lock() */ +static struct uid_entry *find_uid_entry_rcu(uid_t uid) +{ + struct uid_entry *uid_entry; + + hash_for_each_possible_rcu(uid_hash_table, uid_entry, hash, uid) { + if (uid_entry->uid == uid) + return uid_entry; + } + return NULL; +} + /* Caller must hold uid lock */ static struct uid_entry *find_uid_entry_locked(uid_t uid) { @@ -125,6 +138,36 @@ static bool freq_index_invalid(unsigned int index) return true; } +static int single_uid_time_in_state_show(struct seq_file *m, void *ptr) +{ + struct uid_entry *uid_entry; + unsigned int i; + u64 time; + uid_t uid = from_kuid_munged(current_user_ns(), *(kuid_t *)m->private); + + if (uid == overflowuid) + return -EINVAL; + + rcu_read_lock(); + + uid_entry = find_uid_entry_rcu(uid); + if (!uid_entry) { + rcu_read_unlock(); + return 0; + } + + for (i = 0; i < uid_entry->max_state; ++i) { + if (freq_index_invalid(i)) + continue; + time = cputime_to_clock_t(uid_entry->time_in_state[i]); + seq_write(m, &time, sizeof(time)); + } + + rcu_read_unlock(); + + return 0; +} + static void *uid_seq_start(struct seq_file *seq, loff_t *pos) { if (*pos >= HASH_SIZE(uid_hash_table)) @@ -389,6 +432,12 @@ static int uid_time_in_state_open(struct inode *inode, struct file *file) return seq_open(file, &uid_time_in_state_seq_ops); } +int single_uid_time_in_state_open(struct inode *inode, struct file *file) +{ + return single_open(file, single_uid_time_in_state_show, + &(inode->i_uid)); +} + static const struct file_operations uid_time_in_state_fops = { .open = uid_time_in_state_open, .read = seq_read, diff --git a/fs/proc/uid.c b/fs/proc/uid.c index 3c7e87c2a820..c0d439a00560 100644 --- a/fs/proc/uid.c +++ b/fs/proc/uid.c @@ -2,6 +2,7 @@ * /proc/uid support */ +#include <linux/cpufreq_times.h> #include <linux/fs.h> #include <linux/hashtable.h> #include <linux/init.h> @@ -81,7 +82,20 @@ struct uid_entry { .fop = FOP, \ } -static const struct uid_entry uid_base_stuff[] = {}; +#ifdef CONFIG_CPU_FREQ_TIMES +const struct file_operations proc_uid_time_in_state_operations = { + .open = single_uid_time_in_state_open, + .read = seq_read, + .llseek = seq_lseek, + .release = single_release, +}; +#endif + +static const struct uid_entry uid_base_stuff[] = { +#ifdef CONFIG_CPU_FREQ_TIMES + NOD("time_in_state", 0444, NULL, &proc_uid_time_in_state_operations), +#endif +}; const struct inode_operations proc_uid_def_inode_operations = { .setattr = proc_setattr, diff --git a/include/linux/cpufreq_times.h b/include/linux/cpufreq_times.h index 64b94445e872..35c623aa9c1d 100644 --- a/include/linux/cpufreq_times.h +++ b/include/linux/cpufreq_times.h @@ -27,6 +27,7 @@ void cpufreq_acct_update_power(struct task_struct *p, cputime_t cputime); void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_record_transition(struct cpufreq_freqs *freq); void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); +int single_uid_time_in_state_open(struct inode *inode, struct file *file); #else static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_record_transition( |