Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1424230 > unrolled thread
| Started by | riel@redhat.com |
|---|---|
| First post | 2016-06-16 18:10 +0200 |
| Last post | 2016-06-22 13:00 +0200 |
| Articles | 6 — 5 participants |
Back to article view | Back to linux.kernel
This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by
below is the oldest one visible, not the original post.
[PATCH 1/5] sched,time: count actually elapsed irq & softirq time riel@redhat.com - 2016-06-16 18:10 +0200
Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time kbuild test robot <lkp@intel.com> - 2016-06-16 18:30 +0200
Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time Peter Zijlstra <peterz@infradead.org> - 2016-06-21 23:30 +0200
Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time Rik van Riel <riel@redhat.com> - 2016-06-22 00:30 +0200
Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time Paolo Bonzini <pbonzini@redhat.com> - 2016-06-22 12:50 +0200
Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time Peter Zijlstra <peterz@infradead.org> - 2016-06-22 13:00 +0200
| From | riel@redhat.com |
|---|---|
| Date | 2016-06-16 18:10 +0200 |
| Subject | [PATCH 1/5] sched,time: count actually elapsed irq & softirq time |
| Message-ID | <rKI1H-25D-21@gated-at.bofh.it> |
From: Rik van Riel <riel@redhat.com>
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.
This can actually happen when irqtime_account_process_tick
is called from account_idle_ticks, which can pass a larger
number of ticks down all at once.
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 <riel@redhat.com>
---
kernel/sched/cputime.c | 69 +++++++++++++++++++++++++++++++++++---------------
1 file changed, 48 insertions(+), 21 deletions(-)
diff --git a/kernel/sched/cputime.c b/kernel/sched/cputime.c
index 3d60e5d76fdb..9bd2d4f42037 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(unsigned long max_jiffies)
{
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 = min(cputime_to_jiffies(irq), max_jiffies);
+ 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(unsigned long max_jiffies)
{
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;
+ softirq = this_cpu_read(cpu_softirq_time) - cpustat[CPUTIME_SOFTIRQ];
+ si_jiffies = min(cputime_to_jiffies(softirq), max_jiffies);
+ if (si_jiffies)
+ cpustat[CPUTIME_SOFTIRQ] += jiffies_to_cputime(si_jiffies);
local_irq_restore(flags);
- return ret;
+ return si_jiffies;
}
#else /* CONFIG_IRQ_TIME_ACCOUNTING */
@@ -283,6 +285,26 @@ static __always_inline unsigned long steal_account_process_tick(unsigned long ma
}
/*
+ * Account how much elapsed time was spent in steal, irq, or softirq time.
+ * Due to rounding errors, the calculated amount can sometimes exceed
+ * max_jiffies; be careful not to account more than max_jiffies.
+ */
+static inline int account_other_ticks(unsigned long max_jiffies)
+{
+ unsigned long accounted;
+
+ accounted = steal_account_process_tick(max_jiffies);
+
+ if (accounted < max_jiffies)
+ accounted += irqtime_account_hi_update(max_jiffies - accounted);
+
+ if (accounted < max_jiffies)
+ accounted += irqtime_account_si_update(max_jiffies - accounted);
+
+ return accounted;
+}
+
+/*
* Accumulate raw cputime values of dead tasks (sig->[us]time) and live
* tasks (sum on group iteration) belonging to @tsk's group.
*/
@@ -344,19 +366,24 @@ 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(ULONG_MAX))
+ /*
+ * When returning from idle, many ticks can get accounted at
+ * once, including some ticks of steal, irq, and softirq time.
+ * Subtract those ticks from the amount of time accounted to
+ * idle, or potentially user or system time. Due to rounding,
+ * other time can exceed ticks occasionally.
+ */
+ other = account_other_ticks(ticks);
+ if (other >= ticks)
return;
+ ticks -= other;
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
[toc] | [next] | [standalone]
| From | kbuild test robot <lkp@intel.com> |
|---|---|
| Date | 2016-06-16 18:30 +0200 |
| Message-ID | <rKIl3-2cb-9@gated-at.bofh.it> |
| In reply to | #1424230 |
[Multipart message — attachments visible in raw view] — view raw
Hi,
[auto build test ERROR on tip/sched/core]
[also build test ERROR on next-20160616]
[cannot apply to v4.7-rc3]
[if your patch is applied to the wrong git tree, please drop us a note to help improve the system]
url: https://github.com/0day-ci/linux/commits/riel-redhat-com/sched-time-fix-irq-time-accounting-with-nohz_idle/20160617-001150
config: i386-tinyconfig (attached as .config)
compiler: gcc-6 (Debian 6.1.1-1) 6.1.1 20160430
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
Note: the linux-review/riel-redhat-com/sched-time-fix-irq-time-accounting-with-nohz_idle/20160617-001150 HEAD cc827b6bc02ef052d79b5dbd2c355d9483a8ada7 builds fine.
It only hurts bisectibility.
All errors (new ones prefixed by >>):
kernel/sched/cputime.c: In function 'account_other_ticks':
>> kernel/sched/cputime.c:299:16: error: implicit declaration of function 'irqtime_account_hi_update' [-Werror=implicit-function-declaration]
accounted += irqtime_account_hi_update(max_jiffies - accounted);
^~~~~~~~~~~~~~~~~~~~~~~~~
>> kernel/sched/cputime.c:302:16: error: implicit declaration of function 'irqtime_account_si_update' [-Werror=implicit-function-declaration]
accounted += irqtime_account_si_update(max_jiffies - accounted);
^~~~~~~~~~~~~~~~~~~~~~~~~
cc1: some warnings being treated as errors
vim +/irqtime_account_hi_update +299 kernel/sched/cputime.c
293 {
294 unsigned long accounted;
295
296 accounted = steal_account_process_tick(max_jiffies);
297
298 if (accounted < max_jiffies)
> 299 accounted += irqtime_account_hi_update(max_jiffies - accounted);
300
301 if (accounted < max_jiffies)
> 302 accounted += irqtime_account_si_update(max_jiffies - accounted);
303
304 return accounted;
305 }
---
0-DAY kernel test infrastructure Open Source Technology Center
https://lists.01.org/pipermail/kbuild-all Intel Corporation
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-06-21 23:30 +0200 |
| Message-ID | <rMBp8-2Kp-27@gated-at.bofh.it> |
| In reply to | #1424230 |
On Thu, Jun 16, 2016 at 12:06:03PM -0400, riel@redhat.com wrote:
> +static unsigned long irqtime_account_hi_update(unsigned long max_jiffies)
> {
> u64 *cpustat = kcpustat_this_cpu->cpustat;
> + unsigned long irq_jiffies;
> unsigned long flags;
> + u64 irq;
>
> local_irq_save(flags);
> + irq = this_cpu_read(cpu_hardirq_time) - cpustat[CPUTIME_IRQ];
> + irq_jiffies = min(cputime_to_jiffies(irq), max_jiffies);
cputime_to_jiffies is a division, could we not avoid that by doing
something like:
irq_jiffies = min(irq, jiffies_to_cputime(max_jiffies));
while (irq_jiffies > cputime_one_jiffy) {
irq_jiffies -= cputime_one_jiffy;
cpustat[CPUTIME_IRQ] += cputime_one_jiffy;
}
assuming that the loop is 'rare' etc.. If not, only do the division on
that same > cputime_one_jiffy condition.
> + if (irq_jiffies)
> + cpustat[CPUTIME_IRQ] += jiffies_to_cputime(irq_jiffies);
> local_irq_restore(flags);
> + return irq_jiffies;
> }
[toc] | [prev] | [next] | [standalone]
| From | Rik van Riel <riel@redhat.com> |
|---|---|
| Date | 2016-06-22 00:30 +0200 |
| Subject | Re: [PATCH 1/5] sched,time: count actually elapsed irq & softirq time |
| Message-ID | <rMClc-3lP-49@gated-at.bofh.it> |
| In reply to | #1428186 |
[Multipart message — attachments visible in raw view] — view raw
On Tue, 2016-06-21 at 23:21 +0200, Peter Zijlstra wrote:
> On Thu, Jun 16, 2016 at 12:06:03PM -0400, riel@redhat.com wrote:
> >
> > +static unsigned long irqtime_account_hi_update(unsigned long
> > max_jiffies)
> > {
> > u64 *cpustat = kcpustat_this_cpu->cpustat;
> > + unsigned long irq_jiffies;
> > unsigned long flags;
> > + u64 irq;
> >
> > local_irq_save(flags);
> > + irq = this_cpu_read(cpu_hardirq_time) -
> > cpustat[CPUTIME_IRQ];
> > + irq_jiffies = min(cputime_to_jiffies(irq), max_jiffies);
> cputime_to_jiffies is a division, could we not avoid that by doing
> something like:
>
> irq_jiffies = min(irq, jiffies_to_cputime(max_jiffies));
> while (irq_jiffies > cputime_one_jiffy) {
> irq_jiffies -= cputime_one_jiffy;
> cpustat[CPUTIME_IRQ] += cputime_one_jiffy;
> }
>
> assuming that the loop is 'rare' etc.. If not, only do the division
> on
> that same > cputime_one_jiffy condition.
I suspect the loop is not rare on systems with nohz_idle,
where it may be quite a while before a timer tick happens
on an idle cpu.
I can certainly make sure the division is only done when
irq > 2*cputime_one_jiffy. I will do that in the next
version.
--
All Rights Reversed.
[toc] | [prev] | [next] | [standalone]
| From | Paolo Bonzini <pbonzini@redhat.com> |
|---|---|
| Date | 2016-06-22 12:50 +0200 |
| Message-ID | <rMNTj-2fc-3@gated-at.bofh.it> |
| In reply to | #1428186 |
On 21/06/2016 23:21, Peter Zijlstra wrote:
> cputime_to_jiffies is a division, could we not avoid that by doing
> something like:
>
> irq_jiffies = min(irq, jiffies_to_cputime(max_jiffies));
> while (irq_jiffies > cputime_one_jiffy) {
> irq_jiffies -= cputime_one_jiffy;
> cpustat[CPUTIME_IRQ] += cputime_one_jiffy;
> }
>
> assuming that the loop is 'rare' etc.. If not, only do the division on
> that same > cputime_one_jiffy condition.
It's a division by a constant, it ought to become a multiplication. For
64-bit it will, and context tracking is only enabled for 64-bit.
BTW, for 32-bit there's a monster of a macro to turn do_div with
constant divisor into multiplications in include/asm-generic/div64.h.
However, x86-32 doesn't use it.
Paolo
[toc] | [prev] | [next] | [standalone]
| From | Peter Zijlstra <peterz@infradead.org> |
|---|---|
| Date | 2016-06-22 13:00 +0200 |
| Message-ID | <rMO30-2iH-3@gated-at.bofh.it> |
| In reply to | #1428678 |
On Wed, Jun 22, 2016 at 12:40:31PM +0200, Paolo Bonzini wrote:
>
>
> On 21/06/2016 23:21, Peter Zijlstra wrote:
> > cputime_to_jiffies is a division, could we not avoid that by doing
> > something like:
> >
> > irq_jiffies = min(irq, jiffies_to_cputime(max_jiffies));
> > while (irq_jiffies > cputime_one_jiffy) {
> > irq_jiffies -= cputime_one_jiffy;
> > cpustat[CPUTIME_IRQ] += cputime_one_jiffy;
> > }
> >
> > assuming that the loop is 'rare' etc.. If not, only do the division on
> > that same > cputime_one_jiffy condition.
>
> It's a division by a constant, it ought to become a multiplication. For
> 64-bit it will, and context tracking is only enabled for 64-bit.
Right, not enabled on i386, however plenty 32bit archs (including ARM)
do have it enabled.
> BTW, for 32-bit there's a monster of a macro to turn do_div with
> constant divisor into multiplications in include/asm-generic/div64.h.
> However, x86-32 doesn't use it.
Right, but some ARM chips don't exactly have a fast multiplier either,
so avoiding even the 64bit mult (which ends up being 3 or so actual
mult instructions) is worthwhile I'd say.
[toc] | [prev] | [standalone]
Back to top | Article view | linux.kernel
csiph-web