Commit a7e1a9e3af71b45ecae2dae35851f238117b317d

Authored by Frederic Weisbecker
1 parent bf9fae9f5e

vtime: Consolidate system/idle context detection

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>

Showing 5 changed files with 73 additions and 30 deletions Side-by-side Diff

arch/ia64/kernel/time.c
... ... @@ -116,29 +116,32 @@
116 116 * Account time for a transition between system, hard irq or soft irq state.
117 117 * Note that this function is called with interrupts enabled.
118 118 */
119   -void vtime_account(struct task_struct *tsk)
  119 +static cputime_t vtime_delta(struct task_struct *tsk)
120 120 {
121 121 struct thread_info *ti = task_thread_info(tsk);
122   - unsigned long flags;
123 122 cputime_t delta_stime;
124 123 __u64 now;
125 124  
126   - local_irq_save(flags);
127   -
128 125 now = ia64_get_itc();
129 126  
130 127 delta_stime = cycle_to_cputime(ti->ac_stime + (now - ti->ac_stamp));
131   - if (irq_count() || idle_task(smp_processor_id()) != tsk)
132   - account_system_time(tsk, 0, delta_stime, delta_stime);
133   - else
134   - account_idle_time(delta_stime);
135 128 ti->ac_stime = 0;
136   -
137 129 ti->ac_stamp = now;
138 130  
139   - local_irq_restore(flags);
  131 + return delta_stime;
140 132 }
141   -EXPORT_SYMBOL_GPL(vtime_account);
  133 +
  134 +void vtime_account_system(struct task_struct *tsk)
  135 +{
  136 + cputime_t delta = vtime_delta(tsk);
  137 +
  138 + account_system_time(tsk, 0, delta, delta);
  139 +}
  140 +
  141 +void vtime_account_idle(struct task_struct *tsk)
  142 +{
  143 + account_idle_time(vtime_delta(tsk));
  144 +}
142 145  
143 146 /*
144 147 * Called from the timer interrupt handler to charge accumulated user time
arch/powerpc/kernel/time.c
... ... @@ -291,13 +291,12 @@
291 291 * Account time for a transition between system, hard irq
292 292 * or soft irq state.
293 293 */
294   -void vtime_account(struct task_struct *tsk)
  294 +static u64 vtime_delta(struct task_struct *tsk,
  295 + u64 *sys_scaled, u64 *stolen)
295 296 {
296   - u64 now, nowscaled, delta, deltascaled;
297   - unsigned long flags;
298   - u64 stolen, udelta, sys_scaled, user_scaled;
  297 + u64 now, nowscaled, deltascaled;
  298 + u64 udelta, delta, user_scaled;
299 299  
300   - local_irq_save(flags);
301 300 now = mftb();
302 301 nowscaled = read_spurr(now);
303 302 get_paca()->system_time += now - get_paca()->starttime;
... ... @@ -305,7 +304,7 @@
305 304 deltascaled = nowscaled - get_paca()->startspurr;
306 305 get_paca()->startspurr = nowscaled;
307 306  
308   - stolen = calculate_stolen_time(now);
  307 + *stolen = calculate_stolen_time(now);
309 308  
310 309 delta = get_paca()->system_time;
311 310 get_paca()->system_time = 0;
312 311  
313 312  
314 313  
315 314  
... ... @@ -322,28 +321,38 @@
322 321 * the user ticks get saved up in paca->user_time_scaled to be
323 322 * used by account_process_tick.
324 323 */
325   - sys_scaled = delta;
  324 + *sys_scaled = delta;
326 325 user_scaled = udelta;
327 326 if (deltascaled != delta + udelta) {
328 327 if (udelta) {
329   - sys_scaled = deltascaled * delta / (delta + udelta);
330   - user_scaled = deltascaled - sys_scaled;
  328 + *sys_scaled = deltascaled * delta / (delta + udelta);
  329 + user_scaled = deltascaled - *sys_scaled;
331 330 } else {
332   - sys_scaled = deltascaled;
  331 + *sys_scaled = deltascaled;
333 332 }
334 333 }
335 334 get_paca()->user_time_scaled += user_scaled;
336 335  
337   - if (in_interrupt() || idle_task(smp_processor_id()) != tsk) {
338   - account_system_time(tsk, 0, delta, sys_scaled);
339   - if (stolen)
340   - account_steal_time(stolen);
341   - } else {
342   - account_idle_time(delta + stolen);
343   - }
344   - local_irq_restore(flags);
  336 + return delta;
345 337 }
346   -EXPORT_SYMBOL_GPL(vtime_account);
  338 +
  339 +void vtime_account_system(struct task_struct *tsk)
  340 +{
  341 + u64 delta, sys_scaled, stolen;
  342 +
  343 + delta = vtime_delta(tsk, &sys_scaled, &stolen);
  344 + account_system_time(tsk, 0, delta, sys_scaled);
  345 + if (stolen)
  346 + account_steal_time(stolen);
  347 +}
  348 +
  349 +void vtime_account_idle(struct task_struct *tsk)
  350 +{
  351 + u64 delta, sys_scaled, stolen;
  352 +
  353 + delta = vtime_delta(tsk, &sys_scaled, &stolen);
  354 + account_idle_time(delta + stolen);
  355 +}
347 356  
348 357 /*
349 358 * Transfer the user and system times accumulated in the paca
arch/s390/include/asm/cputime.h
... ... @@ -12,6 +12,9 @@
12 12 #include <linux/spinlock.h>
13 13 #include <asm/div64.h>
14 14  
  15 +
  16 +#define __ARCH_HAS_VTIME_ACCOUNT
  17 +
15 18 /* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
16 19  
17 20 typedef unsigned long long __nocast cputime_t;
include/linux/kernel_stat.h
... ... @@ -132,6 +132,8 @@
132 132  
133 133 #ifdef CONFIG_VIRT_CPU_ACCOUNTING
134 134 extern void vtime_task_switch(struct task_struct *prev);
  135 +extern void vtime_account_system(struct task_struct *tsk);
  136 +extern void vtime_account_idle(struct task_struct *tsk);
135 137 #else
136 138 static inline void vtime_task_switch(struct task_struct *prev) { }
137 139 #endif
kernel/sched/cputime.c
... ... @@ -432,6 +432,32 @@
432 432 *ut = cputime.utime;
433 433 *st = cputime.stime;
434 434 }
  435 +
  436 +/*
  437 + * Archs that account the whole time spent in the idle task
  438 + * (outside irq) as idle time can rely on this and just implement
  439 + * vtime_account_system() and vtime_account_idle(). Archs that
  440 + * have other meaning of the idle time (s390 only includes the
  441 + * time spent by the CPU when it's in low power mode) must override
  442 + * vtime_account().
  443 + */
  444 +#ifndef __ARCH_HAS_VTIME_ACCOUNT
  445 +void vtime_account(struct task_struct *tsk)
  446 +{
  447 + unsigned long flags;
  448 +
  449 + local_irq_save(flags);
  450 +
  451 + if (in_interrupt() || !is_idle_task(tsk))
  452 + vtime_account_system(tsk);
  453 + else
  454 + vtime_account_idle(tsk);
  455 +
  456 + local_irq_restore(flags);
  457 +}
  458 +EXPORT_SYMBOL_GPL(vtime_account);
  459 +#endif /* __ARCH_HAS_VTIME_ACCOUNT */
  460 +
435 461 #else
436 462  
437 463 #ifndef nsecs_to_cputime