lkml.org 
[lkml]   [2020]   [Sep]   [2]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 1/4] cpufreq: stats: Defer stats update to cpufreq_stats_record_transition()
    Date
    In order to prepare for lock-less stats update, add support to defer any
    updates to it until cpufreq_stats_record_transition() is called.

    Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org>
    ---
    drivers/cpufreq/cpufreq_stats.c | 75 ++++++++++++++++++++++++---------
    1 file changed, 56 insertions(+), 19 deletions(-)

    diff --git a/drivers/cpufreq/cpufreq_stats.c b/drivers/cpufreq/cpufreq_stats.c
    index 94d959a8e954..fdf9e8556a49 100644
    --- a/drivers/cpufreq/cpufreq_stats.c
    +++ b/drivers/cpufreq/cpufreq_stats.c
    @@ -22,17 +22,22 @@ struct cpufreq_stats {
    spinlock_t lock;
    unsigned int *freq_table;
    unsigned int *trans_table;
    +
    + /* Deferred reset */
    + atomic_t reset_pending;
    + unsigned long long reset_time;
    };

    -static void cpufreq_stats_update(struct cpufreq_stats *stats)
    +static void cpufreq_stats_update(struct cpufreq_stats *stats,
    + unsigned long long time)
    {
    unsigned long long cur_time = get_jiffies_64();

    - stats->time_in_state[stats->last_index] += cur_time - stats->last_time;
    + stats->time_in_state[stats->last_index] += cur_time - time;
    stats->last_time = cur_time;
    }

    -static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
    +static void cpufreq_stats_reset_table(struct cpufreq_stats *stats)
    {
    unsigned int count = stats->max_state;

    @@ -41,42 +46,67 @@ static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
    memset(stats->trans_table, 0, count * count * sizeof(int));
    stats->last_time = get_jiffies_64();
    stats->total_trans = 0;
    +
    + /* Adjust for the time elapsed since reset was requested */
    + atomic_set(&stats->reset_pending, 0);
    + cpufreq_stats_update(stats, stats->reset_time);
    spin_unlock(&stats->lock);
    }

    static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
    {
    - return sprintf(buf, "%d\n", policy->stats->total_trans);
    + struct cpufreq_stats *stats = policy->stats;
    +
    + if (atomic_read(&stats->reset_pending))
    + return sprintf(buf, "%d\n", 0);
    + else
    + return sprintf(buf, "%d\n", stats->total_trans);
    }
    cpufreq_freq_attr_ro(total_trans);

    static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
    {
    struct cpufreq_stats *stats = policy->stats;
    + bool pending = atomic_read(&stats->reset_pending);
    + unsigned long long time;
    ssize_t len = 0;
    int i;

    if (policy->fast_switch_enabled)
    return 0;

    - spin_lock(&stats->lock);
    - cpufreq_stats_update(stats);
    - spin_unlock(&stats->lock);
    -
    for (i = 0; i < stats->state_num; i++) {
    + if (pending) {
    + if (i == stats->last_index)
    + time = get_jiffies_64() - stats->reset_time;
    + else
    + time = 0;
    + } else {
    + time = stats->time_in_state[i];
    + if (i == stats->last_index)
    + time += get_jiffies_64() - stats->last_time;
    + }
    +
    len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
    - (unsigned long long)
    - jiffies_64_to_clock_t(stats->time_in_state[i]));
    + jiffies_64_to_clock_t(time));
    }
    return len;
    }
    cpufreq_freq_attr_ro(time_in_state);

    +/* We don't care what is written to the attribute */
    static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
    size_t count)
    {
    - /* We don't care what is written to the attribute. */
    - cpufreq_stats_clear_table(policy->stats);
    + struct cpufreq_stats *stats = policy->stats;
    +
    + /*
    + * Defer resetting of stats to cpufreq_stats_record_transition() to
    + * avoid races.
    + */
    + atomic_set(&stats->reset_pending, 1);
    + stats->reset_time = get_jiffies_64();
    +
    return count;
    }
    cpufreq_freq_attr_wo(reset);
    @@ -84,8 +114,9 @@ cpufreq_freq_attr_wo(reset);
    static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
    {
    struct cpufreq_stats *stats = policy->stats;
    + bool pending = atomic_read(&stats->reset_pending);
    ssize_t len = 0;
    - int i, j;
    + int i, j, count;

    if (policy->fast_switch_enabled)
    return 0;
    @@ -113,8 +144,13 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
    for (j = 0; j < stats->state_num; j++) {
    if (len >= PAGE_SIZE)
    break;
    - len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ",
    - stats->trans_table[i*stats->max_state+j]);
    +
    + if (pending)
    + count = 0;
    + else
    + count = stats->trans_table[i * stats->max_state + j];
    +
    + len += scnprintf(buf + len, PAGE_SIZE - len, "%9u ", count);
    }
    if (len >= PAGE_SIZE)
    break;
    @@ -228,10 +264,11 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
    struct cpufreq_stats *stats = policy->stats;
    int old_index, new_index;

    - if (!stats) {
    - pr_debug("%s: No stats found\n", __func__);
    + if (!stats)
    return;
    - }
    +
    + if (atomic_read(&stats->reset_pending))
    + cpufreq_stats_reset_table(stats);

    old_index = stats->last_index;
    new_index = freq_table_get_index(stats, new_freq);
    @@ -241,7 +278,7 @@ void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
    return;

    spin_lock(&stats->lock);
    - cpufreq_stats_update(stats);
    + cpufreq_stats_update(stats, stats->last_time);

    stats->last_index = new_index;
    stats->trans_table[old_index * stats->max_state + new_index]++;
    --
    2.25.0.rc1.19.g042ed3e048af
    \
     
     \ /
      Last update: 2020-09-02 09:26    [W:7.059 / U:2.520 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site