Thanks Viresh, I'm out of the office right now but will look at this more
closely early next year.

There's discussions starting among various folks about how to handle
big.LITTLE and what role cpufreq governors vs. platform code play a part in
that, so all this will probably be something a little longer-term as it
shakes out.  I've also recently added a target_loads attribute that can
pair CPU frequencies with target loads (at speed 200M try for target load
85%, at speed 1.5G try for load 98%...), which may also need adjustment if
the governors manage the little CPUs.  If the little CPUs have CPU
numbers exposed to userspace then maybe these attributes become per-CPU
group instead of global?

Anyhow, lots to think about for big.LITTLE.

Thanks -- Todd


On Thu, Dec 20, 2012 at 8:39 PM, Viresh Kumar <viresh.ku...@linaro.org>wrote:

> Latest big LITTLE systems for ARM SoC's have following kind of ranges of
> freqs:
> LITTLE CPU ranges: x MHz -> y MHz
> big CPU ranges: y + delta -> z MHz
>
> For these, we use hispeed_freq as y MHz, to avoid a switch of clusters from
> LITTLE to big when load burst comes. Similar to non big.LITTLE systems, we
> also
> need to avoid highest OPPs for load bursts and so need another "speed
> breaker".
>
> Hence, we introduce hispeed2_freq here. This would normally be set to z -
> delta
> MHz. For, non big.LITTLE systems if we don't set hispeed2_freq, it would
> be set
> as policy->max frequency. And so, behavior would remain same as existing
> code.
>
> Based on Initial work from Sudeep, hence his SOB.
>
> Signed-off-by: Sudeep KarkadaNagesha <sudeep.karkadanage...@arm.com>
> Signed-off-by: Viresh Kumar <viresh.ku...@linaro.org>
> ---
>  drivers/cpufreq/cpufreq_interactive.c | 119
> +++++++++++++++++++++++++++++++---
>  1 file changed, 111 insertions(+), 8 deletions(-)
>
> diff --git a/drivers/cpufreq/cpufreq_interactive.c
> b/drivers/cpufreq/cpufreq_interactive.c
> index 4dc7f04..0c5bb2c 100644
> --- a/drivers/cpufreq/cpufreq_interactive.c
> +++ b/drivers/cpufreq/cpufreq_interactive.c
> @@ -68,6 +68,13 @@ static unsigned int hispeed_freq;
>  #define DEFAULT_GO_HISPEED_LOAD 85
>  static unsigned long go_hispeed_load;
>
> +/* Hi speed2 to bump to from Hi speed when load bursts over hispeed freq
> */
> +static unsigned int hispeed2_freq;
> +
> +/* Go to hi speed2 when CPU load at or above this value. */
> +#define DEFAULT_GO_HISPEED2_LOAD 95
> +static unsigned long go_hispeed2_load;
> +
>  /* Target load.  Lower values result in higher CPU speeds. */
>  #define DEFAULT_TARGET_LOAD 90
>  static unsigned int default_target_loads[] = {DEFAULT_TARGET_LOAD};
> @@ -88,12 +95,15 @@ static unsigned long min_sample_time;
>  static unsigned long timer_rate;
>
>  /*
> - * Wait this long before raising speed above hispeed, by default a single
> - * timer interval.
> + * Wait this long before raising speed above hispeed/hispeed2, by default
> a
> + * single timer interval.
>   */
>  #define DEFAULT_ABOVE_HISPEED_DELAY DEFAULT_TIMER_RATE
>  static unsigned long above_hispeed_delay_val;
>
> +#define DEFAULT_ABOVE_HISPEED2_DELAY DEFAULT_TIMER_RATE
> +static unsigned long above_hispeed2_delay_val;
> +
>  /* Non-zero means indefinite speed boost active */
>  static int boost_val;
>  /* Duration of a boot pulse in usecs */
> @@ -272,7 +282,7 @@ static void cpufreq_interactive_timer(unsigned long
> data)
>         int cpu_load;
>         struct cpufreq_interactive_cpuinfo *pcpu =
>                 &per_cpu(cpuinfo, data);
> -       unsigned int new_freq;
> +       unsigned int new_freq = 0, min_freq = 0;
>         unsigned int loadadjfreq;
>         unsigned int index;
>         unsigned long flags;
> @@ -301,13 +311,22 @@ static void cpufreq_interactive_timer(unsigned long
> data)
>                 if (pcpu->target_freq < hispeed_freq) {
>                         new_freq = hispeed_freq;
>                 } else {
> -                       new_freq = choose_freq(pcpu, loadadjfreq);
> -
> -                       if (new_freq < hispeed_freq)
> -                               new_freq = hispeed_freq;
> +                       if (cpu_load >= go_hispeed2_load) {
> +                               if (pcpu->target_freq < hispeed2_freq)
> +                                       new_freq = hispeed2_freq;
> +                               else
> +                                       min_freq = hispeed2_freq;
> +                       } else {
> +                               min_freq = hispeed_freq;
> +                       }
>                 }
> -       } else {
> +       }
> +
> +       if (!new_freq) {
>                 new_freq = choose_freq(pcpu, loadadjfreq);
> +
> +               if (new_freq < min_freq)
> +                       new_freq = min_freq;
>         }
>
>         if (pcpu->target_freq >= hispeed_freq &&
> @@ -319,6 +338,15 @@ static void cpufreq_interactive_timer(unsigned long
> data)
>                 goto rearm;
>         }
>
> +       if (pcpu->target_freq >= hispeed2_freq &&
> +           new_freq > pcpu->target_freq &&
> +           now - pcpu->hispeed_validate_time < above_hispeed2_delay_val) {
> +               trace_cpufreq_interactive_notyet(
> +                       data, cpu_load, pcpu->target_freq,
> +                       pcpu->policy->cur, new_freq);
> +               goto rearm;
> +       }
> +
>         pcpu->hispeed_validate_time = now;
>
>         if (cpufreq_frequency_table_target(pcpu->policy, pcpu->freq_table,
> @@ -688,6 +716,51 @@ static ssize_t store_go_hispeed_load(struct kobject
> *kobj,
>  static struct global_attr go_hispeed_load_attr = __ATTR(go_hispeed_load,
> 0644,
>                 show_go_hispeed_load, store_go_hispeed_load);
>
> +static ssize_t show_hispeed2_freq(struct kobject *kobj,
> +                                struct attribute *attr, char *buf)
> +{
> +       return sprintf(buf, "%u\n", hispeed2_freq);
> +}
> +
> +static ssize_t store_hispeed2_freq(struct kobject *kobj,
> +                                 struct attribute *attr, const char *buf,
> +                                 size_t count)
> +{
> +       int ret;
> +       long unsigned int val;
> +
> +       ret = strict_strtoul(buf, 0, &val);
> +       if (ret < 0)
> +               return ret;
> +       hispeed2_freq = val;
> +       return count;
> +}
> +
> +static struct global_attr hispeed2_freq_attr = __ATTR(hispeed2_freq, 0644,
> +               show_hispeed2_freq, store_hispeed2_freq);
> +
> +static ssize_t show_go_hispeed2_load(struct kobject *kobj,
> +                                    struct attribute *attr, char *buf)
> +{
> +       return sprintf(buf, "%lu\n", go_hispeed2_load);
> +}
> +
> +static ssize_t store_go_hispeed2_load(struct kobject *kobj,
> +                       struct attribute *attr, const char *buf, size_t
> count)
> +{
> +       int ret;
> +       unsigned long val;
> +
> +       ret = strict_strtoul(buf, 0, &val);
> +       if (ret < 0)
> +               return ret;
> +       go_hispeed2_load = val;
> +       return count;
> +}
> +
> +static struct global_attr go_hispeed2_load_attr =
> __ATTR(go_hispeed2_load, 0644,
> +               show_go_hispeed2_load, store_go_hispeed2_load);
> +
>  static ssize_t show_min_sample_time(struct kobject *kobj,
>                                 struct attribute *attr, char *buf)
>  {
> @@ -732,6 +805,28 @@ static ssize_t store_above_hispeed_delay(struct
> kobject *kobj,
>
>  define_one_global_rw(above_hispeed_delay);
>
> +static ssize_t show_above_hispeed2_delay(struct kobject *kobj,
> +                                       struct attribute *attr, char *buf)
> +{
> +       return sprintf(buf, "%lu\n", above_hispeed2_delay_val);
> +}
> +
> +static ssize_t store_above_hispeed2_delay(struct kobject *kobj,
> +                                        struct attribute *attr,
> +                                        const char *buf, size_t count)
> +{
> +       int ret;
> +       unsigned long val;
> +
> +       ret = strict_strtoul(buf, 0, &val);
> +       if (ret < 0)
> +               return ret;
> +       above_hispeed2_delay_val = val;
> +       return count;
> +}
> +
> +define_one_global_rw(above_hispeed2_delay);
> +
>  static ssize_t show_timer_rate(struct kobject *kobj,
>                         struct attribute *attr, char *buf)
>  {
> @@ -854,6 +949,9 @@ static struct attribute *interactive_attributes[] = {
>         &hispeed_freq_attr.attr,
>         &go_hispeed_load_attr.attr,
>         &above_hispeed_delay.attr,
> +       &hispeed2_freq_attr.attr,
> +       &go_hispeed2_load_attr.attr,
> +       &above_hispeed2_delay.attr,
>         &min_sample_time_attr.attr,
>         &timer_rate_attr.attr,
>         &timer_slack.attr,
> @@ -906,6 +1004,9 @@ static int cpufreq_governor_interactive(struct
> cpufreq_policy *policy,
>                 if (!hispeed_freq)
>                         hispeed_freq = policy->max;
>
> +               if (!hispeed2_freq || hispeed2_freq > policy->max)
> +                       hispeed2_freq = policy->max;
> +
>                 for_each_cpu(j, policy->cpus) {
>                         unsigned long expires;
>
> @@ -994,6 +1095,8 @@ static int __init cpufreq_interactive_init(void)
>         go_hispeed_load = DEFAULT_GO_HISPEED_LOAD;
>         min_sample_time = DEFAULT_MIN_SAMPLE_TIME;
>         above_hispeed_delay_val = DEFAULT_ABOVE_HISPEED_DELAY;
> +       go_hispeed2_load = DEFAULT_GO_HISPEED2_LOAD;
> +       above_hispeed2_delay_val = DEFAULT_ABOVE_HISPEED2_DELAY;
>         timer_rate = DEFAULT_TIMER_RATE;
>
>         /* Initalize per-cpu timers */
> --
> 1.7.12.rc2.18.g61b472e
>
>
>
_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to