Date:2011-08-02 10:26:09 (8 years 4 months ago)
Author:Maarten ter Huurne
Commit:2604e7f9a98c27be50a0c3ff7503b6a5ea8f6cfe
Message:cpufreq_stats: Support runtime changes to frequency table

Files: drivers/cpufreq/cpufreq_stats.c (12 diffs)

Change Details

drivers/cpufreq/cpufreq_stats.c
2020#include <linux/kobject.h>
2121#include <linux/spinlock.h>
2222#include <linux/notifier.h>
23#include <linux/string.h>
2324#include <asm/cputime.h>
2425
2526static spinlock_t cpufreq_stats_lock;
...... 
3637    unsigned long long last_time;
3738    unsigned int max_state;
3839    unsigned int state_num;
39    unsigned int last_index;
40    int last_index;
4041    cputime64_t *time_in_state;
4142    unsigned int *freq_table;
4243#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
...... 
5960    cur_time = get_jiffies_64();
6061    spin_lock(&cpufreq_stats_lock);
6162    stat = per_cpu(cpufreq_stats_table, cpu);
62    if (stat->time_in_state)
63    if (stat->time_in_state && stat->last_index != -1)
6364        stat->time_in_state[stat->last_index] +=
6465            cur_time - stat->last_time;
6566    stat->last_time = cur_time;
...... 
8182    ssize_t len = 0;
8283    int i;
8384    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
84    if (!stat)
85    if (!stat || !stat->time_in_state)
8586        return 0;
8687    cpufreq_stats_update(stat->cpu);
8788    for (i = 0; i < stat->state_num; i++) {
...... 
99100    int i, j;
100101
101102    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
102    if (!stat)
103    if (!stat || !stat->trans_table)
103104        return 0;
104105    cpufreq_stats_update(stat->cpu);
105106    len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
...... 
158159static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
159160{
160161    int index;
161    for (index = 0; index < stat->max_state; index++)
162        if (stat->freq_table[index] == freq)
163            return index;
162    if (stat->freq_table)
163        for (index = 0; index < stat->max_state; index++)
164            if (stat->freq_table[index] == freq)
165                return index;
164166    return -1;
165167}
166168
167/* should be called late in the CPU removal sequence so that the stats
168 * memory is still available in case someone tries to use it.
169 */
170169static void cpufreq_stats_free_table(unsigned int cpu)
171170{
172171    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
172    struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
173    if (policy && policy->cpu == cpu)
174        sysfs_remove_group(&policy->kobj, &stats_attr_group);
173175    if (stat) {
174176        kfree(stat->time_in_state);
175177        kfree(stat);
176178    }
177179    per_cpu(cpufreq_stats_table, cpu) = NULL;
178}
179
180/* must be called early in the CPU removal sequence (before
181 * cpufreq_remove_dev) so that policy is still valid.
182 */
183static void cpufreq_stats_free_sysfs(unsigned int cpu)
184{
185    struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
186    if (policy && policy->cpu == cpu)
187        sysfs_remove_group(&policy->kobj, &stats_attr_group);
188180    if (policy)
189181        cpufreq_cpu_put(policy);
190182}
191183
192static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
184static int cpufreq_stats_update_table(struct cpufreq_policy *policy,
193185        struct cpufreq_frequency_table *table)
194186{
195    unsigned int i, j, count = 0, ret = 0;
196    struct cpufreq_stats *stat;
197    struct cpufreq_policy *data;
187    unsigned int i, j, count = 0;
198188    unsigned int alloc_size;
199189    unsigned int cpu = policy->cpu;
200    if (per_cpu(cpufreq_stats_table, cpu))
201        return -EBUSY;
202    stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
203    if ((stat) == NULL)
204        return -ENOMEM;
205
206    data = cpufreq_cpu_get(cpu);
207    if (data == NULL) {
208        ret = -EINVAL;
209        goto error_get_fail;
210    }
211
212    ret = sysfs_create_group(&data->kobj, &stats_attr_group);
213    if (ret)
214        goto error_out;
215
216    stat->cpu = cpu;
217    per_cpu(cpufreq_stats_table, cpu) = stat;
190    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
218191
219192    for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
220193        unsigned int freq = table[i].frequency;
...... 
223196        count++;
224197    }
225198
199    if (stat->max_state != count) {
200        stat->max_state = count;
201        kfree(stat->time_in_state);
202        stat->time_in_state = NULL;
203    }
226204    alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
227
228205#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
229206    alloc_size += count * count * sizeof(int);
230207#endif
231    stat->max_state = count;
232    stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
233    if (!stat->time_in_state) {
234        ret = -ENOMEM;
235        goto error_out;
236    }
237    stat->freq_table = (unsigned int *)(stat->time_in_state + count);
238
208    if (stat->time_in_state) {
209        memset(stat->time_in_state, 0, alloc_size);
210    } else {
211        stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
212        if (!stat->time_in_state)
213            return -ENOMEM;
214        stat->freq_table = (unsigned int *)(
215                stat->time_in_state + count);
239216#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
240    stat->trans_table = stat->freq_table + count;
217        stat->trans_table = stat->freq_table + count;
241218#endif
219    }
220
242221    j = 0;
243    for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
244        unsigned int freq = table[i].frequency;
245        if (freq == CPUFREQ_ENTRY_INVALID)
246            continue;
247        if (freq_table_get_index(stat, freq) == -1)
248            stat->freq_table[j++] = freq;
222    if (stat->freq_table) {
223        for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
224            unsigned int freq = table[i].frequency;
225            if (freq == CPUFREQ_ENTRY_INVALID)
226                continue;
227            if (freq_table_get_index(stat, freq) == -1)
228                stat->freq_table[j++] = freq;
229        }
249230    }
250231    stat->state_num = j;
251232    spin_lock(&cpufreq_stats_lock);
252233    stat->last_time = get_jiffies_64();
253234    stat->last_index = freq_table_get_index(stat, policy->cur);
254235    spin_unlock(&cpufreq_stats_lock);
236    return 0;
237}
238
239static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
240        struct cpufreq_frequency_table *table)
241{
242    unsigned int ret = 0;
243    struct cpufreq_stats *stat;
244    struct cpufreq_policy *data;
245    unsigned int cpu = policy->cpu;
246
247    stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
248    if ((stat) == NULL)
249        return -ENOMEM;
250
251    data = cpufreq_cpu_get(cpu);
252    if (data == NULL) {
253        ret = -EINVAL;
254        goto error_out;
255    }
256    ret = sysfs_create_group(&data->kobj, &stats_attr_group);
255257    cpufreq_cpu_put(data);
258    if (ret)
259        goto error_out;
260
261    stat->cpu = cpu;
262    per_cpu(cpufreq_stats_table, cpu) = stat;
263
256264    return 0;
257265error_out:
258    cpufreq_cpu_put(data);
259error_get_fail:
260266    kfree(stat);
261267    per_cpu(cpufreq_stats_table, cpu) = NULL;
262268    return ret;
...... 
274280    table = cpufreq_frequency_get_table(cpu);
275281    if (!table)
276282        return 0;
277    ret = cpufreq_stats_create_table(policy, table);
278    if (ret)
279        return ret;
280    return 0;
283    if (!per_cpu(cpufreq_stats_table, cpu)) {
284        ret = cpufreq_stats_create_table(policy, table);
285        if (ret)
286            return ret;
287    }
288    return cpufreq_stats_update_table(policy, table);
281289}
282290
283291static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
...... 
297305    old_index = stat->last_index;
298306    new_index = freq_table_get_index(stat, freq->new);
299307
300    /* We can't do stat->time_in_state[-1]= .. */
301    if (old_index == -1 || new_index == -1)
302        return 0;
303
304308    cpufreq_stats_update(freq->cpu);
305
306309    if (old_index == new_index)
307310        return 0;
308311
312    if (new_index == -1)
313        return 0;
314
309315    spin_lock(&cpufreq_stats_lock);
310316    stat->last_index = new_index;
317    if (old_index != -1) {
311318#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
312    stat->trans_table[old_index * stat->max_state + new_index]++;
319        if (stat->trans_table)
320            stat->trans_table[old_index * stat->max_state +
321                      new_index]++;
313322#endif
314    stat->total_trans++;
323        stat->total_trans++;
324    }
315325    spin_unlock(&cpufreq_stats_lock);
316326    return 0;
317327}
...... 
327337    case CPU_ONLINE_FROZEN:
328338        cpufreq_update_policy(cpu);
329339        break;
330    case CPU_DOWN_PREPARE:
331        cpufreq_stats_free_sysfs(cpu);
332        break;
333340    case CPU_DEAD:
334341    case CPU_DEAD_FROZEN:
335342        cpufreq_stats_free_table(cpu);
...... 
338345    return NOTIFY_OK;
339346}
340347
341/* priority=1 so this will get called before cpufreq_remove_dev */
342static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
348static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
349{
343350    .notifier_call = cpufreq_stat_cpu_callback,
344    .priority = 1,
345351};
346352
347353static struct notifier_block notifier_policy_block = {
...... 
388394    unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
389395    for_each_online_cpu(cpu) {
390396        cpufreq_stats_free_table(cpu);
391        cpufreq_stats_free_sysfs(cpu);
392397    }
393398}
394399

Archive Download the corresponding diff file



interactive