summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorConnor O'Brien <connoro@google.com>2018-01-22 18:28:08 -0800
committerConnor O'Brien <connoro@google.com>2018-03-06 20:40:13 +0000
commitea0dbcb473aab21f18b4f5e0fe6bb5dd4fc74459 (patch)
tree095418cbc972a43700705ddeab6fe644b44e9963
parent552095deb5650aa958cb29c6ae712728d38c4a5a (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.c49
-rw-r--r--fs/proc/uid.c16
-rw-r--r--include/linux/cpufreq_times.h1
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(