Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+73 -30
+14 -11
arch/ia64/kernel/time.c
··· 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 - 126 - local_irq_save(flags); 127 124 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
+28 -19
arch/powerpc/kernel/time.c
··· 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; ··· 304 305 deltascaled = nowscaled - get_paca()->startspurr; 305 306 get_paca()->startspurr = nowscaled; 306 307 307 - stolen = calculate_stolen_time(now); 308 + *stolen = calculate_stolen_time(now); 308 309 309 310 delta = get_paca()->system_time; 310 311 get_paca()->system_time = 0; ··· 321 322 * the user ticks get saved up in paca->user_time_scaled to be 322 323 * used by account_process_tick. 323 324 */ 324 - sys_scaled = delta; 325 + *sys_scaled = delta; 325 326 user_scaled = udelta; 326 327 if (deltascaled != delta + udelta) { 327 328 if (udelta) { 328 - sys_scaled = deltascaled * delta / (delta + udelta); 329 - user_scaled = deltascaled - sys_scaled; 329 + *sys_scaled = deltascaled * delta / (delta + udelta); 330 + user_scaled = deltascaled - *sys_scaled; 330 331 } else { 331 - sys_scaled = deltascaled; 332 + *sys_scaled = deltascaled; 332 333 } 333 334 } 334 335 get_paca()->user_time_scaled += user_scaled; 335 336 336 - if (in_interrupt() || idle_task(smp_processor_id()) != tsk) { 337 - account_system_time(tsk, 0, delta, sys_scaled); 338 - if (stolen) 339 - account_steal_time(stolen); 340 - } else { 341 - account_idle_time(delta + stolen); 342 - } 343 - local_irq_restore(flags); 337 + return delta; 344 338 } 345 - EXPORT_SYMBOL_GPL(vtime_account); 339 + 340 + void vtime_account_system(struct task_struct *tsk) 341 + { 342 + u64 delta, sys_scaled, stolen; 343 + 344 + delta = vtime_delta(tsk, &sys_scaled, &stolen); 345 + account_system_time(tsk, 0, delta, sys_scaled); 346 + if (stolen) 347 + account_steal_time(stolen); 348 + } 349 + 350 + void vtime_account_idle(struct task_struct *tsk) 351 + { 352 + u64 delta, sys_scaled, stolen; 353 + 354 + delta = vtime_delta(tsk, &sys_scaled, &stolen); 355 + account_idle_time(delta + stolen); 356 + } 346 357 347 358 /* 348 359 * Transfer the user and system times accumulated in the paca
+3
arch/s390/include/asm/cputime.h
··· 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;
+2
include/linux/kernel_stat.h
··· 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
+26
kernel/sched/cputime.c
··· 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