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>
This commit is contained in:
parent
bf9fae9f5e
commit
a7e1a9e3af
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue