Message ID | 20230324100023.900616-1-yajun.deng@linux.dev |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp505031vqo; Fri, 24 Mar 2023 03:06:12 -0700 (PDT) X-Google-Smtp-Source: AKy350ZnXbVp0/S/izFB8K4xjjPO3CeFsf592E5E7vrkCLy8xcVz/iNxO92rDoLoeQF1LzCl2eNf X-Received: by 2002:a62:64c4:0:b0:627:eaf5:48e8 with SMTP id y187-20020a6264c4000000b00627eaf548e8mr2753585pfb.32.1679652372340; Fri, 24 Mar 2023 03:06:12 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1679652372; cv=none; d=google.com; s=arc-20160816; b=IJmlWVrlu5bAuGZSRIFAJUK2LKCzD608bUM9IOBQ2af5WbTF4DJhWcCqwKrShMTLwM CClt2Ph9g32jt7Rb+M9PwSx1M7m643VGWdNTZ3hqJGwVrvQ1FkLu/6+9dASq50OtkTRC 2mXp5BcjldbWNViiuotK/uAa/+T3HgDyl6W6I1iWgPVsnLfp2cNA/VnL5piMrCFxds0O ieJ4W/TpqFLhpg7vedNUxQPss5ur5fjgyvP6VAAbIXPN02XxYtf9RlJOdSCku9UUK4Db lq6yxJ/JdT/DXejF23Xc0SleA3/O7wJjPqeJAuW3BCo85+yNUWQJigSt0Dnd5Bdw2yw+ b3sw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :message-id:date:subject:cc:to:from:dkim-signature; bh=bSc0WWKCrF67Pi/HwlNZVSesODSTBfnuSU6f64Y3d4A=; b=p2kfXs2AZngPST79ETaF2CtGaNEwNeGtnuz4Uq00p0uGFJA8hAU7FL/mLZZLXuAeZh AVsnMvnD/jkyc9nXr+Cwg0s2Ze5na3/kPkqAugbt+wptRPI/54LrgsI71e0qb3l1ggN1 cr1P1z2u2ut2P6XUk1qdcUQg7xrusIntT5DTDUtSrZviA/5QIWuvIjV3AeiKf6RWyBbR ZuRRqSxtAC9jNg+ok2iRMVABatwaMttjD6WPzXGI01FIL6wVKpKhZMKrs843fpVGWp7C oIjUyHh/6PCIRlqTem+t4VSlODeiyC9u1//K0cjYZ/zxpzN66lAGY6OgnnzwVMbo3/7c 7KPQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=eZe+OG47; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id b18-20020a056a00115200b0062880abbf2esi6949898pfm.315.2023.03.24.03.05.59; Fri, 24 Mar 2023 03:06:12 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@linux.dev header.s=key1 header.b=eZe+OG47; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=linux.dev Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231289AbjCXKA6 (ORCPT <rfc822;ezelljr.billy@gmail.com> + 99 others); Fri, 24 Mar 2023 06:00:58 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55022 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229919AbjCXKA4 (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Fri, 24 Mar 2023 06:00:56 -0400 Received: from out-47.mta0.migadu.com (out-47.mta0.migadu.com [IPv6:2001:41d0:1004:224b::2f]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3459A199DB for <linux-kernel@vger.kernel.org>; Fri, 24 Mar 2023 03:00:55 -0700 (PDT) X-Report-Abuse: Please report any abuse attempt to abuse@migadu.com and include these headers. DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linux.dev; s=key1; t=1679652053; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=bSc0WWKCrF67Pi/HwlNZVSesODSTBfnuSU6f64Y3d4A=; b=eZe+OG47+3TlSHWJlYF8pqZJwWOkYm4wcvj+d/U76tHtu84GBZq+4nEYKUT9dYfTrKuoYD ApeYh3GxTNz+v52A0863zXehU83OexBfz7xAOy/hCTPvsBtAjKYa+T5e/+jXbQhsvVbw5S yKKmUb9jbuA9qR/mP/n0vuPfhdtNCZM= From: Yajun Deng <yajun.deng@linux.dev> To: rafael@kernel.org, viresh.kumar@linaro.org, mingo@redhat.com, peterz@infradead.org, juri.lelli@redhat.com, vincent.guittot@linaro.org, dietmar.eggemann@arm.com, rostedt@goodmis.org, bsegall@google.com, mgorman@suse.de, bristot@redhat.com, vschneid@redhat.com Cc: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, Yajun Deng <yajun.deng@linux.dev> Subject: [PATCH] cpufreq: schedutil: Combine two loops into one in sugov_start() Date: Fri, 24 Mar 2023 18:00:23 +0800 Message-Id: <20230324100023.900616-1-yajun.deng@linux.dev> MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Migadu-Flow: FLOW_OUT X-Spam-Status: No, score=-0.2 required=5.0 tests=DKIM_SIGNED,DKIM_VALID, DKIM_VALID_AU,DKIM_VALID_EF,SPF_HELO_NONE,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1761243165998541181?= X-GMAIL-MSGID: =?utf-8?q?1761243165998541181?= |
Series |
cpufreq: schedutil: Combine two loops into one in sugov_start()
|
|
Commit Message
Yajun Deng
March 24, 2023, 10 a.m. UTC
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.
Signed-off-by: Yajun Deng <yajun.deng@linux.dev>
---
kernel/sched/cpufreq_schedutil.c | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
Comments
Hi Yajun, On 3/24/23 10:00, Yajun Deng wrote: > 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. > > Signed-off-by: Yajun Deng <yajun.deng@linux.dev> > --- > kernel/sched/cpufreq_schedutil.c | 12 ++++-------- > 1 file changed, 4 insertions(+), 8 deletions(-) > > diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c > index e3211455b203..9a28ebbb9c1e 100644 > --- a/kernel/sched/cpufreq_schedutil.c > +++ b/kernel/sched/cpufreq_schedutil.c > @@ -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; 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
March 24, 2023 6:46 PM, "Lukasz Luba" <lukasz.luba@arm.com> wrote: > Hi Yajun, > > On 3/24/23 10:00, Yajun Deng wrote: > >> 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. >> Signed-off-by: Yajun Deng <yajun.deng@linux.dev> >> --- >> kernel/sched/cpufreq_schedutil.c | 12 ++++-------- >> 1 file changed, 4 insertions(+), 8 deletions(-) >> diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c >> index e3211455b203..9a28ebbb9c1e 100644 >> --- a/kernel/sched/cpufreq_schedutil.c >> +++ b/kernel/sched/cpufreq_schedutil.c >> @@ -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; > > 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. > Ok, Got it. Thanks! > Regards > Lukasz
diff --git a/kernel/sched/cpufreq_schedutil.c b/kernel/sched/cpufreq_schedutil.c index e3211455b203..9a28ebbb9c1e 100644 --- a/kernel/sched/cpufreq_schedutil.c +++ b/kernel/sched/cpufreq_schedutil.c @@ -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;