cpufreq: schedutil: Combine two loops into one in sugov_start()
Subsystems (2)
PATCH 1/1 cpufreq: schedutil: Combine two loops into one in sugov_start()
The sugov_start() function currently contains two for loops that traverse the CPU list and perform some initialization tasks. The first loop initializes each sugov_cpu struct and assigns the CPU number and sugov_policy pointer. The second loop sets up the update_util hook for each CPU based on the policy type.
Since both loops operate on the same CPU list, it is possible to combine them into a single for loop. This simplifies the code and reduces the number of times the CPU list needs to be traversed, which can improve performance.
--- kernel/sched/cpufreq_schedutil.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)
kernel/sched/cpufreq_schedutil.c +4 -8
@@ -766,14 +766,6 @@ static int sugov_start(struct cpufreq_policy *policy) sg_policy->need_freq_update =cpufreq_driver_test_flags (CPUFREQ_NEED_UPDATE_LIMITS ); -for_each_cpu (cpu, policy->cpus) { -struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); - -memset (sg_cpu,0 ,sizeof (*sg_cpu)); - sg_cpu->cpu = cpu; - sg_cpu->sg_policy = sg_policy; - } -if (policy_is_shared (policy)) uu = sugov_update_shared;else if (policy->fast_switch_enabled &&cpufreq_driver_has_adjust_perf ())
@@ -784,6 +776,10 @@ static int sugov_start(struct cpufreq_policy *policy)for_each_cpu (cpu, policy->cpus) {struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); +memset (sg_cpu,0 ,sizeof (*sg_cpu)); + sg_cpu->cpu = cpu; + sg_cpu->sg_policy = sg_policy; +cpufreq_add_update_util_hook (cpu, &sg_cpu->update_util, uu); }return 0 ;
Signature · 1 line
2.25.1
Hi Yajun,
Quoted 36 lines · Yajun Deng
The
sugov_start()function currently contains two for loops that traverse the CPU list and perform some initialization tasks. The first loop initializes eachsugov_cpustruct and assigns the CPU number andsugov_policypointer. The second loop sets up theupdate_utilhook for each CPU based on the policy type.Since both loops operate on the same CPU list, it is possible to combine them into a single for loop. This simplifies the code and reduces the number of times the CPU list needs to be traversed, which can improve performance.
Signed-off-by Yajun Deng <[email protected]>--- kernel/sched/cpufreq_schedutil.c | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-)kernel/sched/cpufreq_schedutil.c +0
-8@@ -766,14 +766,6 @@ static int sugov_start(struct cpufreq_policy *policy) sg_policy->need_freq_update =cpufreq_driver_test_flags (CPUFREQ_NEED_UPDATE_LIMITS ); -for_each_cpu (cpu, policy->cpus) { -struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); - -memset (sg_cpu,0 ,sizeof (*sg_cpu)); - sg_cpu->cpu = cpu; - sg_cpu->sg_policy = sg_policy; - } -if (policy_is_shared (policy)) uu = sugov_update_shared;else if (policy->fast_switch_enabled &&cpufreq_driver_has_adjust_perf ())
kernel/sched/cpufreq_schedutil.c static int sugov_start(struct cpufreq_policy *policy) · line 785
Quoted 10 lines
kernel/sched/cpufreq_schedutil.c +4
-0@@ -784,6 +776,10 @@ static int sugov_start(struct cpufreq_policy *policy)for_each_cpu (cpu, policy->cpus) {struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); +memset (sg_cpu,0 ,sizeof (*sg_cpu)); + sg_cpu->cpu = cpu; + sg_cpu->sg_policy = sg_policy; +cpufreq_add_update_util_hook (cpu, &sg_cpu->update_util, uu); }return 0 ;
IMO the change might cause a race.
There is a call to set scheduler hook in the 2nd loop.
If you combine two loops that hook might be used
from other CPU in the meantime, while still the rest CPUs are not finished.
The first loop makes sure all CPUs in the 'policy->cpus' get a clean context 'sg_cpu' and proper 'cpu' values first (and 'sg_policy' as well). When the two loops are combined, there might be fast usage from scheduler on other CPU the sugov code path.
If the policy is shared for many CPUs and any of them is able to change the freq, then some CPU can enter this code flow, where remotely wants to check the other CPUs' utilization:
sugov_next_freq_shared()
for each cpu in policy->cpus: sugov_get_util() where the 'sg_cpu->cpu' is used
Therefore, IMO this optimization in a start function (which is only called once and is not part of the 'hot path') is not worth the race risk.
Regards
Lukasz
Quoted 59 lines · Lukasz Luba
Hi Yajun,
Quoted 31 lines · Yajun Deng
The
sugov_start()function currently contains two for loops that traverse the CPU list and perform some initialization tasks. The first loop initializes eachsugov_cpustruct and assigns the CPU number andsugov_policypointer. The second loop sets up theupdate_utilhook for each CPU based on the policy type.
Since both loops operate on the same CPU list, it is possible to combine them into a single for loop. This simplifies the code and reduces the number of times the CPU list needs to be traversed, which can improve performance.Signed-off-by Yajun Deng <[email protected]>---
kernel/sched/cpufreq_schedutil.c| 12 ++++--------1 file changed, 4 insertions(+), 8 deletions(-)kernel/sched/cpufreq_schedutil.c +0
-7@@ -766,14 +766,6 @@ static int sugov_start(struct cpufreq_policy *policy) > sg_policy->need_freq_update = cpufreq_driver_test_flags(CPUFREQ_NEED_UPDATE_LIMITS); > - for_each_cpu(cpu, policy->cpus) { -struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); - -memset (sg_cpu,0 ,sizeof (*sg_cpu)); - sg_cpu->cpu = cpu; - sg_cpu->sg_policy = sg_policy; - } -if (policy_is_shared (policy)) uu = sugov_update_shared;else if (policy->fast_switch_enabled &&cpufreq_driver_has_adjust_perf ())kernel/sched/cpufreq_schedutil.c static int sugov_start(struct cpufreq_policy *policy) · line 784
Quoted 9 lines
kernel/sched/cpufreq_schedutil.c +3
-0@@ -784,6 +776,10 @@ static int sugov_start(struct cpufreq_policy *policy) for_each_cpu(cpu, policy->cpus) {struct sugov_cpu *sg_cpu = &per_cpu (sugov_cpu, cpu); > + memset(sg_cpu, 0, sizeof(*sg_cpu)); + sg_cpu->cpu = cpu; + sg_cpu->sg_policy = sg_policy; +cpufreq_add_update_util_hook (cpu, &sg_cpu->update_util, uu); }return 0 ;IMO the change might cause a race.
There is a call to set scheduler hook in the 2nd loop.
If you combine two loops that hook might be used
from other CPU in the meantime, while still the rest CPUs are not finished.
The first loop makes sure all CPUs in the 'policy->cpus' get a clean context 'sg_cpu' and proper 'cpu' values first (and 'sg_policy' as well). When the two loops are combined, there might be fast usage from scheduler on other CPU the sugov code path.If the policy is shared for many CPUs and any of them is able to change the freq, then some CPU can enter this code flow, where remotely wants to check the other CPUs' utilization:
Quoted 9 lines
sugov_next_freq_shared()
for each cpu inpolicy->cpus:sugov_get_util()
where the 'sg_cpu->cpu' is usedTherefore, IMO this optimization in a start function (which is only called once and is not part of the 'hot path') is not worth the race risk.
Ok, Got it. Thanks!
Quoted 2 lines
Regards
Lukasz