From patchwork Tue Sep 12 06:10:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liao Chang X-Patchwork-Id: 722007 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 6A63DCA0EC9 for ; Tue, 12 Sep 2023 06:13:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229606AbjILGNU (ORCPT ); Tue, 12 Sep 2023 02:13:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43718 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229567AbjILGNU (ORCPT ); Tue, 12 Sep 2023 02:13:20 -0400 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 049B7AF; Mon, 11 Sep 2023 23:13:16 -0700 (PDT) Received: from kwepemd200002.china.huawei.com (unknown [172.30.72.53]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4RlCpz5k45zMlHw; Tue, 12 Sep 2023 14:09:47 +0800 (CST) Received: from huawei.com (10.67.174.28) by kwepemd200002.china.huawei.com (7.221.188.186) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.1258.23; Tue, 12 Sep 2023 14:13:13 +0800 From: Liao Chang To: , CC: , Subject: [PATCH 1/2] cpufreq: userspace: Use fine-grained mutex in userspace governor Date: Tue, 12 Sep 2023 06:10:56 +0000 Message-ID: <20230912061057.2516963-1-liaochang1@huawei.com> X-Mailer: git-send-email 2.34.1 MIME-Version: 1.0 X-Originating-IP: [10.67.174.28] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd200002.china.huawei.com (7.221.188.186) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The userspace governor currently uses a big global mutex to avoid the race condition on the governor_data field of cpufreq_policy structure. This leads to a low concurrency if multiple userspace applications are trying to set the speed of different policies at the same time. This patch introduces a per-policy mutex to allow the updating of different policies to be performed concurrently, improving overall concurrency. Signed-off-by: Liao Chang Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq_userspace.c | 69 +++++++++++++++++------------ 1 file changed, 40 insertions(+), 29 deletions(-) diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 50a4d7846580..442e31060d62 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -16,7 +16,11 @@ #include static DEFINE_PER_CPU(unsigned int, cpu_is_managed); -static DEFINE_MUTEX(userspace_mutex); + +struct userspace_policy { + unsigned int setspeed; + struct mutex mutex; +}; /** * cpufreq_set - set the CPU frequency @@ -28,19 +32,19 @@ static DEFINE_MUTEX(userspace_mutex); static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) { int ret = -EINVAL; - unsigned int *setspeed = policy->governor_data; + struct userspace_policy *userspace = policy->governor_data; pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); - mutex_lock(&userspace_mutex); + mutex_lock(&userspace->mutex); if (!per_cpu(cpu_is_managed, policy->cpu)) goto err; - *setspeed = freq; + userspace->setspeed = freq; ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L); err: - mutex_unlock(&userspace_mutex); + mutex_unlock(&userspace->mutex); return ret; } @@ -51,67 +55,74 @@ static ssize_t show_speed(struct cpufreq_policy *policy, char *buf) static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) { - unsigned int *setspeed; + struct userspace_policy *userspace; - setspeed = kzalloc(sizeof(*setspeed), GFP_KERNEL); - if (!setspeed) + userspace = kzalloc(sizeof(*userspace), GFP_KERNEL); + if (!userspace) return -ENOMEM; - policy->governor_data = setspeed; + mutex_init(&userspace->mutex); + + policy->governor_data = userspace; return 0; } +/* + * Any routine that writes to the policy struct will hold the "rwsem" of + * policy struct that means it is free to free "governor_data" here. + */ static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy) { - mutex_lock(&userspace_mutex); kfree(policy->governor_data); policy->governor_data = NULL; - mutex_unlock(&userspace_mutex); } static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) { - unsigned int *setspeed = policy->governor_data; + struct userspace_policy *userspace = policy->governor_data; BUG_ON(!policy->cur); pr_debug("started managing cpu %u\n", policy->cpu); - mutex_lock(&userspace_mutex); + mutex_lock(&userspace->mutex); per_cpu(cpu_is_managed, policy->cpu) = 1; - *setspeed = policy->cur; - mutex_unlock(&userspace_mutex); + userspace->setspeed = policy->cur; + mutex_unlock(&userspace->mutex); return 0; } static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) { - unsigned int *setspeed = policy->governor_data; + struct userspace_policy *userspace = policy->governor_data; pr_debug("managing cpu %u stopped\n", policy->cpu); - mutex_lock(&userspace_mutex); + mutex_lock(&userspace->mutex); per_cpu(cpu_is_managed, policy->cpu) = 0; - *setspeed = 0; - mutex_unlock(&userspace_mutex); + userspace->setspeed = 0; + mutex_unlock(&userspace->mutex); } static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy) { - unsigned int *setspeed = policy->governor_data; + struct userspace_policy *userspace = policy->governor_data; - mutex_lock(&userspace_mutex); + mutex_lock(&userspace->mutex); pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n", - policy->cpu, policy->min, policy->max, policy->cur, *setspeed); - - if (policy->max < *setspeed) - __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H); - else if (policy->min > *setspeed) - __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L); + policy->cpu, policy->min, policy->max, policy->cur, userspace->setspeed); + + if (policy->max < userspace->setspeed) + __cpufreq_driver_target(policy, policy->max, + CPUFREQ_RELATION_H); + else if (policy->min > userspace->setspeed) + __cpufreq_driver_target(policy, policy->min, + CPUFREQ_RELATION_L); else - __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L); + __cpufreq_driver_target(policy, userspace->setspeed, + CPUFREQ_RELATION_L); - mutex_unlock(&userspace_mutex); + mutex_unlock(&userspace->mutex); } static struct cpufreq_governor cpufreq_gov_userspace = { From patchwork Tue Sep 12 06:10:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Liao Chang X-Patchwork-Id: 722452 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 01C83CA0ECA for ; Tue, 12 Sep 2023 06:13:17 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229678AbjILGNU (ORCPT ); Tue, 12 Sep 2023 02:13:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:43728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229461AbjILGNU (ORCPT ); Tue, 12 Sep 2023 02:13:20 -0400 Received: from szxga03-in.huawei.com (szxga03-in.huawei.com [45.249.212.189]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 285EBE77; Mon, 11 Sep 2023 23:13:16 -0700 (PDT) Received: from kwepemd200002.china.huawei.com (unknown [172.30.72.56]) by szxga03-in.huawei.com (SkyGuard) with ESMTP id 4RlCq00hj0zMlJ0; Tue, 12 Sep 2023 14:09:48 +0800 (CST) Received: from huawei.com (10.67.174.28) by kwepemd200002.china.huawei.com (7.221.188.186) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256) id 15.2.1258.23; Tue, 12 Sep 2023 14:13:14 +0800 From: Liao Chang To: , CC: , Subject: [PATCH 2/2] cpufreq: userspace: Move is_managed indicator into per-policy structure Date: Tue, 12 Sep 2023 06:10:57 +0000 Message-ID: <20230912061057.2516963-2-liaochang1@huawei.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20230912061057.2516963-1-liaochang1@huawei.com> References: <20230912061057.2516963-1-liaochang1@huawei.com> MIME-Version: 1.0 X-Originating-IP: [10.67.174.28] X-ClientProxiedBy: dggems702-chm.china.huawei.com (10.3.19.179) To kwepemd200002.china.huawei.com (7.221.188.186) X-CFilter-Loop: Reflected Precedence: bulk List-ID: X-Mailing-List: linux-pm@vger.kernel.org The userspace governor use the 'cpu' field of cpufreq_policy structure to track if it is allowed to set the speed of policy. However, there is a window where the 'cpu' field is equal to the value of nr_cpus_id when all affected CPUs of policy are offline, which is an illegal value to get the per-CPU variable. To avoid this issue, this patch uses a per-policy indicator to track if the policy is managed. Signed-off-by: Liao Chang Acked-by: Viresh Kumar --- drivers/cpufreq/cpufreq_userspace.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/drivers/cpufreq/cpufreq_userspace.c b/drivers/cpufreq/cpufreq_userspace.c index 442e31060d62..2c42fee76daa 100644 --- a/drivers/cpufreq/cpufreq_userspace.c +++ b/drivers/cpufreq/cpufreq_userspace.c @@ -15,9 +15,8 @@ #include #include -static DEFINE_PER_CPU(unsigned int, cpu_is_managed); - struct userspace_policy { + unsigned int is_managed; unsigned int setspeed; struct mutex mutex; }; @@ -37,7 +36,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq) pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq); mutex_lock(&userspace->mutex); - if (!per_cpu(cpu_is_managed, policy->cpu)) + if (!userspace->is_managed) goto err; userspace->setspeed = freq; @@ -85,7 +84,7 @@ static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy) pr_debug("started managing cpu %u\n", policy->cpu); mutex_lock(&userspace->mutex); - per_cpu(cpu_is_managed, policy->cpu) = 1; + userspace->is_managed = 1; userspace->setspeed = policy->cur; mutex_unlock(&userspace->mutex); return 0; @@ -98,7 +97,7 @@ static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy) pr_debug("managing cpu %u stopped\n", policy->cpu); mutex_lock(&userspace->mutex); - per_cpu(cpu_is_managed, policy->cpu) = 0; + userspace->is_managed = 0; userspace->setspeed = 0; mutex_unlock(&userspace->mutex); }