From nobody Thu Feb 12 15:50:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id E1E6D17BB07; Tue, 11 Jun 2024 11:24:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105073; cv=none; b=Omk0NzEt04UOq4f+a90jJ88hLgS7rWgmpALqWZo6TpKYtedqp+IJEn1jFJax9RaOp/YFTr9DxypZ8hb1+qjeyytaUaz7PBlp2lftHgQE5oiK0yNuxaH7I8/ywjazGVz1F+BN5H0nVp75bLXCgCMqy8tZZuyAsZvXjyZVw+Y7hKY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105073; c=relaxed/simple; bh=2FRA2gx0qe2detqSe7MH2Srde32cQGErCkimGK8s5rI=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=IECZ9Kaf5cpR1ZNrYo8sNAQkn9yv9CRsMaugFuQY9CqqstGSa3sEFfHJ9pmWo11Yv/vPXTTyqc05tuUqtvG6F9+EWjIUD8QwyvbguZxes+NOdSEr6FaETRRngPaD/ScP+I31RsNAwGEqsOQfhal3OeYa3bkXy6ab7stgYVqfVZU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id BE7A41595; Tue, 11 Jun 2024 04:24:54 -0700 (PDT) Received: from e127648.cambridge.arm.com (e127648.arm.com [10.1.32.59]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 18DA93F64C; Tue, 11 Jun 2024 04:24:26 -0700 (PDT) From: Christian Loehle To: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, rafael@kernel.org Cc: vincent.guittot@linaro.org, qyousef@layalina.io, peterz@infradead.org, daniel.lezcano@linaro.org, ulf.hansson@linaro.org, anna-maria@linutronix.de, kajetan.puchalski@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, Christian Loehle Subject: [PATCHv2 1/3] Revert: "cpuidle: teo: Introduce util-awareness" Date: Tue, 11 Jun 2024 12:24:11 +0100 Message-Id: <20240611112413.1241352-2-christian.loehle@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240611112413.1241352-1-christian.loehle@arm.com> References: <20240611112413.1241352-1-christian.loehle@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" This reverts commit 9ce0f7c4bc64d820b02a1c53f7e8dba9539f942b. Util-awareness was reported to be too aggressive in selecting shallower states. Additionally a single threshold was found to not be suitable for reasoning about sleep length as, for all practical purposes, almost arbitrary sleep lengths are still possible for any load value. Fixes: 9ce0f7c4bc64 ("cpuidle: teo: Introduce util-awareness") Reported-by: Qais Yousef Reported-by: Vincent Guittot Signed-off-by: Christian Loehle Reviewed-by: Qais Yousef Tested-by: Vincent Guittot --- drivers/cpuidle/governors/teo.c | 100 -------------------------------- 1 file changed, 100 deletions(-) diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/te= o.c index 7244f71c59c5..d8554c20cf10 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -104,56 +104,16 @@ * select the given idle state instead of the candidate one. * * 3. By default, select the candidate state. - * - * Util-awareness mechanism: - * - * The idea behind the util-awareness extension is that there are two dist= inct - * scenarios for the CPU which should result in two different approaches t= o idle - * state selection - utilized and not utilized. - * - * In this case, 'utilized' means that the average runqueue util of the CP= U is - * above a certain threshold. - * - * When the CPU is utilized while going into idle, more likely than not it= will - * be woken up to do more work soon and so a shallower idle state should be - * selected to minimise latency and maximise performance. When the CPU is = not - * being utilized, the usual metrics-based approach to selecting the deepe= st - * available idle state should be preferred to take advantage of the power - * saving. - * - * In order to achieve this, the governor uses a utilization threshold. - * The threshold is computed per-CPU as a percentage of the CPU's capacity - * by bit shifting the capacity value. Based on testing, the shift of 6 (~= 1.56%) - * seems to be getting the best results. - * - * Before selecting the next idle state, the governor compares the current= CPU - * util to the precomputed util threshold. If it's below, it defaults to t= he - * TEO metrics mechanism. If it's above, the closest shallower idle state = will - * be selected instead, as long as is not a polling state. */ =20 #include #include #include -#include #include -#include #include =20 #include "gov.h" =20 -/* - * The number of bits to shift the CPU's capacity by in order to determine - * the utilized threshold. - * - * 6 was chosen based on testing as the number that achieved the best bala= nce - * of power and performance on average. - * - * The resulting threshold is high enough to not be triggered by background - * noise and low enough to react quickly when activity starts to ramp up. - */ -#define UTIL_THRESHOLD_SHIFT 6 - /* * The PULSE value is added to metrics when they grow and the DECAY_SHIFT = value * is used for decreasing metrics on a regular basis. @@ -188,7 +148,6 @@ struct teo_bin { * @next_recent_idx: Index of the next @recent_idx entry to update. * @recent_idx: Indices of bins corresponding to recent "intercepts". * @tick_hits: Number of "hits" after TICK_NSEC. - * @util_threshold: Threshold above which the CPU is considered utilized */ struct teo_cpu { s64 time_span_ns; @@ -198,28 +157,10 @@ struct teo_cpu { int next_recent_idx; int recent_idx[NR_RECENT]; unsigned int tick_hits; - unsigned long util_threshold; }; =20 static DEFINE_PER_CPU(struct teo_cpu, teo_cpus); =20 -/** - * teo_cpu_is_utilized - Check if the CPU's util is above the threshold - * @cpu: Target CPU - * @cpu_data: Governor CPU data for the target CPU - */ -#ifdef CONFIG_SMP -static bool teo_cpu_is_utilized(int cpu, struct teo_cpu *cpu_data) -{ - return sched_cpu_util(cpu) > cpu_data->util_threshold; -} -#else -static bool teo_cpu_is_utilized(int cpu, struct teo_cpu *cpu_data) -{ - return false; -} -#endif - /** * teo_update - Update CPU metrics after wakeup. * @drv: cpuidle driver containing state data. @@ -386,7 +327,6 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, int constraint_idx =3D 0; int idx0 =3D 0, idx =3D -1; bool alt_intercepts, alt_recent; - bool cpu_utilized; s64 duration_ns; int i; =20 @@ -411,32 +351,6 @@ static int teo_select(struct cpuidle_driver *drv, stru= ct cpuidle_device *dev, if (!dev->states_usage[0].disable) idx =3D 0; =20 - cpu_utilized =3D teo_cpu_is_utilized(dev->cpu, cpu_data); - /* - * If the CPU is being utilized over the threshold and there are only 2 - * states to choose from, the metrics need not be considered, so choose - * the shallowest non-polling state and exit. - */ - if (drv->state_count < 3 && cpu_utilized) { - /* - * If state 0 is enabled and it is not a polling one, select it - * right away unless the scheduler tick has been stopped, in - * which case care needs to be taken to leave the CPU in a deep - * enough state in case it is not woken up any time soon after - * all. If state 1 is disabled, though, state 0 must be used - * anyway. - */ - if ((!idx && !(drv->states[0].flags & CPUIDLE_FLAG_POLLING) && - teo_state_ok(0, drv)) || dev->states_usage[1].disable) { - idx =3D 0; - goto out_tick; - } - /* Assume that state 1 is not a polling one and use it. */ - idx =3D 1; - duration_ns =3D drv->states[1].target_residency_ns; - goto end; - } - /* Compute the sums of metrics for early wakeup pattern detection. */ for (i =3D 1; i < drv->state_count; i++) { struct teo_bin *prev_bin =3D &cpu_data->state_bins[i-1]; @@ -560,18 +474,6 @@ static int teo_select(struct cpuidle_driver *drv, stru= ct cpuidle_device *dev, if (idx > constraint_idx) idx =3D constraint_idx; =20 - /* - * If the CPU is being utilized over the threshold, choose a shallower - * non-polling state to improve latency, unless the scheduler tick has - * been stopped already and the shallower state's target residency is - * not sufficiently large. - */ - if (cpu_utilized) { - i =3D teo_find_shallower_state(drv, dev, idx, KTIME_MAX, true); - if (teo_state_ok(i, drv)) - idx =3D i; - } - /* * Skip the timers check if state 0 is the current candidate one, * because an immediate non-timer wakeup is expected in that case. @@ -667,11 +569,9 @@ static int teo_enable_device(struct cpuidle_driver *dr= v, struct cpuidle_device *dev) { struct teo_cpu *cpu_data =3D per_cpu_ptr(&teo_cpus, dev->cpu); - unsigned long max_capacity =3D arch_scale_cpu_capacity(dev->cpu); int i; =20 memset(cpu_data, 0, sizeof(*cpu_data)); - cpu_data->util_threshold =3D max_capacity >> UTIL_THRESHOLD_SHIFT; =20 for (i =3D 0; i < NR_RECENT; i++) cpu_data->recent_idx[i] =3D -1; --=20 2.34.1 From nobody Thu Feb 12 15:50:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 28CF617C213; Tue, 11 Jun 2024 11:24:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105077; cv=none; b=TZhFgZiIAO/yXt4l6tGlR09kmc9o+KapsCtySBl9ToQdcED/cL5QZfnS4PU0WKevJpye2Pr08n5747JLuOrYlgrC25oIDAe3RYigWF/EomOeyKkHCMD9Boe4nCWeKxZpanE7pmSErB+dz+EDljzcuN6pjmlnVdW2BwwWbyb3mlo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105077; c=relaxed/simple; bh=BoxPdFyqtP13A/8u8G6KN80fcsHRA/eJ0TbinIMP2vE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=eo+3G9W8ZT0I1HOy+XALgvGEexgT9T0CBjHc5Ol3995XoQHIjuHXYo81hRfXjZkKX7b0Hxpmm5THTlZNus9KmwLOCP7OEFNWKp3ABVaAIMZWsCPBUiAX8pv4VcpkMGhwMSM9aqtuQBK7VL+RNLYKCyiqMBwMDVIdXm6p6i0sRMw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 0EA52152B; Tue, 11 Jun 2024 04:24:59 -0700 (PDT) Received: from e127648.cambridge.arm.com (e127648.arm.com [10.1.32.59]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id 7BB0E3F64C; Tue, 11 Jun 2024 04:24:31 -0700 (PDT) From: Christian Loehle To: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, rafael@kernel.org Cc: vincent.guittot@linaro.org, qyousef@layalina.io, peterz@infradead.org, daniel.lezcano@linaro.org, ulf.hansson@linaro.org, anna-maria@linutronix.de, kajetan.puchalski@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, Christian Loehle Subject: [PATCHv2 2/3] cpuidle: teo: Remove recent intercepts metric Date: Tue, 11 Jun 2024 12:24:12 +0100 Message-Id: <20240611112413.1241352-3-christian.loehle@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240611112413.1241352-1-christian.loehle@arm.com> References: <20240611112413.1241352-1-christian.loehle@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The logic for recent intercepts didn't work, there is an underflow of the 'recent' value that can be observed during boot already, which teo usually doesn't recover from, making the entire logic pointless. Furthermore the recent intercepts also were never reset, thus not actually being very 'recent'. Having underflowed 'recent' values lead to teo always acting as if we were in a scenario were expected sleep length based on timers is too high and it therefore unnecessarily selecting shallower states. Experiments show that the remaining 'intercept' logic is enough to quickly react to scenarios in which teo cannot rely on the timer expected sleep length. See also here: https://lore.kernel.org/lkml/0ce2d536-1125-4df8-9a5b-0d5e389cd8af@arm.com/ Fixes: 77577558f25d ("cpuidle: teo: Rework most recent idle duration values= treatment") Signed-off-by: Christian Loehle --- drivers/cpuidle/governors/teo.c | 73 ++++++--------------------------- 1 file changed, 12 insertions(+), 61 deletions(-) diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/te= o.c index d8554c20cf10..cc7df59f488d 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -59,10 +59,6 @@ * shallower than the one whose bin is fallen into by the sleep length (th= ese * situations are referred to as "intercepts" below). * - * In addition to the metrics described above, the governor counts recent - * intercepts (that is, intercepts that have occurred during the last - * %NR_RECENT invocations of it for the given CPU) for each bin. - * * In order to select an idle state for a CPU, the governor takes the foll= owing * steps (modulo the possible latency constraint that must be taken into a= ccount * too): @@ -81,20 +77,15 @@ * idle long enough to avoid being intercepted if the sleep length ha= d been * equal to the current one). * - * - The sum of the numbers of recent intercepts for all of the idle st= ates - * shallower than the candidate one. - * - * 2. If the second sum is greater than the first one or the third sum is - * greater than %NR_RECENT / 2, the CPU is likely to wake up early, so = look - * for an alternative idle state to select. + * 2. If the second sum is greater than the first one the CPU is likely to= wake + * up early, so look for an alternative idle state to select. * * - Traverse the idle states shallower than the candidate one in the * descending order. * - * - For each of them compute the sum of the "intercepts" metrics and t= he sum - * of the numbers of recent intercepts over all of the idle states be= tween - * it and the candidate one (including the former and excluding the - * latter). + * - For each of them compute the sum of the "intercepts" metrics over = all + * of the idle states between it and the candidate one (including the + * former and excluding the latter). * * - If each of these sums that needs to be taken into account (because= the * check related to it has indicated that the CPU is likely to wake up @@ -121,22 +112,14 @@ #define PULSE 1024 #define DECAY_SHIFT 3 =20 -/* - * Number of the most recent idle duration values to take into considerati= on for - * the detection of recent early wakeup patterns. - */ -#define NR_RECENT 9 - /** * struct teo_bin - Metrics used by the TEO cpuidle governor. * @intercepts: The "intercepts" metric. * @hits: The "hits" metric. - * @recent: The number of recent "intercepts". */ struct teo_bin { unsigned int intercepts; unsigned int hits; - unsigned int recent; }; =20 /** @@ -145,8 +128,6 @@ struct teo_bin { * @sleep_length_ns: Time till the closest timer event (at the selection t= ime). * @state_bins: Idle state data bins for this CPU. * @total: Grand total of the "intercepts" and "hits" metrics for all bins. - * @next_recent_idx: Index of the next @recent_idx entry to update. - * @recent_idx: Indices of bins corresponding to recent "intercepts". * @tick_hits: Number of "hits" after TICK_NSEC. */ struct teo_cpu { @@ -154,8 +135,6 @@ struct teo_cpu { s64 sleep_length_ns; struct teo_bin state_bins[CPUIDLE_STATE_MAX]; unsigned int total; - int next_recent_idx; - int recent_idx[NR_RECENT]; unsigned int tick_hits; }; =20 @@ -227,13 +206,6 @@ static void teo_update(struct cpuidle_driver *drv, str= uct cpuidle_device *dev) } } =20 - i =3D cpu_data->next_recent_idx++; - if (cpu_data->next_recent_idx >=3D NR_RECENT) - cpu_data->next_recent_idx =3D 0; - - if (cpu_data->recent_idx[i] >=3D 0) - cpu_data->state_bins[cpu_data->recent_idx[i]].recent--; - /* * If the deepest state's target residency is below the tick length, * make a record of it to help teo_select() decide whether or not @@ -260,14 +232,10 @@ static void teo_update(struct cpuidle_driver *drv, st= ruct cpuidle_device *dev) * Otherwise, update the "intercepts" metric for the bin fallen into by * the measured idle duration. */ - if (idx_timer =3D=3D idx_duration) { + if (idx_timer =3D=3D idx_duration) cpu_data->state_bins[idx_timer].hits +=3D PULSE; - cpu_data->recent_idx[i] =3D -1; - } else { + else cpu_data->state_bins[idx_duration].intercepts +=3D PULSE; - cpu_data->state_bins[idx_duration].recent++; - cpu_data->recent_idx[i] =3D idx_duration; - } =20 end: cpu_data->total +=3D PULSE; @@ -320,8 +288,6 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, unsigned int tick_intercept_sum =3D 0; unsigned int idx_intercept_sum =3D 0; unsigned int intercept_sum =3D 0; - unsigned int idx_recent_sum =3D 0; - unsigned int recent_sum =3D 0; unsigned int idx_hit_sum =3D 0; unsigned int hit_sum =3D 0; int constraint_idx =3D 0; @@ -362,7 +328,6 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, */ intercept_sum +=3D prev_bin->intercepts; hit_sum +=3D prev_bin->hits; - recent_sum +=3D prev_bin->recent; =20 if (dev->states_usage[i].disable) continue; @@ -378,7 +343,6 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, /* Save the sums for the current state. */ idx_intercept_sum =3D intercept_sum; idx_hit_sum =3D hit_sum; - idx_recent_sum =3D recent_sum; } =20 /* Avoid unnecessary overhead. */ @@ -403,37 +367,28 @@ static int teo_select(struct cpuidle_driver *drv, str= uct cpuidle_device *dev, * If the sum of the intercepts metric for all of the idle states * shallower than the current candidate one (idx) is greater than the * sum of the intercepts and hits metrics for the candidate state and - * all of the deeper states, or the sum of the numbers of recent - * intercepts over all of the states shallower than the candidate one - * is greater than a half of the number of recent events taken into - * account, a shallower idle state is likely to be a better choice. + * all of the deeper states a shallower idle state is likely to be a + * better choice. */ - alt_intercepts =3D 2 * idx_intercept_sum > cpu_data->total - idx_hit_sum; - alt_recent =3D idx_recent_sum > NR_RECENT / 2; - if (alt_recent || alt_intercepts) { + if (2 * idx_intercept_sum > cpu_data->total - idx_hit_sum) { int first_suitable_idx =3D idx; =20 /* * Look for the deepest idle state whose target residency had * not exceeded the idle duration in over a half of the relevant - * cases (both with respect to intercepts overall and with - * respect to the recent intercepts only) in the past. + * cases in the past. * * Take the possible duration limitation present if the tick * has been stopped already into account. */ intercept_sum =3D 0; - recent_sum =3D 0; =20 for (i =3D idx - 1; i >=3D 0; i--) { struct teo_bin *bin =3D &cpu_data->state_bins[i]; =20 intercept_sum +=3D bin->intercepts; - recent_sum +=3D bin->recent; =20 - if ((!alt_recent || 2 * recent_sum > idx_recent_sum) && - (!alt_intercepts || - 2 * intercept_sum > idx_intercept_sum)) { + if (2 * intercept_sum > idx_intercept_sum) { /* * Use the current state unless it is too * shallow or disabled, in which case take the @@ -569,13 +524,9 @@ static int teo_enable_device(struct cpuidle_driver *dr= v, struct cpuidle_device *dev) { struct teo_cpu *cpu_data =3D per_cpu_ptr(&teo_cpus, dev->cpu); - int i; =20 memset(cpu_data, 0, sizeof(*cpu_data)); =20 - for (i =3D 0; i < NR_RECENT; i++) - cpu_data->recent_idx[i] =3D -1; - return 0; } =20 --=20 2.34.1 From nobody Thu Feb 12 15:50:54 2026 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by smtp.subspace.kernel.org (Postfix) with ESMTP id 7533F17C22B; Tue, 11 Jun 2024 11:24:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=217.140.110.172 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105081; cv=none; b=AOk7FE1Hd8VStnxvmFcDuWcX8j0/8jJqK3QEbSYNh/i78tNp1cD2kBQWq7blPSGrwXxi/AznM4hKddB2GuHAP8vLidjtdYYkKzK1JP0NagY/j/gWSG7V8CuizKnTFBIJKC2AaGqI3fhNnt969KTztH54jE9uzo/tHXExKcR8q3Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1718105081; c=relaxed/simple; bh=fHD5oPENUsfVgGeH0bAFr+9+RB6uqV+WC51G1sQTKQk=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=po8IyVNuuE9Y34eE83MQ5uOSljenUW9fNCpGuIxvWU5T6D0JxmmzYDYFsmPsOGi+cLP0po+tOY36tQOoUKsKY85SvKP3BIftkDmJFDfn7nYTzYcAONN69berK6EcWq6jMfF8E6ujrZVjrKyEO1M625wKY4hnCTWbw0RwzypxktA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com; spf=pass smtp.mailfrom=arm.com; arc=none smtp.client-ip=217.140.110.172 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=arm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=arm.com Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 5F265152B; Tue, 11 Jun 2024 04:25:03 -0700 (PDT) Received: from e127648.cambridge.arm.com (e127648.arm.com [10.1.32.59]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPA id AB22F3F64C; Tue, 11 Jun 2024 04:24:35 -0700 (PDT) From: Christian Loehle To: linux-pm@vger.kernel.org, linux-kernel@vger.kernel.org, rafael@kernel.org Cc: vincent.guittot@linaro.org, qyousef@layalina.io, peterz@infradead.org, daniel.lezcano@linaro.org, ulf.hansson@linaro.org, anna-maria@linutronix.de, kajetan.puchalski@arm.com, lukasz.luba@arm.com, dietmar.eggemann@arm.com, Christian Loehle Subject: [PATCHv2 3/3] cpuidle: teo: Don't count non-existent intercepts Date: Tue, 11 Jun 2024 12:24:13 +0100 Message-Id: <20240611112413.1241352-4-christian.loehle@arm.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240611112413.1241352-1-christian.loehle@arm.com> References: <20240611112413.1241352-1-christian.loehle@arm.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" When bailing out early, teo will not query the sleep length anymore since commit 6da8f9ba5a87 ("cpuidle: teo: Skip tick_nohz_get_sleep_length() call in some cases") with an expected sleep_length_ns value of KTIME_MAX. This lead to state0 accumulating lots of 'intercepts' because the actually measured sleep length was < KTIME_MAX, so count KTIME_MAX as a hit (we have to count them as something otherwise we are stuck) and therefore teo taking too long to recover from intercept-heavy scenarios. Fundamentally we can only do one of the two: 1. Skip sleep_length_ns query when we think intercept is likely 2. Have accurate data if sleep_length_ns is actually intercepted when we believe it is currently intercepted. This patch chooses the latter as I've found the additional time it takes to query the sleep length to be negligible and the variants of option 1 (count all unknowns as misses or count all unknown as hits) had significant regressions (as misses had lots of too shallow idle state selections and as hits had terrible performance in intercept-heavy workloads). Fixes: 6da8f9ba5a87 ("cpuidle: teo: Skip tick_nohz_get_sleep_length() call = in some cases") Signed-off-by: Christian Loehle --- drivers/cpuidle/governors/teo.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/drivers/cpuidle/governors/teo.c b/drivers/cpuidle/governors/te= o.c index cc7df59f488d..1e4b40474f49 100644 --- a/drivers/cpuidle/governors/teo.c +++ b/drivers/cpuidle/governors/teo.c @@ -231,8 +231,13 @@ static void teo_update(struct cpuidle_driver *drv, str= uct cpuidle_device *dev) * length, this is a "hit", so update the "hits" metric for that bin. * Otherwise, update the "intercepts" metric for the bin fallen into by * the measured idle duration. + * If teo_select() bailed out early, we have to count this as a hit as + * we don't know what the true sleep length would've been. Otherwise + * we accumulate lots of intercepts at the shallower state (especially + * state0) even though there weren't any intercepts due to us + * anticipating one. */ - if (idx_timer =3D=3D idx_duration) + if (idx_timer =3D=3D idx_duration || cpu_data->sleep_length_ns =3D=3D KTI= ME_MAX) cpu_data->state_bins[idx_timer].hits +=3D PULSE; else cpu_data->state_bins[idx_duration].intercepts +=3D PULSE; @@ -292,7 +297,7 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, unsigned int hit_sum =3D 0; int constraint_idx =3D 0; int idx0 =3D 0, idx =3D -1; - bool alt_intercepts, alt_recent; + int prev_intercept_idx; s64 duration_ns; int i; =20 @@ -370,6 +375,7 @@ static int teo_select(struct cpuidle_driver *drv, struc= t cpuidle_device *dev, * all of the deeper states a shallower idle state is likely to be a * better choice. */ + prev_intercept_idx =3D idx; if (2 * idx_intercept_sum > cpu_data->total - idx_hit_sum) { int first_suitable_idx =3D idx; =20 @@ -421,6 +427,14 @@ static int teo_select(struct cpuidle_driver *drv, stru= ct cpuidle_device *dev, first_suitable_idx =3D i; } } + if (!idx && prev_intercept_idx) { + /* + * We have to query the sleep length here otherwise we don't + * know after wakeup if our guess was correct. + */ + duration_ns =3D tick_nohz_get_sleep_length(&delta_tick); + cpu_data->sleep_length_ns =3D duration_ns; + } =20 /* * If there is a latency constraint, it may be necessary to select an --=20 2.34.1