Commit 2d513868 authored by Thomas Gleixner's avatar Thomas Gleixner Committed by Ingo Molnar

sched: Sanitize irq accounting madness

Russell reported, that irqtime_account_idle_ticks() takes ages due to:

       for (i = 0; i < ticks; i++)
               irqtime_account_process_tick(current, 0, rq);

It's sad, that this code was written way _AFTER_ the NOHZ idle
functionality was available. I charge myself guitly for not paying
attention when that crap got merged with commit abb74cef ("sched:
Export ns irqtimes through /proc/stat")

So instead of looping nr_ticks times just apply the whole thing at
once.

As a side note: The whole cputime_t vs. u64 business in that context
wants to be cleaned up as well. There is no point in having all these
back and forth conversions. Lets standardise on u64 nsec for all
kernel internal accounting and be done with it. Everything else does
not make sense at all for fine grained accounting. Frederic, can you
please take care of that?
Reported-by: default avatarRussell King <rmk+kernel@arm.linux.org.uk>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Reviewed-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Signed-off-by: default avatarPeter Zijlstra <peterz@infradead.org>
Cc: Venkatesh Pallipadi <venki@google.com>
Cc: Shaun Ruffell <sruffell@digium.com>
Cc: stable@vger.kernel.org
Link: http://lkml.kernel.org/r/alpine.DEB.2.02.1405022307000.6261@ionos.tec.linutronix.deSigned-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent db66d756
...@@ -332,50 +332,50 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times) ...@@ -332,50 +332,50 @@ void thread_group_cputime(struct task_struct *tsk, struct task_cputime *times)
* softirq as those do not count in task exec_runtime any more. * softirq as those do not count in task exec_runtime any more.
*/ */
static void irqtime_account_process_tick(struct task_struct *p, int user_tick, static void irqtime_account_process_tick(struct task_struct *p, int user_tick,
struct rq *rq) struct rq *rq, int ticks)
{ {
cputime_t one_jiffy_scaled = cputime_to_scaled(cputime_one_jiffy); cputime_t scaled = cputime_to_scaled(cputime_one_jiffy);
u64 cputime = (__force u64) cputime_one_jiffy;
u64 *cpustat = kcpustat_this_cpu->cpustat; u64 *cpustat = kcpustat_this_cpu->cpustat;
if (steal_account_process_tick()) if (steal_account_process_tick())
return; return;
cputime *= ticks;
scaled *= ticks;
if (irqtime_account_hi_update()) { if (irqtime_account_hi_update()) {
cpustat[CPUTIME_IRQ] += (__force u64) cputime_one_jiffy; cpustat[CPUTIME_IRQ] += cputime;
} else if (irqtime_account_si_update()) { } else if (irqtime_account_si_update()) {
cpustat[CPUTIME_SOFTIRQ] += (__force u64) cputime_one_jiffy; cpustat[CPUTIME_SOFTIRQ] += cputime;
} else if (this_cpu_ksoftirqd() == p) { } else if (this_cpu_ksoftirqd() == p) {
/* /*
* ksoftirqd time do not get accounted in cpu_softirq_time. * ksoftirqd time do not get accounted in cpu_softirq_time.
* So, we have to handle it separately here. * So, we have to handle it separately here.
* Also, p->stime needs to be updated for ksoftirqd. * Also, p->stime needs to be updated for ksoftirqd.
*/ */
__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, __account_system_time(p, cputime, scaled, CPUTIME_SOFTIRQ);
CPUTIME_SOFTIRQ);
} else if (user_tick) { } else if (user_tick) {
account_user_time(p, cputime_one_jiffy, one_jiffy_scaled); account_user_time(p, cputime, scaled);
} else if (p == rq->idle) { } else if (p == rq->idle) {
account_idle_time(cputime_one_jiffy); account_idle_time(cputime);
} else if (p->flags & PF_VCPU) { /* System time or guest time */ } else if (p->flags & PF_VCPU) { /* System time or guest time */
account_guest_time(p, cputime_one_jiffy, one_jiffy_scaled); account_guest_time(p, cputime, scaled);
} else { } else {
__account_system_time(p, cputime_one_jiffy, one_jiffy_scaled, __account_system_time(p, cputime, scaled, CPUTIME_SYSTEM);
CPUTIME_SYSTEM);
} }
} }
static void irqtime_account_idle_ticks(int ticks) static void irqtime_account_idle_ticks(int ticks)
{ {
int i;
struct rq *rq = this_rq(); struct rq *rq = this_rq();
for (i = 0; i < ticks; i++) irqtime_account_process_tick(current, 0, rq, ticks);
irqtime_account_process_tick(current, 0, rq);
} }
#else /* CONFIG_IRQ_TIME_ACCOUNTING */ #else /* CONFIG_IRQ_TIME_ACCOUNTING */
static inline void irqtime_account_idle_ticks(int ticks) {} static inline void irqtime_account_idle_ticks(int ticks) {}
static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick, static inline void irqtime_account_process_tick(struct task_struct *p, int user_tick,
struct rq *rq) {} struct rq *rq, int nr_ticks) {}
#endif /* CONFIG_IRQ_TIME_ACCOUNTING */ #endif /* CONFIG_IRQ_TIME_ACCOUNTING */
/* /*
...@@ -464,7 +464,7 @@ void account_process_tick(struct task_struct *p, int user_tick) ...@@ -464,7 +464,7 @@ void account_process_tick(struct task_struct *p, int user_tick)
return; return;
if (sched_clock_irqtime) { if (sched_clock_irqtime) {
irqtime_account_process_tick(p, user_tick, rq); irqtime_account_process_tick(p, user_tick, rq, 1);
return; return;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment