vtime: Consolidate system/idle context detection
authorFrederic Weisbecker <fweisbec@gmail.com>
Sat, 8 Sep 2012 14:14:02 +0000 (16:14 +0200)
committerFrederic Weisbecker <fweisbec@gmail.com>
Tue, 25 Sep 2012 13:42:37 +0000 (15:42 +0200)
Move the code that finds out to which context we account the
cputime into generic layer.

Archs that consider the whole time spent in the idle task as idle
time (ia64, powerpc) can rely on the generic vtime_account()
and implement vtime_account_system() and vtime_account_idle(),
letting the generic code to decide when to call which API.

Archs that have their own meaning of idle time, such as s390
that only considers the time spent in CPU low power mode as idle
time, can just override vtime_account().

Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Tony Luck <tony.luck@intel.com>
Cc: Fenghua Yu <fenghua.yu@intel.com>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Martin Schwidefsky <schwidefsky@de.ibm.com>
Cc: Heiko Carstens <heiko.carstens@de.ibm.com>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>
arch/ia64/kernel/time.c
arch/powerpc/kernel/time.c
arch/s390/include/asm/cputime.h
include/linux/kernel_stat.h
kernel/sched/cputime.c

index 16bb6eda879df994c194b8bb91f30f8b6979f31e..01cd43e491cd0b7117264aeca2d95d3aac7e507b 100644 (file)
@@ -116,29 +116,32 @@ void vtime_task_switch(struct task_struct *prev)
  * Account time for a transition between system, hard irq or soft irq state.
  * Note that this function is called with interrupts enabled.
  */
-void vtime_account(struct task_struct *tsk)
+static cputime_t vtime_delta(struct task_struct *tsk)
 {
        struct thread_info *ti = task_thread_info(tsk);
-       unsigned long flags;
        cputime_t delta_stime;
        __u64 now;
 
-       local_irq_save(flags);
-
        now = ia64_get_itc();
 
        delta_stime = cycle_to_cputime(ti->ac_stime + (now - ti->ac_stamp));
-       if (irq_count() || idle_task(smp_processor_id()) != tsk)
-               account_system_time(tsk, 0, delta_stime, delta_stime);
-       else
-               account_idle_time(delta_stime);
        ti->ac_stime = 0;
-
        ti->ac_stamp = now;
 
-       local_irq_restore(flags);
+       return delta_stime;
+}
+
+void vtime_account_system(struct task_struct *tsk)
+{
+       cputime_t delta = vtime_delta(tsk);
+
+       account_system_time(tsk, 0, delta, delta);
+}
+
+void vtime_account_idle(struct task_struct *tsk)
+{
+       account_idle_time(vtime_delta(tsk));
 }
-EXPORT_SYMBOL_GPL(vtime_account);
 
 /*
  * Called from the timer interrupt handler to charge accumulated user time
index 39899d7ebda0081a6057d6a999301aacdaf56b02..29b6d3e1ea28df7c15c9a94b444482312454a1d1 100644 (file)
@@ -291,13 +291,12 @@ static inline u64 calculate_stolen_time(u64 stop_tb)
  * Account time for a transition between system, hard irq
  * or soft irq state.
  */
-void vtime_account(struct task_struct *tsk)
+static u64 vtime_delta(struct task_struct *tsk,
+                       u64 *sys_scaled, u64 *stolen)
 {
-       u64 now, nowscaled, delta, deltascaled;
-       unsigned long flags;
-       u64 stolen, udelta, sys_scaled, user_scaled;
+       u64 now, nowscaled, deltascaled;
+       u64 udelta, delta, user_scaled;
 
-       local_irq_save(flags);
        now = mftb();
        nowscaled = read_spurr(now);
        get_paca()->system_time += now - get_paca()->starttime;
@@ -305,7 +304,7 @@ void vtime_account(struct task_struct *tsk)
        deltascaled = nowscaled - get_paca()->startspurr;
        get_paca()->startspurr = nowscaled;
 
-       stolen = calculate_stolen_time(now);
+       *stolen = calculate_stolen_time(now);
 
        delta = get_paca()->system_time;
        get_paca()->system_time = 0;
@@ -322,28 +321,38 @@ void vtime_account(struct task_struct *tsk)
         * the user ticks get saved up in paca->user_time_scaled to be
         * used by account_process_tick.
         */
-       sys_scaled = delta;
+       *sys_scaled = delta;
        user_scaled = udelta;
        if (deltascaled != delta + udelta) {
                if (udelta) {
-                       sys_scaled = deltascaled * delta / (delta + udelta);
-                       user_scaled = deltascaled - sys_scaled;
+                       *sys_scaled = deltascaled * delta / (delta + udelta);
+                       user_scaled = deltascaled - *sys_scaled;
                } else {
-                       sys_scaled = deltascaled;
+                       *sys_scaled = deltascaled;
                }
        }
        get_paca()->user_time_scaled += user_scaled;
 
-       if (in_interrupt() || idle_task(smp_processor_id()) != tsk) {
-               account_system_time(tsk, 0, delta, sys_scaled);
-               if (stolen)
-                       account_steal_time(stolen);
-       } else {
-               account_idle_time(delta + stolen);
-       }
-       local_irq_restore(flags);
+       return delta;
+}
+
+void vtime_account_system(struct task_struct *tsk)
+{
+       u64 delta, sys_scaled, stolen;
+
+       delta = vtime_delta(tsk, &sys_scaled, &stolen);
+       account_system_time(tsk, 0, delta, sys_scaled);
+       if (stolen)
+               account_steal_time(stolen);
+}
+
+void vtime_account_idle(struct task_struct *tsk)
+{
+       u64 delta, sys_scaled, stolen;
+
+       delta = vtime_delta(tsk, &sys_scaled, &stolen);
+       account_idle_time(delta + stolen);
 }
-EXPORT_SYMBOL_GPL(vtime_account);
 
 /*
  * Transfer the user and system times accumulated in the paca
index 8709bdef233cc5a7a42d3b9bafc19d0682167849..023d5ae24482f188b984e269923471649c71502a 100644 (file)
@@ -12,6 +12,9 @@
 #include <linux/spinlock.h>
 #include <asm/div64.h>
 
+
+#define __ARCH_HAS_VTIME_ACCOUNT
+
 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
 
 typedef unsigned long long __nocast cputime_t;
index ca0944b92f4abf5b0b1176db3680db6df9fcacd1..36d12f0884c3d287d31cd00e7c97e417249d67e9 100644 (file)
@@ -132,6 +132,8 @@ extern void account_idle_ticks(unsigned long ticks);
 
 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
 extern void vtime_task_switch(struct task_struct *prev);
+extern void vtime_account_system(struct task_struct *tsk);
+extern void vtime_account_idle(struct task_struct *tsk);
 #else
 static inline void vtime_task_switch(struct task_struct *prev) { }
 #endif
index 53f5b12f28212a1b2a79632956285589ab81b093..81b763ba58a669e940dd1d9b6aa7c730159c2eab 100644 (file)
@@ -432,6 +432,32 @@ void thread_group_times(struct task_struct *p, cputime_t *ut, cputime_t *st)
        *ut = cputime.utime;
        *st = cputime.stime;
 }
+
+/*
+ * Archs that account the whole time spent in the idle task
+ * (outside irq) as idle time can rely on this and just implement
+ * vtime_account_system() and vtime_account_idle(). Archs that
+ * have other meaning of the idle time (s390 only includes the
+ * time spent by the CPU when it's in low power mode) must override
+ * vtime_account().
+ */
+#ifndef __ARCH_HAS_VTIME_ACCOUNT
+void vtime_account(struct task_struct *tsk)
+{
+       unsigned long flags;
+
+       local_irq_save(flags);
+
+       if (in_interrupt() || !is_idle_task(tsk))
+               vtime_account_system(tsk);
+       else
+               vtime_account_idle(tsk);
+
+       local_irq_restore(flags);
+}
+EXPORT_SYMBOL_GPL(vtime_account);
+#endif /* __ARCH_HAS_VTIME_ACCOUNT */
+
 #else
 
 #ifndef nsecs_to_cputime