diff options
author | Wen Yi <wyi@nvidia.com> | 2012-06-12 12:01:11 -0700 |
---|---|---|
committer | Simone Willett <swillett@nvidia.com> | 2012-07-01 09:15:23 -0700 |
commit | 69f4a0f9adb0d8f82b920ceffcc40f7bd770c2e2 (patch) | |
tree | 282ae29b0961e6b99b02e1235f32bac2a25039e6 /arch/arm/mach-tegra | |
parent | 1802afb2ad9ee1b6c1e11207f3fcdd3a56a1e0f0 (diff) |
ARM: tegra: power: Use runnable threads average for hotplug
Sample scheduler runnable threads average in auto-hotplug work
function and use it to determine the auto-hotplug target for number
of on-line cores. Use cpu up delay as sampling period, and enforce
down delay by checking last cpu configuration change time stamp.
Bug 958978
Change-Id: I4280a11d39914687e6ffaa6f38df594d10aedaa9
Signed-off-by: Alex Frid <afrid@nvidia.com>
(cherry picked from commit 507e2ef5e4f09b23de2e924003dba259d3c8bc3c)
Reviewed-on: http://git-master/r/111638
Reviewed-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Tested-by: Sai Gurrappadi <sgurrappadi@nvidia.com>
Reviewed-by: Automatic_Commit_Validation_User
Reviewed-by: Peter Boonstoppel <pboonstoppel@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra')
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 47 |
1 files changed, 39 insertions, 8 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index 5b9ac4f770a2..01b954625e54 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -73,6 +73,8 @@ static struct clk *cpu_clk; static struct clk *cpu_g_clk; static struct clk *cpu_lp_clk; +static unsigned long last_change_time; + static struct { cputime64_t time_up_total; u64 last_update; @@ -186,6 +188,14 @@ enum { TEGRA_CPU_SPEED_SKEWED, }; +#define NR_FSHIFT 2 +static unsigned int nr_run_thresholds[] = { +/* 1, 2, 3, 4 - on-line cpus target */ + 5, 9, 13, UINT_MAX /* avg run threads * 4 (e.g., 9 = 2.25 threads) */ +}; +static unsigned int nr_run_hysteresis = 2; /* 0.5 thread */ +static unsigned int nr_run_last; + static noinline int tegra_cpu_speed_balance(void) { unsigned long highest_speed = tegra_cpu_highest_speed(); @@ -194,17 +204,36 @@ static noinline int tegra_cpu_speed_balance(void) unsigned int nr_cpus = num_online_cpus(); unsigned int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4; unsigned int min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS); + unsigned int avg_nr_run = avg_nr_running(); + unsigned int nr_run; + + /* Evaluate: + * - distribution of freq targets for already on-lined CPUs + * - average number of runnable threads + * - effective MIPS available within EDP frequency limits, + * and return: + * TEGRA_CPU_SPEED_BALANCED to bring one more CPU core on-line + * TEGRA_CPU_SPEED_BIASED to keep CPU core composition unchanged + * TEGRA_CPU_SPEED_SKEWED to remove CPU core off-line + */ + for (nr_run = 1; nr_run < ARRAY_SIZE(nr_run_thresholds); nr_run++) { + unsigned int nr_threshold = nr_run_thresholds[nr_run - 1]; + if (nr_run_last <= nr_run) + nr_threshold += nr_run_hysteresis; + if (avg_nr_run <= (nr_threshold << (FSHIFT - NR_FSHIFT))) + break; + } + nr_run_last = nr_run; - /* balanced: freq targets for all CPUs are above 50% of highest speed - biased: freq target for at least one CPU is below 50% threshold - skewed: freq targets for at least 2 CPUs are below 25% threshold */ if (((tegra_count_slow_cpus(skewed_speed) >= 2) || + (nr_run < nr_cpus) || tegra_cpu_edp_favor_down(nr_cpus, mp_overhead) || (highest_speed <= idle_bottom_freq) || (nr_cpus > max_cpus)) && (nr_cpus > min_cpus)) return TEGRA_CPU_SPEED_SKEWED; if (((tegra_count_slow_cpus(balanced_speed) >= 1) || + (nr_run <= nr_cpus) || (!tegra_cpu_edp_favor_up(nr_cpus, mp_overhead)) || (highest_speed <= idle_bottom_freq) || (nr_cpus == max_cpus)) && (nr_cpus >= min_cpus)) @@ -218,7 +247,6 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) bool up = false; unsigned int cpu = nr_cpu_ids; unsigned long now = jiffies; - static unsigned long last_change_time; mutex_lock(tegra3_cpu_lock); @@ -231,7 +259,8 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) if (cpu < nr_cpu_ids) { up = false; } else if (!is_lp_cluster() && !no_lp && - !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS)) { + !pm_qos_request(PM_QOS_MIN_ONLINE_CPUS) && + ((now - last_change_time) >= down_delay)) { if(!clk_set_parent(cpu_clk, cpu_lp_clk)) { hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); @@ -241,11 +270,12 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) } } queue_delayed_work( - hotplug_wq, &hotplug_work, down_delay); + hotplug_wq, &hotplug_work, up2gn_delay); break; case TEGRA_HP_UP: if (is_lp_cluster() && !no_lp) { if(!clk_set_parent(cpu_clk, cpu_g_clk)) { + last_change_time = now; hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ @@ -307,6 +337,7 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p) tegra_update_cpu_speed(speed); if (!clk_set_parent(cpu_clk, cpu_g_clk)) { + last_change_time = jiffies; hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); } @@ -372,7 +403,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend) } else if (cpu_freq <= bottom_freq) { hp_state = TEGRA_HP_DOWN; queue_delayed_work( - hotplug_wq, &hotplug_work, down_delay); + hotplug_wq, &hotplug_work, up_delay); } break; case TEGRA_HP_DOWN: @@ -388,7 +419,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend) if (cpu_freq <= bottom_freq) { hp_state = TEGRA_HP_DOWN; queue_delayed_work( - hotplug_wq, &hotplug_work, down_delay); + hotplug_wq, &hotplug_work, up_delay); } else if (cpu_freq <= top_freq) { hp_state = TEGRA_HP_IDLE; } |