From fb408cd5617b85291a046d7755a6fe5ed85a8ff8 Mon Sep 17 00:00:00 2001 From: Frederic Weisbecker Date: Sat, 6 Oct 2012 04:07:19 +0200 Subject: [PATCH] --- yaml --- r: 339081 b: refs/heads/master c: fa5058f3b63153e0147ef65bcdb3a4ee63581346 h: refs/heads/master i: 339079: 68f3ac88c2a77fbaf89f6f531e4cd26d015ad7c9 v: v3 --- [refs] | 2 +- trunk/include/linux/hardirq.h | 4 ++-- trunk/include/linux/vtime.h | 25 +++++++++++++++++++++++++ trunk/kernel/softirq.c | 6 +++--- 4 files changed, 31 insertions(+), 6 deletions(-) diff --git a/[refs] b/[refs] index 8bf1cc8b99ec..52c17f9a0ce9 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: b080935c8638e08134629d0a9ebdf35669bec14d +refs/heads/master: fa5058f3b63153e0147ef65bcdb3a4ee63581346 diff --git a/trunk/include/linux/hardirq.h b/trunk/include/linux/hardirq.h index b083a475423d..624ef3f45c8e 100644 --- a/trunk/include/linux/hardirq.h +++ b/trunk/include/linux/hardirq.h @@ -153,7 +153,7 @@ extern void rcu_nmi_exit(void); */ #define __irq_enter() \ do { \ - vtime_account(current); \ + vtime_account_irq_enter(current); \ add_preempt_count(HARDIRQ_OFFSET); \ trace_hardirq_enter(); \ } while (0) @@ -169,7 +169,7 @@ extern void irq_enter(void); #define __irq_exit() \ do { \ trace_hardirq_exit(); \ - vtime_account(current); \ + vtime_account_irq_exit(current); \ sub_preempt_count(HARDIRQ_OFFSET); \ } while (0) diff --git a/trunk/include/linux/vtime.h b/trunk/include/linux/vtime.h index b9fc4f9ab470..c35c02223da8 100644 --- a/trunk/include/linux/vtime.h +++ b/trunk/include/linux/vtime.h @@ -21,4 +21,29 @@ static inline void vtime_account(struct task_struct *tsk) extern void vtime_account(struct task_struct *tsk); #endif +static inline void vtime_account_irq_enter(struct task_struct *tsk) +{ + /* + * Hardirq can interrupt idle task anytime. So we need vtime_account() + * that performs the idle check in CONFIG_VIRT_CPU_ACCOUNTING. + * Softirq can also interrupt idle task directly if it calls + * local_bh_enable(). Such case probably don't exist but we never know. + * Ksoftirqd is not concerned because idle time is flushed on context + * switch. Softirqs in the end of hardirqs are also not a problem because + * the idle time is flushed on hardirq time already. + */ + vtime_account(tsk); +} + +static inline void vtime_account_irq_exit(struct task_struct *tsk) +{ +#ifdef CONFIG_VIRT_CPU_ACCOUNTING + /* On hard|softirq exit we always account to hard|softirq cputime */ + __vtime_account_system(tsk); +#endif +#ifdef CONFIG_IRQ_TIME_ACCOUNTING + vtime_account(tsk); +#endif +} + #endif /* _LINUX_KERNEL_VTIME_H */ diff --git a/trunk/kernel/softirq.c b/trunk/kernel/softirq.c index cc96bdc0c2c9..ed567babe789 100644 --- a/trunk/kernel/softirq.c +++ b/trunk/kernel/softirq.c @@ -221,7 +221,7 @@ asmlinkage void __do_softirq(void) current->flags &= ~PF_MEMALLOC; pending = local_softirq_pending(); - vtime_account(current); + vtime_account_irq_enter(current); __local_bh_disable((unsigned long)__builtin_return_address(0), SOFTIRQ_OFFSET); @@ -272,7 +272,7 @@ asmlinkage void __do_softirq(void) lockdep_softirq_exit(); - vtime_account(current); + vtime_account_irq_exit(current); __local_bh_enable(SOFTIRQ_OFFSET); tsk_restore_flags(current, old_flags, PF_MEMALLOC); } @@ -341,7 +341,7 @@ static inline void invoke_softirq(void) */ void irq_exit(void) { - vtime_account(current); + vtime_account_irq_exit(current); trace_hardirq_exit(); sub_preempt_count(IRQ_EXIT_OFFSET); if (!in_interrupt() && local_softirq_pending())