Message ID | 1374146275-5758-3-git-send-email-cw00.choi@samsung.com (mailing list archive) |
---|---|
State | Changes Requested, archived |
Headers | show |
On 18 July 2013 16:47, Chanwoo Choi <cw00.choi@samsung.com> wrote: > diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c > +static int cpufreq_stats_reset_debugfs(struct cpufreq_policy *policy) > +{ > + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); > + int size; > + > + if (!stat) > + return -EINVAL; > + > + if (stat->load_table) > + kfree(stat->load_table); > + stat->load_last_index = 0; > + > + size = sizeof(*stat->load_table) * stat->load_max_index; > + stat->load_table = kzalloc(size, GFP_KERNEL); > + if (!stat->load_table) > + return -ENOMEM; Why are you freeing memory and allocating it again ?? > + return 0; > +} > + > +static int cpufreq_stats_create_debugfs(struct cpufreq_policy *policy) > +{ > + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); > + unsigned int idx, size; > + int ret = 0; > + > + if (!stat) > + return -EINVAL; > + > + if (!policy->cpu_debugfs) > + return -EINVAL; > + > + stat->load_last_index = 0; > + stat->load_max_index = CONFIG_NR_CPU_LOAD_STORAGE; > + > + /* Allocate memory for storage of CPUs load */ > + size = sizeof(*stat->load_table) * stat->load_max_index; > + stat->load_table = kzalloc(size, GFP_KERNEL); > + if (!stat->load_table) > + return -ENOMEM; > + > + /* Create debugfs directory and file for cpufreq */ > + idx = cpumask_weight(policy->cpus) > 1 ? policy->cpu : 0; idx is broken again.. > + stat->debugfs_load_table = debugfs_create_file("load_table", S_IWUSR, > + policy->cpu_debugfs[idx], > + policy, &load_table_fops); > + if (!stat->debugfs_load_table) { > + ret = -ENOMEM; > + goto err; > + } > + > + pr_debug("Creating debugfs file for CPU%d \n", policy->cpu); s/Creating/Created > + > + return 0; > +err: > + kfree(stat->load_table); > + return ret; > +} > + > +/* should be called late in the CPU removal sequence so that the stats > + * memory is still available in case someone tries to use it. > + */ Please write multiline comment correctly.. > +static void cpufreq_stats_free_load_table(unsigned int cpu) > +{ > + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); > + > + if (stat) { > + pr_debug("Free memory of load_table\n"); > + kfree(stat->load_table); > + } > +} > + > +/* must be called early in the CPU removal sequence (before > + * cpufreq_remove_dev) so that policy is still valid. > + */ > +static void cpufreq_stats_free_debugfs(unsigned int cpu) > +{ > + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); > + > + if (stat) { > + pr_debug("Remove load_table debugfs file\n"); > + debugfs_remove(stat->debugfs_load_table); > + } > +} > + > +static void cpufreq_stats_store_load_table(struct cpufreq_freqs *freq, > + unsigned long val) > +{ > + struct cpufreq_stats *stat; > + int cpu, last_idx; > + > + stat = per_cpu(cpufreq_stats_table, freq->cpu); > + if (!stat) > + return; > + > + spin_lock(&cpufreq_stats_lock); > + > + switch (val) { > + case CPUFREQ_POSTCHANGE: > + if (!stat->load_last_index) > + last_idx = stat->load_max_index; > + else > + last_idx = stat->load_last_index - 1; > + > + stat->load_table[last_idx].new = freq->new; > + break; > + case CPUFREQ_LOADCHECK: > + last_idx = stat->load_last_index; > + > + stat->load_table[last_idx].time = freq->time; > + stat->load_table[last_idx].old = freq->old; > + stat->load_table[last_idx].new = freq->old; > + for_each_present_cpu(cpu) > + stat->load_table[last_idx].load[cpu] = freq->load[cpu]; > + > + if (++stat->load_last_index == stat->load_max_index) > + stat->load_last_index = 0; > + break; > + } > + > + spin_unlock(&cpufreq_stats_lock); > +} > + > static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) > { > int index; > @@ -204,7 +386,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, > unsigned int alloc_size; > unsigned int cpu = policy->cpu; > if (per_cpu(cpufreq_stats_table, cpu)) > - return -EBUSY; > + return 0; > stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); > if ((stat) == NULL) > return -ENOMEM; > @@ -257,6 +439,14 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, > spin_lock(&cpufreq_stats_lock); > stat->last_time = get_jiffies_64(); > stat->last_index = freq_table_get_index(stat, policy->cur); > + > + ret = cpufreq_stats_create_debugfs(data); > + if (ret < 0) { > + spin_unlock(&cpufreq_stats_lock); > + ret = -EINVAL; > + goto error_out; > + } > + > spin_unlock(&cpufreq_stats_lock); > cpufreq_cpu_put(data); > return 0; > @@ -297,11 +487,18 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, > if (val != CPUFREQ_NOTIFY) > return 0; > table = cpufreq_frequency_get_table(cpu); > - if (!table) > - return 0; > - ret = cpufreq_stats_create_table(policy, table); > - if (ret) > + if (table) { > + ret = cpufreq_stats_create_table(policy, table); > + if (ret) > + return ret; > + } > + > + ret = cpufreq_stats_reset_debugfs(policy); Why? > + if (ret < 0) { > + pr_debug("Failed to reset CPUs data of debugfs\n"); > return ret; > + } > + > return 0; > } -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Hi Viresh, On 07/22/2013 08:05 PM, Viresh Kumar wrote: > On 18 July 2013 16:47, Chanwoo Choi <cw00.choi@samsung.com> wrote: >> diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c > >> +static int cpufreq_stats_reset_debugfs(struct cpufreq_policy *policy) >> +{ >> + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); >> + int size; >> + >> + if (!stat) >> + return -EINVAL; >> + >> + if (stat->load_table) >> + kfree(stat->load_table); >> + stat->load_last_index = 0; >> + >> + size = sizeof(*stat->load_table) * stat->load_max_index; >> + stat->load_table = kzalloc(size, GFP_KERNEL); >> + if (!stat->load_table) >> + return -ENOMEM; > > Why are you freeing memory and allocating it again ?? This purpose is reseting the data of stat->load_table. If you don't agree this, I'll initizliae stat->load_table array as zero(0) with loop statement. > >> + return 0; >> +} >> + >> +static int cpufreq_stats_create_debugfs(struct cpufreq_policy *policy) >> +{ >> + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); >> + unsigned int idx, size; >> + int ret = 0; >> + >> + if (!stat) >> + return -EINVAL; >> + >> + if (!policy->cpu_debugfs) >> + return -EINVAL; >> + >> + stat->load_last_index = 0; >> + stat->load_max_index = CONFIG_NR_CPU_LOAD_STORAGE; >> + >> + /* Allocate memory for storage of CPUs load */ >> + size = sizeof(*stat->load_table) * stat->load_max_index; >> + stat->load_table = kzalloc(size, GFP_KERNEL); >> + if (!stat->load_table) >> + return -ENOMEM; >> + >> + /* Create debugfs directory and file for cpufreq */ >> + idx = cpumask_weight(policy->cpus) > 1 ? policy->cpu : 0; > > idx is broken again.. OK, I'll fix it. > >> + stat->debugfs_load_table = debugfs_create_file("load_table", S_IWUSR, >> + policy->cpu_debugfs[idx], >> + policy, &load_table_fops); >> + if (!stat->debugfs_load_table) { >> + ret = -ENOMEM; >> + goto err; >> + } >> + >> + pr_debug("Creating debugfs file for CPU%d \n", policy->cpu); > > s/Creating/Created OK, I'll fixt it. > >> + >> + return 0; >> +err: >> + kfree(stat->load_table); >> + return ret; >> +} >> + >> +/* should be called late in the CPU removal sequence so that the stats >> + * memory is still available in case someone tries to use it. >> + */ > > Please write multiline comment correctly.. OK. > >> +static void cpufreq_stats_free_load_table(unsigned int cpu) >> +{ >> + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); >> + >> + if (stat) { >> + pr_debug("Free memory of load_table\n"); >> + kfree(stat->load_table); >> + } >> +} >> + >> +/* must be called early in the CPU removal sequence (before >> + * cpufreq_remove_dev) so that policy is still valid. >> + */ >> +static void cpufreq_stats_free_debugfs(unsigned int cpu) >> +{ >> + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); >> + >> + if (stat) { >> + pr_debug("Remove load_table debugfs file\n"); >> + debugfs_remove(stat->debugfs_load_table); >> + } >> +} >> + >> +static void cpufreq_stats_store_load_table(struct cpufreq_freqs *freq, >> + unsigned long val) >> +{ >> + struct cpufreq_stats *stat; >> + int cpu, last_idx; >> + >> + stat = per_cpu(cpufreq_stats_table, freq->cpu); >> + if (!stat) >> + return; >> + >> + spin_lock(&cpufreq_stats_lock); >> + >> + switch (val) { >> + case CPUFREQ_POSTCHANGE: >> + if (!stat->load_last_index) >> + last_idx = stat->load_max_index; >> + else >> + last_idx = stat->load_last_index - 1; >> + >> + stat->load_table[last_idx].new = freq->new; >> + break; >> + case CPUFREQ_LOADCHECK: >> + last_idx = stat->load_last_index; >> + >> + stat->load_table[last_idx].time = freq->time; >> + stat->load_table[last_idx].old = freq->old; >> + stat->load_table[last_idx].new = freq->old; >> + for_each_present_cpu(cpu) >> + stat->load_table[last_idx].load[cpu] = freq->load[cpu]; >> + >> + if (++stat->load_last_index == stat->load_max_index) >> + stat->load_last_index = 0; >> + break; >> + } >> + >> + spin_unlock(&cpufreq_stats_lock); >> +} >> + >> static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) >> { >> int index; >> @@ -204,7 +386,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, >> unsigned int alloc_size; >> unsigned int cpu = policy->cpu; >> if (per_cpu(cpufreq_stats_table, cpu)) >> - return -EBUSY; >> + return 0; >> stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); >> if ((stat) == NULL) >> return -ENOMEM; >> @@ -257,6 +439,14 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, >> spin_lock(&cpufreq_stats_lock); >> stat->last_time = get_jiffies_64(); >> stat->last_index = freq_table_get_index(stat, policy->cur); >> + >> + ret = cpufreq_stats_create_debugfs(data); >> + if (ret < 0) { >> + spin_unlock(&cpufreq_stats_lock); >> + ret = -EINVAL; >> + goto error_out; >> + } >> + >> spin_unlock(&cpufreq_stats_lock); >> cpufreq_cpu_put(data); >> return 0; >> @@ -297,11 +487,18 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, >> if (val != CPUFREQ_NOTIFY) >> return 0; >> table = cpufreq_frequency_get_table(cpu); >> - if (!table) >> - return 0; >> - ret = cpufreq_stats_create_table(policy, table); >> - if (ret) >> + if (table) { >> + ret = cpufreq_stats_create_table(policy, table); >> + if (ret) >> + return ret; >> + } >> + >> + ret = cpufreq_stats_reset_debugfs(policy); > > Why? When cpufreq governor is changed, always reset stats->load_table for performance/powersave/userspace governor. -sh-4.1# cat /sys/kernel/debug/cpufreq/cpu0/load_table Time(ms) Old Freq(Hz) New Freq(Hz) CPU0 CPU1 CPU3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 > >> + if (ret < 0) { >> + pr_debug("Failed to reset CPUs data of debugfs\n"); >> return ret; >> + } >> + >> return 0; >> } > Thanks for your comment. Best Regards, Chanwoo Choi -- To unsubscribe from this list: send the line "unsubscribe linux-pm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig index 534fcb8..5c3f406 100644 --- a/drivers/cpufreq/Kconfig +++ b/drivers/cpufreq/Kconfig @@ -36,6 +36,12 @@ config CPU_FREQ_STAT If in doubt, say N. +config NR_CPU_LOAD_STORAGE + int "Maximum storage size to save CPU load (10-1000)" + range 10 1000 + depends on CPU_FREQ_STAT + default "10" + config CPU_FREQ_STAT_DETAILS bool "CPU frequency translation statistics details" depends on CPU_FREQ_STAT diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index 924d654..cb68873 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c @@ -293,6 +293,10 @@ void __cpufreq_notify_transition(struct cpufreq_policy *policy, if (likely(policy) && likely(policy->cpu == freqs->cpu)) policy->cur = freqs->new; break; + case CPUFREQ_LOADCHECK: + srcu_notifier_call_chain(&cpufreq_transition_notifier_list, + CPUFREQ_LOADCHECK, freqs); + break; } } /** diff --git a/drivers/cpufreq/cpufreq_governor.c b/drivers/cpufreq/cpufreq_governor.c index dc9b72e..decabcb 100644 --- a/drivers/cpufreq/cpufreq_governor.c +++ b/drivers/cpufreq/cpufreq_governor.c @@ -87,6 +87,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) struct od_dbs_tuners *od_tuners = dbs_data->tuners; struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; struct cpufreq_policy *policy; +#ifdef CONFIG_CPU_FREQ_STAT + struct cpufreq_freqs freq = {0}; +#endif unsigned int max_load = 0; unsigned int ignore_nice; unsigned int j; @@ -148,6 +151,9 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) continue; load = 100 * (wall_time - idle_time) / wall_time; +#ifdef CONFIG_CPU_FREQ_STAT + freq.load[j] = load; +#endif if (dbs_data->cdata->governor == GOV_ONDEMAND) { int freq_avg = __cpufreq_driver_getavg(policy, j); @@ -161,6 +167,14 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) max_load = load; } +#ifdef CONFIG_CPU_FREQ_STAT + freq.time = ktime_to_ms(ktime_get()); + freq.old = policy->cur; + freq.cpu = policy->cpu; + + cpufreq_notify_transition(policy, &freq, CPUFREQ_LOADCHECK); +#endif + dbs_data->cdata->gov_check_cpu(cpu, max_load); } EXPORT_SYMBOL_GPL(dbs_check_cpu); diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c index fb65dec..fd171ba 100644 --- a/drivers/cpufreq/cpufreq_stats.c +++ b/drivers/cpufreq/cpufreq_stats.c @@ -12,6 +12,7 @@ #include <linux/kernel.h> #include <linux/slab.h> #include <linux/cpu.h> +#include <linux/debugfs.h> #include <linux/sysfs.h> #include <linux/cpufreq.h> #include <linux/module.h> @@ -36,6 +37,12 @@ struct cpufreq_stats { #ifdef CONFIG_CPU_FREQ_STAT_DETAILS unsigned int *trans_table; #endif + + /* Debugfs file for load_table */ + struct cpufreq_freqs *load_table; + unsigned int load_last_index; + unsigned int load_max_index; + struct dentry *debugfs_load_table; }; static DEFINE_PER_CPU(struct cpufreq_stats *, cpufreq_stats_table); @@ -149,6 +156,181 @@ static struct attribute_group stats_attr_group = { .name = "stats" }; +#define MAX_LINE_SIZE 255 +static ssize_t load_table_read(struct file *file, char __user *user_buf, + size_t count, loff_t *ppos) +{ + struct cpufreq_policy *policy = file->private_data; + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); + struct cpufreq_freqs *load_table = stat->load_table; + ssize_t len = 0; + char *buf; + int i, cpu, ret; + + buf = kzalloc(MAX_LINE_SIZE * stat->load_max_index, GFP_KERNEL); + if (!buf) + return 0; + + spin_lock(&cpufreq_stats_lock); + len += sprintf(buf + len, "%-10s %-12s %-12s ", "Time(ms)", + "Old Freq(Hz)", + "New Freq(Hz)"); + for_each_cpu(cpu, policy->cpus) + len += sprintf(buf + len, "%3s%d ", "CPU", cpu); + len += sprintf(buf + len, "\n"); + + i = stat->load_last_index; + do { + len += sprintf(buf + len, "%-10lld %-12d %-12d ", + load_table[i].time, + load_table[i].old, + load_table[i].new); + + for_each_cpu(cpu, policy->cpus) + len += sprintf(buf + len, "%-4d ", + load_table[i].load[cpu]); + len += sprintf(buf + len, "\n"); + + if (++i == stat->load_max_index) + i = 0; + } while (i != stat->load_last_index); + spin_unlock(&cpufreq_stats_lock); + + ret = simple_read_from_buffer(user_buf, count, ppos, buf, len); + kfree(buf); + + return ret; +} + +static const struct file_operations load_table_fops = { + .read = load_table_read, + .open = simple_open, + .llseek = no_llseek, +}; + +static int cpufreq_stats_reset_debugfs(struct cpufreq_policy *policy) +{ + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); + int size; + + if (!stat) + return -EINVAL; + + if (stat->load_table) + kfree(stat->load_table); + stat->load_last_index = 0; + + size = sizeof(*stat->load_table) * stat->load_max_index; + stat->load_table = kzalloc(size, GFP_KERNEL); + if (!stat->load_table) + return -ENOMEM; + + return 0; +} + +static int cpufreq_stats_create_debugfs(struct cpufreq_policy *policy) +{ + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu); + unsigned int idx, size; + int ret = 0; + + if (!stat) + return -EINVAL; + + if (!policy->cpu_debugfs) + return -EINVAL; + + stat->load_last_index = 0; + stat->load_max_index = CONFIG_NR_CPU_LOAD_STORAGE; + + /* Allocate memory for storage of CPUs load */ + size = sizeof(*stat->load_table) * stat->load_max_index; + stat->load_table = kzalloc(size, GFP_KERNEL); + if (!stat->load_table) + return -ENOMEM; + + /* Create debugfs directory and file for cpufreq */ + idx = cpumask_weight(policy->cpus) > 1 ? policy->cpu : 0; + stat->debugfs_load_table = debugfs_create_file("load_table", S_IWUSR, + policy->cpu_debugfs[idx], + policy, &load_table_fops); + if (!stat->debugfs_load_table) { + ret = -ENOMEM; + goto err; + } + + pr_debug("Creating debugfs file for CPU%d \n", policy->cpu); + + return 0; +err: + kfree(stat->load_table); + return ret; +} + +/* should be called late in the CPU removal sequence so that the stats + * memory is still available in case someone tries to use it. + */ +static void cpufreq_stats_free_load_table(unsigned int cpu) +{ + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); + + if (stat) { + pr_debug("Free memory of load_table\n"); + kfree(stat->load_table); + } +} + +/* must be called early in the CPU removal sequence (before + * cpufreq_remove_dev) so that policy is still valid. + */ +static void cpufreq_stats_free_debugfs(unsigned int cpu) +{ + struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu); + + if (stat) { + pr_debug("Remove load_table debugfs file\n"); + debugfs_remove(stat->debugfs_load_table); + } +} + +static void cpufreq_stats_store_load_table(struct cpufreq_freqs *freq, + unsigned long val) +{ + struct cpufreq_stats *stat; + int cpu, last_idx; + + stat = per_cpu(cpufreq_stats_table, freq->cpu); + if (!stat) + return; + + spin_lock(&cpufreq_stats_lock); + + switch (val) { + case CPUFREQ_POSTCHANGE: + if (!stat->load_last_index) + last_idx = stat->load_max_index; + else + last_idx = stat->load_last_index - 1; + + stat->load_table[last_idx].new = freq->new; + break; + case CPUFREQ_LOADCHECK: + last_idx = stat->load_last_index; + + stat->load_table[last_idx].time = freq->time; + stat->load_table[last_idx].old = freq->old; + stat->load_table[last_idx].new = freq->old; + for_each_present_cpu(cpu) + stat->load_table[last_idx].load[cpu] = freq->load[cpu]; + + if (++stat->load_last_index == stat->load_max_index) + stat->load_last_index = 0; + break; + } + + spin_unlock(&cpufreq_stats_lock); +} + static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq) { int index; @@ -204,7 +386,7 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, unsigned int alloc_size; unsigned int cpu = policy->cpu; if (per_cpu(cpufreq_stats_table, cpu)) - return -EBUSY; + return 0; stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL); if ((stat) == NULL) return -ENOMEM; @@ -257,6 +439,14 @@ static int cpufreq_stats_create_table(struct cpufreq_policy *policy, spin_lock(&cpufreq_stats_lock); stat->last_time = get_jiffies_64(); stat->last_index = freq_table_get_index(stat, policy->cur); + + ret = cpufreq_stats_create_debugfs(data); + if (ret < 0) { + spin_unlock(&cpufreq_stats_lock); + ret = -EINVAL; + goto error_out; + } + spin_unlock(&cpufreq_stats_lock); cpufreq_cpu_put(data); return 0; @@ -297,11 +487,18 @@ static int cpufreq_stat_notifier_policy(struct notifier_block *nb, if (val != CPUFREQ_NOTIFY) return 0; table = cpufreq_frequency_get_table(cpu); - if (!table) - return 0; - ret = cpufreq_stats_create_table(policy, table); - if (ret) + if (table) { + ret = cpufreq_stats_create_table(policy, table); + if (ret) + return ret; + } + + ret = cpufreq_stats_reset_debugfs(policy); + if (ret < 0) { + pr_debug("Failed to reset CPUs data of debugfs\n"); return ret; + } + return 0; } @@ -312,32 +509,40 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, struct cpufreq_stats *stat; int old_index, new_index; - if (val != CPUFREQ_POSTCHANGE) - return 0; + switch (val) { + case CPUFREQ_POSTCHANGE: + stat = per_cpu(cpufreq_stats_table, freq->cpu); + if (!stat) + return 0; - stat = per_cpu(cpufreq_stats_table, freq->cpu); - if (!stat) - return 0; + old_index = stat->last_index; + new_index = freq_table_get_index(stat, freq->new); - old_index = stat->last_index; - new_index = freq_table_get_index(stat, freq->new); + /* We can't do stat->time_in_state[-1]= .. */ + if (old_index == -1 || new_index == -1) + return 0; - /* We can't do stat->time_in_state[-1]= .. */ - if (old_index == -1 || new_index == -1) - return 0; + cpufreq_stats_update(freq->cpu); - cpufreq_stats_update(freq->cpu); + if (old_index == new_index) + return 0; - if (old_index == new_index) - return 0; - - spin_lock(&cpufreq_stats_lock); - stat->last_index = new_index; + spin_lock(&cpufreq_stats_lock); + stat->last_index = new_index; #ifdef CONFIG_CPU_FREQ_STAT_DETAILS - stat->trans_table[old_index * stat->max_state + new_index]++; + stat->trans_table[old_index * stat->max_state + new_index]++; #endif - stat->total_trans++; - spin_unlock(&cpufreq_stats_lock); + stat->total_trans++; + spin_unlock(&cpufreq_stats_lock); + + cpufreq_stats_store_load_table(freq, CPUFREQ_POSTCHANGE); + + break; + case CPUFREQ_LOADCHECK: + cpufreq_stats_store_load_table(freq, CPUFREQ_LOADCHECK); + break; + } + return 0; } @@ -352,12 +557,16 @@ static int __cpuinit cpufreq_stat_cpu_callback(struct notifier_block *nfb, cpufreq_update_policy(cpu); break; case CPU_DOWN_PREPARE: + cpufreq_stats_free_debugfs(cpu); cpufreq_stats_free_sysfs(cpu); break; case CPU_DEAD: + cpufreq_stats_free_load_table(cpu); cpufreq_stats_free_table(cpu); break; case CPU_UP_CANCELED_FROZEN: + cpufreq_stats_free_debugfs(cpu); + cpufreq_stats_free_load_table(cpu); cpufreq_stats_free_sysfs(cpu); cpufreq_stats_free_table(cpu); break; @@ -418,6 +627,7 @@ static void __exit cpufreq_stats_exit(void) unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier); for_each_online_cpu(cpu) { cpufreq_stats_free_table(cpu); + cpufreq_stats_free_debugfs(cpu); cpufreq_stats_free_sysfs(cpu); } } diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h index 825f379..4d0a4fd 100644 --- a/include/linux/cpufreq.h +++ b/include/linux/cpufreq.h @@ -141,12 +141,18 @@ static inline bool policy_is_shared(struct cpufreq_policy *policy) #define CPUFREQ_POSTCHANGE (1) #define CPUFREQ_RESUMECHANGE (8) #define CPUFREQ_SUSPENDCHANGE (9) +#define CPUFREQ_LOADCHECK (10) struct cpufreq_freqs { unsigned int cpu; /* cpu nr */ unsigned int old; unsigned int new; u8 flags; /* flags of cpufreq_driver, see below. */ + +#ifdef CONFIG_CPU_FREQ_STAT + int64_t time; + unsigned int load[NR_CPUS]; +#endif };