In the unlikely event more than one tick's worth has accumulated, add all the remaining time to cpustat. -ck --- kernel/sched/bfs.c | 51 ++++++++++++++++++++++++++++----------------------- 1 file changed, 28 insertions(+), 23 deletions(-) Index: linux-3.7-bfs/kernel/sched/bfs.c =================================================================== --- linux-3.7-bfs.orig/kernel/sched/bfs.c 2013-01-29 01:22:36.807775273 +1100 +++ linux-3.7-bfs/kernel/sched/bfs.c 2013-01-29 01:22:37.207770272 +1100 @@ -2359,23 +2359,24 @@ static __always_inline bool steal_accoun * accumulated one tick's worth, account for that. This means the total * percentage of load components will always be 128 (pseudo 100) per tick. */ -static void pc_idle_time(struct rq *rq, unsigned long pc) +static void pc_idle_time(struct rq *rq, struct task_struct *idle, unsigned long pc) { u64 *cpustat = kcpustat_this_cpu->cpustat; if (atomic_read(&rq->nr_iowait) > 0) { rq->iowait_pc += pc; if (rq->iowait_pc >= 128) { + cpustat[CPUTIME_IOWAIT] += (__force u64)cputime_one_jiffy * rq->iowait_pc / 128; rq->iowait_pc %= 128; - cpustat[CPUTIME_IOWAIT] += (__force u64)cputime_one_jiffy; } } else { rq->idle_pc += pc; if (rq->idle_pc >= 128) { + cpustat[CPUTIME_IDLE] += (__force u64)cputime_one_jiffy * rq->idle_pc / 128; rq->idle_pc %= 128; - cpustat[CPUTIME_IDLE] += (__force u64)cputime_one_jiffy; } } + acct_update_integrals(idle); } static void @@ -2387,33 +2388,35 @@ pc_system_time(struct rq *rq, struct tas p->stime_pc += pc; if (p->stime_pc >= 128) { + int jiffs = p->stime_pc / 128; + p->stime_pc %= 128; - p->stime += (__force u64)cputime_one_jiffy; - p->stimescaled += one_jiffy_scaled; - account_group_system_time(p, cputime_one_jiffy); - acct_update_integrals(p); + p->stime += (__force u64)cputime_one_jiffy * jiffs; + p->stimescaled += one_jiffy_scaled * jiffs; + account_group_system_time(p, cputime_one_jiffy * jiffs); } p->sched_time += ns; if (hardirq_count() - hardirq_offset) { rq->irq_pc += pc; if (rq->irq_pc >= 128) { + cpustat[CPUTIME_IRQ] += (__force u64)cputime_one_jiffy * rq->irq_pc / 128; rq->irq_pc %= 128; - cpustat[CPUTIME_IRQ] += (__force u64)cputime_one_jiffy; } } else if (in_serving_softirq()) { rq->softirq_pc += pc; if (rq->softirq_pc >= 128) { + cpustat[CPUTIME_SOFTIRQ] += (__force u64)cputime_one_jiffy * rq->softirq_pc / 128; rq->softirq_pc %= 128; - cpustat[CPUTIME_SOFTIRQ] += (__force u64)cputime_one_jiffy; } } else { rq->system_pc += pc; if (rq->system_pc >= 128) { + cpustat[CPUTIME_SYSTEM] += (__force u64)cputime_one_jiffy * rq->system_pc / 128; rq->system_pc %= 128; - cpustat[CPUTIME_SYSTEM] += (__force u64)cputime_one_jiffy; } } + acct_update_integrals(p); } static void pc_user_time(struct rq *rq, struct task_struct *p, @@ -2424,11 +2427,12 @@ static void pc_user_time(struct rq *rq, p->utime_pc += pc; if (p->utime_pc >= 128) { + int jiffs = p->utime_pc / 128; + p->utime_pc %= 128; - p->utime += (__force u64)cputime_one_jiffy; - p->utimescaled += one_jiffy_scaled; - account_group_user_time(p, cputime_one_jiffy); - acct_update_integrals(p); + p->utime += (__force u64)cputime_one_jiffy * jiffs; + p->utimescaled += one_jiffy_scaled * jiffs; + account_group_user_time(p, cputime_one_jiffy * jiffs); } p->sched_time += ns; @@ -2439,24 +2443,25 @@ static void pc_user_time(struct rq *rq, */ rq->softirq_pc += pc; if (rq->softirq_pc >= 128) { + cpustat[CPUTIME_SOFTIRQ] += (__force u64)cputime_one_jiffy * rq->softirq_pc / 128; rq->softirq_pc %= 128; - cpustat[CPUTIME_SOFTIRQ] += (__force u64)cputime_one_jiffy; } } if (TASK_NICE(p) > 0 || idleprio_task(p)) { rq->nice_pc += pc; if (rq->nice_pc >= 128) { + cpustat[CPUTIME_NICE] += (__force u64)cputime_one_jiffy * rq->nice_pc / 128; rq->nice_pc %= 128; - cpustat[CPUTIME_NICE] += (__force u64)cputime_one_jiffy; } } else { rq->user_pc += pc; if (rq->user_pc >= 128) { + cpustat[CPUTIME_USER] += (__force u64)cputime_one_jiffy * rq->user_pc / 128; rq->user_pc %= 128; - cpustat[CPUTIME_USER] += (__force u64)cputime_one_jiffy; } } + acct_update_integrals(p); } /* @@ -2474,14 +2479,13 @@ static void update_cpu_clock(struct rq *rq, struct task_struct *p, bool tick) { long account_ns = rq->clock - rq->timekeep_clock; - struct task_struct *idle; + struct task_struct *idle = rq->idle; unsigned long account_pc; if (unlikely(account_ns < 0)) - goto out; + goto ts_account; account_pc = NS_TO_PC(account_ns); - idle = rq->idle; if (tick) { /* Accurate tick timekeeping */ @@ -2494,14 +2498,14 @@ update_cpu_clock(struct rq *rq, struct t pc_system_time(rq, p, HARDIRQ_OFFSET, account_pc, account_ns); else - pc_idle_time(rq, account_pc); + pc_idle_time(rq, idle, account_pc); if (sched_clock_irqtime) irqtime_account_hi_si(); } else { /* Accurate subtick timekeeping */ if (p == idle) - pc_idle_time(rq, account_pc); + pc_idle_time(rq, idle, account_pc); else pc_user_time(rq, p, account_pc, account_ns); } @@ -2514,7 +2518,7 @@ ts_account: niffy_diff(&time_diff, 1); rq->rq_time_slice -= NS_TO_US(time_diff); } -out: + rq->rq_last_ran = rq->timekeep_clock = rq->clock; } @@ -3324,6 +3328,7 @@ need_resched: } if (likely(prev != next)) { + resched_suitable_idle(prev); /* * Don't stick tasks when a real time task is going to run as * they may literally get stuck.