From mboxrd@z Thu Jan 1 00:00:00 1970 From: "Rafael J. Wysocki" Subject: [PATCH] cpuidle: poll_state: Avoid invoking local_clock() too often Date: Tue, 27 Mar 2018 23:58:45 +0200 Message-ID: <2095821.OCbkRpinqI@aspire.rjw.lan> Mime-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7Bit Return-path: Sender: linux-kernel-owner@vger.kernel.org To: Linux PM Cc: Peter Zijlstra , Frederic Weisbecker , Thomas Gleixner , Paul McKenney , Thomas Ilsche , Doug Smythies , Rik van Riel , Aubrey Li , Mike Galbraith , LKML List-Id: linux-pm@vger.kernel.org From: Rafael J. Wysocki Rik reports that he sees an increase in CPU use in one benchmark due to commit 612f1a22f067 "cpuidle: poll_state: Add time limit to poll_idle()" that caused poll_idle() to call local_clock() in every iteration of the loop. Utilization increase generally means more non-idle time with respect to total CPU time (on the average) which implies reduced CPU frequency. Doug reports that limiting the rate of local_clock() invocations in there causes much less power to be drawn during a CPU-intensive parallel workload (with idle states 1 and 2 disabled to enforce more state 0 residency). These two reports together suggest that executing local_clock() on multiple CPUs in parallel at a high rate may cause chips to get hot and trigger thermal/power limits on them to kick in, so reduce the rate of local_clock() invocations in poll_idle() to avoid that issue. Fixes: 612f1a22f067 "cpuidle: poll_state: Add time limit to poll_idle()" Reported-by: Rik van Riel Reported-by: Doug Smythies Signed-off-by: Rafael J. Wysocki --- I've settled for POLL_IDLE_RELAX_COUNT = 200 after quite a bit of back-and-forth and a number of test runs. It may need to be refined going forward if somebody has a problem with the current one. --- drivers/cpuidle/poll_state.c | 6 ++++++ 1 file changed, 6 insertions(+) Index: linux-pm/drivers/cpuidle/poll_state.c =================================================================== --- linux-pm.orig/drivers/cpuidle/poll_state.c +++ linux-pm/drivers/cpuidle/poll_state.c @@ -10,6 +10,7 @@ #include #define POLL_IDLE_TIME_LIMIT (TICK_NSEC / 16) +#define POLL_IDLE_RELAX_COUNT 200 static int __cpuidle poll_idle(struct cpuidle_device *dev, struct cpuidle_driver *drv, int index) @@ -18,9 +19,14 @@ static int __cpuidle poll_idle(struct cp local_irq_enable(); if (!current_set_polling_and_test()) { + unsigned int loop_count = 0; + while (!need_resched()) { cpu_relax(); + if (loop_count++ < POLL_IDLE_RELAX_COUNT) + continue; + loop_count = 0; if (local_clock() - time_start > POLL_IDLE_TIME_LIMIT) break; }