Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753316AbdGJBtE (ORCPT ); Sun, 9 Jul 2017 21:49:04 -0400 Received: from mga06.intel.com ([134.134.136.31]:24495 "EHLO mga06.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753286AbdGJBtC (ORCPT ); Sun, 9 Jul 2017 21:49:02 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.40,337,1496127600"; d="scan'208";a="1193388610" From: Aubrey Li To: tglx@linutronix.de, peterz@infradead.org, len.brown@intel.com, rjw@rjwysocki.net, ak@linux.intel.com, tim.c.chen@linux.intel.com, arjan@linux.intel.com, paulmck@linux.vnet.ibm.com, yang.zhang.wz@gmail.com Cc: x86@kernel.org, linux-kernel@vger.kernel.org, Aubrey Li Subject: [RFC PATCH v1 05/11] cpuidle: update idle statistics before cpuidle governor Date: Mon, 10 Jul 2017 09:38:35 +0800 Message-Id: <1499650721-5928-6-git-send-email-aubrey.li@intel.com> X-Mailer: git-send-email 2.7.4 In-Reply-To: <1499650721-5928-1-git-send-email-aubrey.li@intel.com> References: <1499650721-5928-1-git-send-email-aubrey.li@intel.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3485 Lines: 105 From: Aubrey Li Promote menu governor update functionality into cpuidle governor, so that cpuidle can make a prediction based on the fresh data. --- drivers/cpuidle/cpuidle.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/drivers/cpuidle/cpuidle.c b/drivers/cpuidle/cpuidle.c index 0be7f75..2b7d7bf 100644 --- a/drivers/cpuidle/cpuidle.c +++ b/drivers/cpuidle/cpuidle.c @@ -297,6 +297,79 @@ static unsigned int get_typical_interval(struct cpuidle_device *dev) } /** + * cpuidle_update - attempts to guess what happened after entry + * @drv: cpuidle driver containing state data + * @dev: the CPU + */ +static void cpuidle_update(struct cpuidle_driver *drv, + struct cpuidle_device *dev) +{ + struct cpuidle_governor_stat *gov_stat = + (struct cpuidle_governor_stat *)&(dev->gov_stat); + int last_idx = gov_stat->last_state_idx; + struct cpuidle_state *target = &drv->states[last_idx]; + unsigned int measured_us; + unsigned int new_factor; + + /* + * Try to figure out how much time passed between entry to low + * power state and occurrence of the wakeup event. + * + * If the entered idle state didn't support residency measurements, + * we use them anyway if they are short, and if long, + * truncate to the whole expected time. + * + * Any measured amount of time will include the exit latency. + * Since we are interested in when the wakeup begun, not when it + * was completed, we must subtract the exit latency. However, if + * the measured amount of time is less than the exit latency, + * assume the state was never reached and the exit latency is 0. + */ + + /* measured value */ + measured_us = cpuidle_get_last_residency(dev); + + /* Deduct exit latency */ + if (measured_us > 2 * target->exit_latency) + measured_us -= target->exit_latency; + else + measured_us /= 2; + + /* Make sure our coefficients do not exceed unity */ + if (measured_us > gov_stat->next_timer_us) + measured_us = gov_stat->next_timer_us; + + /* Update our correction ratio */ + new_factor = gov_stat->correction_factor[gov_stat->bucket]; + new_factor -= new_factor / DECAY; + + if (gov_stat->next_timer_us > 0 && measured_us < MAX_INTERESTING) + new_factor += RESOLUTION * measured_us / gov_stat->next_timer_us; + else + /* + * we were idle so long that we count it as a perfect + * prediction + */ + new_factor += RESOLUTION; + + /* + * We don't want 0 as factor; we always want at least + * a tiny bit of estimated time. Fortunately, due to rounding, + * new_factor will stay nonzero regardless of measured_us values + * and the compiler can eliminate this test as long as DECAY > 1. + */ + if (DECAY == 1 && unlikely(new_factor == 0)) + new_factor = 1; + + gov_stat->correction_factor[gov_stat->bucket] = new_factor; + + /* update the repeating-pattern data */ + gov_stat->intervals[gov_stat->interval_ptr++] = measured_us; + if (gov_stat->interval_ptr >= INTERVALS) + gov_stat->interval_ptr = 0; +} + +/** * cpuidle_predict - predict the next idle duration, in micro-second. * There are two factors in the cpu idle governor, taken from menu: * 1) Energy break even point @@ -319,6 +392,10 @@ unsigned int cpuidle_predict(void) if (cpuidle_not_available(drv, dev)) return -ENODEV; + /* + * Give the governor an opportunity to update on the outcome + */ + cpuidle_update(drv, dev); gov_stat = (struct cpuidle_governor_stat *)&(dev->gov_stat); -- 2.7.4