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
This commit is contained in:
Connor O'Brien 2018-01-22 18:28:08 -08:00 committed by Amit Pundir
parent 3bf5a8aff6
commit d3a225b7a8
3 changed files with 65 additions and 1 deletions

View file

@ -58,6 +58,19 @@ static struct cpu_freqs *all_freqs[NR_CPUS];
static unsigned int next_offset; 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 */ /* Caller must hold uid lock */
static struct uid_entry *find_uid_entry_locked(uid_t uid) static struct uid_entry *find_uid_entry_locked(uid_t uid)
{ {
@ -127,6 +140,36 @@ static bool freq_index_invalid(unsigned int index)
return true; 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 = nsec_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) static void *uid_seq_start(struct seq_file *seq, loff_t *pos)
{ {
if (*pos >= HASH_SIZE(uid_hash_table)) if (*pos >= HASH_SIZE(uid_hash_table))
@ -394,6 +437,12 @@ static int uid_time_in_state_open(struct inode *inode, struct file *file)
return seq_open(file, &uid_time_in_state_seq_ops); 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 = { static const struct file_operations uid_time_in_state_fops = {
.open = uid_time_in_state_open, .open = uid_time_in_state_open,
.read = seq_read, .read = seq_read,

View file

@ -2,6 +2,7 @@
* /proc/uid support * /proc/uid support
*/ */
#include <linux/cpufreq_times.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/init.h> #include <linux/init.h>
@ -82,7 +83,20 @@ struct uid_entry {
.fop = FOP, \ .fop = FOP, \
} }
static const struct uid_entry uid_base_stuff[] = {}; #ifdef CONFIG_CPU_FREQ_TIMES
static 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
};
static const struct inode_operations proc_uid_def_inode_operations = { static const struct inode_operations proc_uid_def_inode_operations = {
.setattr = proc_setattr, .setattr = proc_setattr,

View file

@ -28,6 +28,7 @@ void cpufreq_acct_update_power(struct task_struct *p, u64 cputime);
void cpufreq_times_create_policy(struct cpufreq_policy *policy); void cpufreq_times_create_policy(struct cpufreq_policy *policy);
void cpufreq_times_record_transition(struct cpufreq_freqs *freq); void cpufreq_times_record_transition(struct cpufreq_freqs *freq);
void cpufreq_task_times_remove_uids(uid_t uid_start, uid_t uid_end); 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 #else
static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {} static inline void cpufreq_times_create_policy(struct cpufreq_policy *policy) {}
static inline void cpufreq_times_record_transition( static inline void cpufreq_times_record_transition(