Date:2011-08-02 10:26:09 (12 years 7 months ago)
Author:Maarten ter Huurne
Commit:2485a5469be6d50b84e03c05654de70f64d4c346
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            cputime64_add(stat->time_in_state[stat->last_index],
6566                      cputime_sub(cur_time, stat->last_time));
...... 
8283    ssize_t len = 0;
8384    int i;
8485    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
85    if (!stat)
86    if (!stat || !stat->time_in_state)
8687        return 0;
8788    cpufreq_stats_update(stat->cpu);
8889    for (i = 0; i < stat->state_num; i++) {
...... 
100101    int i, j;
101102
102103    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, policy->cpu);
103    if (!stat)
104    if (!stat || !stat->trans_table)
104105        return 0;
105106    cpufreq_stats_update(stat->cpu);
106107    len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
...... 
159160static int freq_table_get_index(struct cpufreq_stats *stat, unsigned int freq)
160161{
161162    int index;
162    for (index = 0; index < stat->max_state; index++)
163        if (stat->freq_table[index] == freq)
164            return index;
163    if (stat->freq_table)
164        for (index = 0; index < stat->max_state; index++)
165            if (stat->freq_table[index] == freq)
166                return index;
165167    return -1;
166168}
167169
168/* should be called late in the CPU removal sequence so that the stats
169 * memory is still available in case someone tries to use it.
170 */
171170static void cpufreq_stats_free_table(unsigned int cpu)
172171{
173172    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
173    struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
174    if (policy && policy->cpu == cpu)
175        sysfs_remove_group(&policy->kobj, &stats_attr_group);
174176    if (stat) {
175177        kfree(stat->time_in_state);
176178        kfree(stat);
177179    }
178180    per_cpu(cpufreq_stats_table, cpu) = NULL;
179}
180
181/* must be called early in the CPU removal sequence (before
182 * cpufreq_remove_dev) so that policy is still valid.
183 */
184static void cpufreq_stats_free_sysfs(unsigned int cpu)
185{
186    struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
187    if (policy && policy->cpu == cpu)
188        sysfs_remove_group(&policy->kobj, &stats_attr_group);
189181    if (policy)
190182        cpufreq_cpu_put(policy);
191183}
192184
193static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
185static int cpufreq_stats_update_table(struct cpufreq_policy *policy,
194186        struct cpufreq_frequency_table *table)
195187{
196    unsigned int i, j, count = 0, ret = 0;
197    struct cpufreq_stats *stat;
198    struct cpufreq_policy *data;
188    unsigned int i, j, count = 0;
199189    unsigned int alloc_size;
200190    unsigned int cpu = policy->cpu;
201    if (per_cpu(cpufreq_stats_table, cpu))
202        return -EBUSY;
203    stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
204    if ((stat) == NULL)
205        return -ENOMEM;
206
207    data = cpufreq_cpu_get(cpu);
208    if (data == NULL) {
209        ret = -EINVAL;
210        goto error_get_fail;
211    }
212
213    ret = sysfs_create_group(&data->kobj, &stats_attr_group);
214    if (ret)
215        goto error_out;
216
217    stat->cpu = cpu;
218    per_cpu(cpufreq_stats_table, cpu) = stat;
191    struct cpufreq_stats *stat = per_cpu(cpufreq_stats_table, cpu);
219192
220193    for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
221194        unsigned int freq = table[i].frequency;
...... 
224197        count++;
225198    }
226199
200    if (stat->max_state != count) {
201        stat->max_state = count;
202        kfree(stat->time_in_state);
203        stat->time_in_state = NULL;
204    }
227205    alloc_size = count * sizeof(int) + count * sizeof(cputime64_t);
228
229206#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
230207    alloc_size += count * count * sizeof(int);
231208#endif
232    stat->max_state = count;
233    stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
234    if (!stat->time_in_state) {
235        ret = -ENOMEM;
236        goto error_out;
237    }
238    stat->freq_table = (unsigned int *)(stat->time_in_state + count);
239
209    if (stat->time_in_state) {
210        memset(stat->time_in_state, 0, alloc_size);
211    } else {
212        stat->time_in_state = kzalloc(alloc_size, GFP_KERNEL);
213        if (!stat->time_in_state)
214            return -ENOMEM;
215        stat->freq_table = (unsigned int *)(
216                stat->time_in_state + count);
240217#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
241    stat->trans_table = stat->freq_table + count;
218        stat->trans_table = stat->freq_table + count;
242219#endif
220    }
221
243222    j = 0;
244    for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
245        unsigned int freq = table[i].frequency;
246        if (freq == CPUFREQ_ENTRY_INVALID)
247            continue;
248        if (freq_table_get_index(stat, freq) == -1)
249            stat->freq_table[j++] = freq;
223    if (stat->freq_table) {
224        for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
225            unsigned int freq = table[i].frequency;
226            if (freq == CPUFREQ_ENTRY_INVALID)
227                continue;
228            if (freq_table_get_index(stat, freq) == -1)
229                stat->freq_table[j++] = freq;
230        }
250231    }
251232    stat->state_num = j;
252233    spin_lock(&cpufreq_stats_lock);
253234    stat->last_time = get_jiffies_64();
254235    stat->last_index = freq_table_get_index(stat, policy->cur);
255236    spin_unlock(&cpufreq_stats_lock);
237    return 0;
238}
239
240static int cpufreq_stats_create_table(struct cpufreq_policy *policy,
241        struct cpufreq_frequency_table *table)
242{
243    unsigned int ret = 0;
244    struct cpufreq_stats *stat;
245    struct cpufreq_policy *data;
246    unsigned int cpu = policy->cpu;
247
248    stat = kzalloc(sizeof(struct cpufreq_stats), GFP_KERNEL);
249    if ((stat) == NULL)
250        return -ENOMEM;
251
252    data = cpufreq_cpu_get(cpu);
253    if (data == NULL) {
254        ret = -EINVAL;
255        goto error_out;
256    }
257    ret = sysfs_create_group(&data->kobj, &stats_attr_group);
256258    cpufreq_cpu_put(data);
259    if (ret)
260        goto error_out;
261
262    stat->cpu = cpu;
263    per_cpu(cpufreq_stats_table, cpu) = stat;
264
257265    return 0;
258266error_out:
259    cpufreq_cpu_put(data);
260error_get_fail:
261267    kfree(stat);
262268    per_cpu(cpufreq_stats_table, cpu) = NULL;
263269    return ret;
...... 
275281    table = cpufreq_frequency_get_table(cpu);
276282    if (!table)
277283        return 0;
278    ret = cpufreq_stats_create_table(policy, table);
279    if (ret)
280        return ret;
281    return 0;
284    if (!per_cpu(cpufreq_stats_table, cpu)) {
285        ret = cpufreq_stats_create_table(policy, table);
286        if (ret)
287            return ret;
288    }
289    return cpufreq_stats_update_table(policy, table);
282290}
283291
284292static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
...... 
298306    old_index = stat->last_index;
299307    new_index = freq_table_get_index(stat, freq->new);
300308
301    /* We can't do stat->time_in_state[-1]= .. */
302    if (old_index == -1 || new_index == -1)
303        return 0;
304
305309    cpufreq_stats_update(freq->cpu);
306
307310    if (old_index == new_index)
308311        return 0;
309312
313    if (new_index == -1)
314        return 0;
315
310316    spin_lock(&cpufreq_stats_lock);
311317    stat->last_index = new_index;
318    if (old_index != -1) {
312319#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
313    stat->trans_table[old_index * stat->max_state + new_index]++;
320        if (stat->trans_table)
321            stat->trans_table[old_index * stat->max_state +
322                      new_index]++;
314323#endif
315    stat->total_trans++;
324        stat->total_trans++;
325    }
316326    spin_unlock(&cpufreq_stats_lock);
317327    return 0;
318328}
...... 
328338    case CPU_ONLINE_FROZEN:
329339        cpufreq_update_policy(cpu);
330340        break;
331    case CPU_DOWN_PREPARE:
332        cpufreq_stats_free_sysfs(cpu);
333        break;
334341    case CPU_DEAD:
335342    case CPU_DEAD_FROZEN:
336343        cpufreq_stats_free_table(cpu);
...... 
339346    return NOTIFY_OK;
340347}
341348
342/* priority=1 so this will get called before cpufreq_remove_dev */
343static struct notifier_block cpufreq_stat_cpu_notifier __refdata = {
349static struct notifier_block cpufreq_stat_cpu_notifier __refdata =
350{
344351    .notifier_call = cpufreq_stat_cpu_callback,
345    .priority = 1,
346352};
347353
348354static struct notifier_block notifier_policy_block = {
...... 
389395    unregister_hotcpu_notifier(&cpufreq_stat_cpu_notifier);
390396    for_each_online_cpu(cpu) {
391397        cpufreq_stats_free_table(cpu);
392        cpufreq_stats_free_sysfs(cpu);
393398    }
394399}
395400

Archive Download the corresponding diff file



interactive