From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1755602AbcFHCuI (ORCPT ); Tue, 7 Jun 2016 22:50:08 -0400 Received: from shelob.surriel.com ([74.92.59.67]:45441 "EHLO shelob.surriel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1754390AbcFHCuG (ORCPT ); Tue, 7 Jun 2016 22:50:06 -0400 X-Greylist: delayed 1190 seconds by postgrey-1.27 at vger.kernel.org; Tue, 07 Jun 2016 22:50:06 EDT From: riel@redhat.com To: linux-kernel@vger.kernel.org Cc: kernellwp@gmail.com, mingo@kernel.org, peterz@infradead.org, tglx@linutronix.de, fweisbec@redhat.com Subject: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time Date: Tue, 7 Jun 2016 22:30:00 -0400 Message-Id: <1465353004-15044-2-git-send-email-riel@redhat.com> X-Mailer: git-send-email 2.5.5 In-Reply-To: <1465353004-15044-1-git-send-email-riel@redhat.com> References: <1465353004-15044-1-git-send-email-riel@redhat.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org From: Rik van Riel Currently, if there was any irq or softirq time during 'ticks' jiffies, the entire period will be accounted as irq or softirq time. This is inaccurate if only a subset of 'ticks' jiffies was actually spent handling irqs, and could conceivably mis-count all of the ticks during a period as irq time, when there was some irq and some softirq time. Fix this by changing irqtime_account_hi_update and irqtime_account_si_update to round elapsed irq and softirq time to jiffies, and return the number of jiffies spent in each mode, similar to how steal time is handled. Additionally, have irqtime_account_process_tick take into account how much time was spent in each of steal, irq, and softirq time. The latter could help improve the accuracy of timekeeping when returning from idle on a NO_HZ_IDLE CPU. Properly accounting how much time was spent in hardirq and softirq time will also allow the NO_HZ_FULL code to re-use these same functions for hardirq and softirq accounting. Signed-off-by: Rik van Riel --- kernel/sched/cputime.c | 54 +++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c index f51c98c740b5..4bd6d1b774ab 100644 --- a/kernel/sched/cputime.c +++ b/kernel/sched/cputime.c @@ -79,34 +79,36 @@ void irqtime_account_irq(struct task_struct *curr) } EXPORT_SYMBOL_GPL(irqtime_account_irq); -static int irqtime_account_hi_update(void) +static unsigned long irqtime_account_hi_update(void) { u64 *cpustat = kcpustat_this_cpu->cpustat; + unsigned long irq_jiffies; unsigned long flags; - u64 latest_ns; - int ret = 0; + u64 irq; local_irq_save(flags); - latest_ns = this_cpu_read(cpu_hardirq_time); - if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_IRQ]) - ret = 1; + irq = this_cpu_read(cpu_hardirq_time) - cpustat[CPUTIME_IRQ]; + irq_jiffies = cputime_to_jiffies(irq); + if (irq_jiffies) + cpustat[CPUTIME_IRQ] += jiffies_to_cputime(irq_jiffies); local_irq_restore(flags); - return ret; + return irq_jiffies; } -static int irqtime_account_si_update(void) +static unsigned long irqtime_account_si_update(void) { u64 *cpustat = kcpustat_this_cpu->cpustat; + unsigned long si_jiffies; unsigned long flags; - u64 latest_ns; - int ret = 0; + u64 softirq; local_irq_save(flags); - latest_ns = this_cpu_read(cpu_softirq_time); - if (nsecs_to_cputime64(latest_ns) > cpustat[CPUTIME_SOFTIRQ]) - ret = 1; + delta = this_cpu_read(cpu_softirq_time) - cpustat[CPUTIME_SOFTIRQ]; + si_jiffies = cputime_to_jiffies(delta); + if (si_jiffies) + cpustat[CPUSTIME_SOFTIRQ] += jiffies_to_cputime(si_jiffies); local_irq_restore(flags); - return ret; + return si_jiffies; } #else /* CONFIG_IRQ_TIME_ACCOUNTING */ @@ -345,18 +347,30 @@ static void irqtime_account_process_tick(struct task_struct *p, int user_tick, cputime_t scaled = cputime_to_scaled(cputime_one_jiffy); u64 cputime = (__force u64) cputime_one_jiffy; u64 *cpustat = kcpustat_this_cpu->cpustat; + unsigned long other; - if (steal_account_process_tick()) + /* + * Subtract steal, irq & softirq time (if any) from ticks. + * These are counted in nanoseconds and not aligned with jiffies. + * Multiple of these could "break a jiffy" simultaneously due to + * rounding; be careful to not account too much of this time at once. + */ + other = steal_account_process_tick(); + if (other >= ticks) + return; + + other += irqtime_account_hi_update(); + if (other >= ticks) + return; + + other += irqtime_account_si_update(); + if (other >= ticks) return; cputime *= ticks; scaled *= ticks; - if (irqtime_account_hi_update()) { - cpustat[CPUTIME_IRQ] += cputime; - } else if (irqtime_account_si_update()) { - cpustat[CPUTIME_SOFTIRQ] += cputime; - } else if (this_cpu_ksoftirqd() == p) { + if (this_cpu_ksoftirqd() == p) { /* * ksoftirqd time do not get accounted in cpu_softirq_time. * So, we have to handle it separately here. -- 2.5.5