From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1754680AbbI2BJu (ORCPT ); Mon, 28 Sep 2015 21:09:50 -0400 Received: from mga14.intel.com ([192.55.52.115]:8360 "EHLO mga14.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753129AbbI2BJt (ORCPT ); Mon, 28 Sep 2015 21:09:49 -0400 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.17,605,1437462000"; d="scan'208";a="570178618" From: Yunhong Jiang To: tglx@linutronix.de Cc: arjan@linux.intel.com, linux-kernel@vger.kernel.org Subject: [RFC] nohz: no update idle entry time on get_cpu_idle/iowait_time_us() Date: Mon, 28 Sep 2015 18:01:24 -0700 Message-Id: <1443488484-24305-1-git-send-email-yunhong.jiang@linux.intel.com> X-Mailer: git-send-email 1.8.3.1 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Currently the get_cpu_idle/iowait_time_us() updates the idle_entrytime. When it's invoked from another CPU and the target CPU has been on idle already, it will update the idle_entrytime to now, which is incorrect. However, the get_cpu_idle/iowait_time_us() is not guranteed to be called on the target CPU. For example, the get_cpu_idle_time_us() seems is invoked remotely on drivers/cpufreq/cpufreq_governor.c through get_cpu_idle_time(). There is a check that the update happens only if a valid last_update_time parameter passed. IMHO, this is more a hack because there is no guarantee that it's invoked on the target CPU when last_update_time is valid. In fact, we don't need update the idle stats from get_cpu_idle/iowait_time_us(). Now the policy is, we record the entrytime when tick_nohz_start_idle() and update the stats when tick_nohz_stop_idle(). We calculate the stats on other situations. Please notice: 1) There is a bug currently that the tick_nohz_stop_idle() calls the update_ts_time_stats() and update the idle_entrytime, which is sure to be wrong. Removing the idle_entrytime update resolves the bug also. 2) There is a small widows in tick_nohz_stop_idle() between update_ts_time_stats() and clear ts->idle_active, that get_cpu_idle/iowait_time_us(), when invoked remotely, may double count last idle period. This window exists w/o this change and this change does not fix it. Signed-off-by: Yunhong Jiang --- kernel/time/tick-sched.c | 43 +++++++++++++++---------------------------- 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 7c7ec4515983..c2a78887d265 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -437,7 +437,7 @@ static void tick_nohz_update_jiffies(ktime_t now) * Updates the per cpu time idle statistics counters */ static void -update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_update_time) +update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now) { ktime_t delta; @@ -447,17 +447,12 @@ update_ts_time_stats(int cpu, struct tick_sched *ts, ktime_t now, u64 *last_upda ts->iowait_sleeptime = ktime_add(ts->iowait_sleeptime, delta); else ts->idle_sleeptime = ktime_add(ts->idle_sleeptime, delta); - ts->idle_entrytime = now; } - - if (last_update_time) - *last_update_time = ktime_to_us(now); - } static void tick_nohz_stop_idle(struct tick_sched *ts, ktime_t now) { - update_ts_time_stats(smp_processor_id(), ts, now, NULL); + update_ts_time_stats(smp_processor_id(), ts, now); ts->idle_active = 0; sched_clock_idle_wakeup_event(0); @@ -496,21 +491,16 @@ u64 get_cpu_idle_time_us(int cpu, u64 *last_update_time) return -1; now = ktime_get(); - if (last_update_time) { - update_ts_time_stats(cpu, ts, now, last_update_time); - idle = ts->idle_sleeptime; - } else { - if (ts->idle_active && !nr_iowait_cpu(cpu)) { - ktime_t delta = ktime_sub(now, ts->idle_entrytime); + idle = ts->idle_sleeptime; + if (ts->idle_active && !nr_iowait_cpu(cpu)) { + ktime_t delta = ktime_sub(now, ts->idle_entrytime); - idle = ktime_add(ts->idle_sleeptime, delta); - } else { - idle = ts->idle_sleeptime; - } + idle = ktime_add(ts->idle_sleeptime, delta); } + if (last_update_time) + *last_update_time = ktime_to_us(now); return ktime_to_us(idle); - } EXPORT_SYMBOL_GPL(get_cpu_idle_time_us); @@ -537,19 +527,16 @@ u64 get_cpu_iowait_time_us(int cpu, u64 *last_update_time) return -1; now = ktime_get(); - if (last_update_time) { - update_ts_time_stats(cpu, ts, now, last_update_time); - iowait = ts->iowait_sleeptime; - } else { - if (ts->idle_active && nr_iowait_cpu(cpu) > 0) { - ktime_t delta = ktime_sub(now, ts->idle_entrytime); + iowait = ts->iowait_sleeptime; + if (ts->idle_active && nr_iowait_cpu(cpu) > 0) { + ktime_t delta = ktime_sub(now, ts->idle_entrytime); - iowait = ktime_add(ts->iowait_sleeptime, delta); - } else { - iowait = ts->iowait_sleeptime; - } + iowait = ktime_add(ts->iowait_sleeptime, delta); } + if (last_update_time) + *last_update_time = ktime_to_us(now); + return ktime_to_us(iowait); } EXPORT_SYMBOL_GPL(get_cpu_iowait_time_us); -- 1.8.3.1