Commit fa13a5a1 authored by Paul Mackerras's avatar Paul Mackerras Committed by Ingo Molnar

sched: restore deterministic CPU accounting on powerpc

Since powerpc started using CONFIG_GENERIC_CLOCKEVENTS, the
deterministic CPU accounting (CONFIG_VIRT_CPU_ACCOUNTING) has been
broken on powerpc, because we end up counting user time twice: once in
timer_interrupt() and once in update_process_times().

This fixes the problem by pulling the code in update_process_times
that updates utime and stime into a separate function called
account_process_tick.  If CONFIG_VIRT_CPU_ACCOUNTING is not defined,
there is a version of account_process_tick in kernel/timer.c that
simply accounts a whole tick to either utime or stime as before.  If
CONFIG_VIRT_CPU_ACCOUNTING is defined, then arch code gets to
implement account_process_tick.

This also lets us simplify the s390 code a bit; it means that the s390
timer interrupt can now call update_process_times even when
CONFIG_VIRT_CPU_ACCOUNTING is turned on, and can just implement a
suitable account_process_tick().

account_process_tick() now takes the task_struct * as an argument.
Tested both with and without CONFIG_VIRT_CPU_ACCOUNTING.
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent 9a41785c
...@@ -350,7 +350,7 @@ struct task_struct *__switch_to(struct task_struct *prev, ...@@ -350,7 +350,7 @@ struct task_struct *__switch_to(struct task_struct *prev,
local_irq_save(flags); local_irq_save(flags);
account_system_vtime(current); account_system_vtime(current);
account_process_vtime(current); account_process_tick(current, 0);
calculate_steal_time(); calculate_steal_time();
last = _switch(old_thread, new_thread); last = _switch(old_thread, new_thread);
......
...@@ -259,7 +259,7 @@ void account_system_vtime(struct task_struct *tsk) ...@@ -259,7 +259,7 @@ void account_system_vtime(struct task_struct *tsk)
* user and system time records. * user and system time records.
* Must be called with interrupts disabled. * Must be called with interrupts disabled.
*/ */
void account_process_vtime(struct task_struct *tsk) void account_process_tick(struct task_struct *tsk, int user_tick)
{ {
cputime_t utime, utimescaled; cputime_t utime, utimescaled;
...@@ -274,18 +274,6 @@ void account_process_vtime(struct task_struct *tsk) ...@@ -274,18 +274,6 @@ void account_process_vtime(struct task_struct *tsk)
account_user_time_scaled(tsk, utimescaled); account_user_time_scaled(tsk, utimescaled);
} }
static void account_process_time(struct pt_regs *regs)
{
int cpu = smp_processor_id();
account_process_vtime(current);
run_local_timers();
if (rcu_pending(cpu))
rcu_check_callbacks(cpu, user_mode(regs));
scheduler_tick();
run_posix_cpu_timers(current);
}
/* /*
* Stuff for accounting stolen time. * Stuff for accounting stolen time.
*/ */
...@@ -375,7 +363,6 @@ static void snapshot_purr(void) ...@@ -375,7 +363,6 @@ static void snapshot_purr(void)
#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */ #else /* ! CONFIG_VIRT_CPU_ACCOUNTING */
#define calc_cputime_factors() #define calc_cputime_factors()
#define account_process_time(regs) update_process_times(user_mode(regs))
#define calculate_steal_time() do { } while (0) #define calculate_steal_time() do { } while (0)
#endif #endif
...@@ -599,16 +586,6 @@ void timer_interrupt(struct pt_regs * regs) ...@@ -599,16 +586,6 @@ void timer_interrupt(struct pt_regs * regs)
get_lppaca()->int_dword.fields.decr_int = 0; get_lppaca()->int_dword.fields.decr_int = 0;
#endif #endif
/*
* We cannot disable the decrementer, so in the period
* between this cpu's being marked offline in cpu_online_map
* and calling stop-self, it is taking timer interrupts.
* Avoid calling into the scheduler rebalancing code if this
* is the case.
*/
if (!cpu_is_offline(cpu))
account_process_time(regs);
if (evt->event_handler) if (evt->event_handler)
evt->event_handler(evt); evt->event_handler(evt);
else else
......
...@@ -145,12 +145,8 @@ void account_ticks(u64 time) ...@@ -145,12 +145,8 @@ void account_ticks(u64 time)
do_timer(ticks); do_timer(ticks);
#endif #endif
#ifdef CONFIG_VIRT_CPU_ACCOUNTING
account_tick_vtime(current);
#else
while (ticks--) while (ticks--)
update_process_times(user_mode(get_irq_regs())); update_process_times(user_mode(get_irq_regs()));
#endif
s390_do_profile(); s390_do_profile();
} }
......
...@@ -32,7 +32,7 @@ static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer); ...@@ -32,7 +32,7 @@ static DEFINE_PER_CPU(struct vtimer_queue, virt_cpu_timer);
* Update process times based on virtual cpu times stored by entry.S * Update process times based on virtual cpu times stored by entry.S
* to the lowcore fields user_timer, system_timer & steal_clock. * to the lowcore fields user_timer, system_timer & steal_clock.
*/ */
void account_tick_vtime(struct task_struct *tsk) void account_process_tick(struct task_struct *tsk, int user_tick)
{ {
cputime_t cputime; cputime_t cputime;
__u64 timer, clock; __u64 timer, clock;
...@@ -64,12 +64,6 @@ void account_tick_vtime(struct task_struct *tsk) ...@@ -64,12 +64,6 @@ void account_tick_vtime(struct task_struct *tsk)
S390_lowcore.steal_clock -= cputime << 12; S390_lowcore.steal_clock -= cputime << 12;
account_steal_time(tsk, cputime); account_steal_time(tsk, cputime);
} }
run_local_timers();
if (rcu_pending(smp_processor_id()))
rcu_check_callbacks(smp_processor_id(), rcu_user_flag);
scheduler_tick();
run_posix_cpu_timers(tsk);
} }
/* /*
......
...@@ -254,6 +254,7 @@ long io_schedule_timeout(long timeout); ...@@ -254,6 +254,7 @@ long io_schedule_timeout(long timeout);
extern void cpu_init (void); extern void cpu_init (void);
extern void trap_init(void); extern void trap_init(void);
extern void account_process_tick(struct task_struct *task, int user);
extern void update_process_times(int user); extern void update_process_times(int user);
extern void scheduler_tick(void); extern void scheduler_tick(void);
......
...@@ -817,6 +817,19 @@ unsigned long next_timer_interrupt(void) ...@@ -817,6 +817,19 @@ unsigned long next_timer_interrupt(void)
#endif #endif
#ifndef CONFIG_VIRT_CPU_ACCOUNTING
void account_process_tick(struct task_struct *p, int user_tick)
{
if (user_tick) {
account_user_time(p, jiffies_to_cputime(1));
account_user_time_scaled(p, jiffies_to_cputime(1));
} else {
account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
account_system_time_scaled(p, jiffies_to_cputime(1));
}
}
#endif
/* /*
* Called from the timer interrupt handler to charge one tick to the current * Called from the timer interrupt handler to charge one tick to the current
* process. user_tick is 1 if the tick is user time, 0 for system. * process. user_tick is 1 if the tick is user time, 0 for system.
...@@ -827,13 +840,7 @@ void update_process_times(int user_tick) ...@@ -827,13 +840,7 @@ void update_process_times(int user_tick)
int cpu = smp_processor_id(); int cpu = smp_processor_id();
/* Note: this timer irq context must be accounted for as well. */ /* Note: this timer irq context must be accounted for as well. */
if (user_tick) { account_process_tick(p, user_tick);
account_user_time(p, jiffies_to_cputime(1));
account_user_time_scaled(p, jiffies_to_cputime(1));
} else {
account_system_time(p, HARDIRQ_OFFSET, jiffies_to_cputime(1));
account_system_time_scaled(p, jiffies_to_cputime(1));
}
run_local_timers(); run_local_timers();
if (rcu_pending(cpu)) if (rcu_pending(cpu))
rcu_check_callbacks(cpu, user_tick); rcu_check_callbacks(cpu, user_tick);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment