OSDN Git Service

ANDROID: cpufreq: Add time_in_state to /proc/uid directories
authorConnor O'Brien <connoro@google.com>
Tue, 23 Jan 2018 02:28:08 +0000 (18:28 -0800)
committerConnor O'Brien <connoro@google.com>
Tue, 3 Apr 2018 18:15:31 +0000 (11:15 -0700)
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
Bug: 70951257
Test: compare values to those reported in /proc/uid_time_in_state
Change-Id: I463039ea7f17b842be4c70024fe772539fe2ce02

drivers/cpufreq/cpufreq_times.c
fs/proc/uid.c
include/linux/cpufreq_times.h

index 67560f7..19cf50b 100644 (file)
@@ -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)
 {
@@ -127,6 +140,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))
@@ -390,6 +433,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,
index 9997ade..4803387 100644 (file)
@@ -2,6 +2,7 @@
  * /proc/uid support
  */
 
+#include <linux/cpufreq_times.h>
 #include <linux/fs.h>
 #include <linux/hashtable.h>
 #include <linux/init.h>
@@ -82,7 +83,20 @@ struct uid_entry {
        .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 = {
        .setattr        = proc_setattr,
index 4966f65..3fb3875 100644 (file)
@@ -29,6 +29,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(