scheduler changes for v3.8
Linus,
Please pull the latest sched-core-for-linus git tree from:
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git sched-core-for-linus
HEAD: c1ad41f1f7270c1956da13fa8fd59d8d5929d56e Revert "sched/autogroup: Fix crash on reboot when autogroup is disabled"
The biggest change affects group scheduling: we now track the runnable average on a per-task entity basis, allowing a smoother, exponential decay average based load/weight estimation instead of the previous binary on-the-runqueue/off-the-runqueue load weight method.
This will inevitably disturb workloads that were in some sort of borderline balancing state or unstable equilibrium, so an eye has to be kept on regressions.
For that reason the new load average is only limited to group scheduling (shares distribution) at the moment (which was also hurting the most from the prior, crude weight calculation and whose scheduling quality wins most from this change) - but we plan to extend this to regular SMP balancing as well in the future, which will simplify and speed up things a bit.
Other changes involve ongoing preparatory work to extend NOHZ to the scheduler as well, eventually allowing completely irq-free user-space execution.
Thanks,
Ingo
------------------>
Ben Segall (1):
sched: Maintain per-rq runnable averages
Frederic Weisbecker (14):
vtime: Gather vtime declarations to their own header file
vtime: Make vtime_account_system() irqsafe
kvm: Directly account vtime to system on guest switch
cputime: Specialize irq vtime hooks
cputime: Separate irqtime accounting from generic vtime
vtime: Remove the underscore prefix invasion
vtime: Explicitly account pending user time on process tick
vtime: Consolidate a bit the ctx switch code
vtime: No need to disable irqs on vtime_account()
vtime: Warn if irqs aren't disabled on system time accounting APIs
cputime: Move thread_group_cputime() to sched code
cputime: Rename thread_group_times to thread_group_cputime_adjusted
cputime: Consolidate cputime adjustment code
cputime: Comment cputime's adjusting code
Ingo Molnar (2):
sched: Add WAKEUP_PREEMPTION feature flag, on by default Revert "sched/autogroup: Fix crash on reboot when autogroup is disabled"
Mike Galbraith (1):
sched/autogroup: Fix crash on reboot when autogroup is disabled
Paul Turner (14):
sched: Track the runnable average on a per-task entity basis
sched: Aggregate load contributed by task entities on parenting cfs_rq
sched: Maintain the load contribution of blocked entities
sched: Add an rq migration call-back to sched_class
sched: Account for blocked load waking back up
sched: Aggregate total task_group load
sched: Compute load contribution by a group entity
sched: Normalize tg load contributions against runnable time
sched: Maintain runnable averages across throttled periods
sched: Replace update_shares weight distribution with per-entity computation
sched: Refactor update_shares_cpu() -> update_blocked_avgs()
sched: Update_cfs_shares at period edge
sched: Make __update_entity_runnable_avg() fast
sched: Introduce temporary FAIR_GROUP_SCHED dependency for load-tracking
Peter Zijlstra (1):
sched: Describe CFS load-balancer
arch/ia64/include/asm/cputime.h | 2 + arch/ia64/kernel/time.c | 22 +- arch/powerpc/include/asm/cputime.h | 2 + arch/powerpc/kernel/time.c | 20 +- arch/s390/include/asm/cputime.h | 1 + arch/s390/kernel/vtime.c | 13 +- arch/s390/kvm/kvm-s390.c | 4 - fs/proc/array.c | 4 +- include/linux/hardirq.h | 15 +- include/linux/kernel_stat.h | 17 +- include/linux/kvm_host.h | 12 +- include/linux/sched.h | 49 +- include/linux/vtime.h | 48 ++ kernel/exit.c | 4 +- kernel/fork.c | 2 +- kernel/posix-cpu-timers.c | 24 - kernel/sched/auto_group.c | 4 + kernel/sched/auto_group.h | 5 + kernel/sched/core.c | 11 + kernel/sched/cputime.c | 131 ++++-- kernel/sched/debug.c | 36 +- kernel/sched/fair.c | 914 ++++++++++++++++++++++++++++++------- kernel/sched/features.h | 5 + kernel/sched/sched.h | 60 ++- kernel/softirq.c | 6 +- kernel/sys.c | 6 +- 26 files changed, 1082 insertions(+), 335 deletions(-) create mode 100644 include/linux/vtime.h
arch/ia64/include/asm/cputime.h +2 -0
@@ -103,5 +103,7 @@ static inline void cputime_to_timeval(const cputime_t ct, struct timeval *val)#define cputime64_to_clock_t (__ct) \ cputime_to_clock_t((__force cputime_t)__ct) +extern void arch_vtime_task_switch (struct task_struct *tsk); +#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ #endif /* __IA64_CPUTIME_H */
arch/ia64/kernel/time.c +4 -18
@@ -83,7 +83,7 @@ static struct clocksource *itc_clocksource;extern cputime_t cycle_to_cputime (u64 cyc); -static void vtime_account_user (struct task_struct *tsk) +void vtime_account_user (struct task_struct *tsk) {cputime_t delta_utime;struct thread_info *ti =task_thread_info (tsk);
@@ -100,18 +100,11 @@ static void vtime_account_user(struct task_struct *tsk)* accumulated times to the current process, and to prepare accounting on * the next process. */ -void vtime_task_switch (struct task_struct *prev) +void arch_vtime_task_switch (struct task_struct *prev) {struct thread_info *pi =task_thread_info (prev);struct thread_info *ni =task_thread_info (current); -if (idle_task (smp_processor_id ()) != prev) -vtime_account_system (prev); -else -vtime_account_idle (prev); - -vtime_account_user (prev); - pi->ac_stamp = ni->ac_stamp; ni->ac_stime = ni->ac_utime =0 ; }
@@ -126,6 +119,8 @@ static cputime_t vtime_delta(struct task_struct *tsk)cputime_t delta_stime;__u64 now; +WARN_ON_ONCE (!irqs_disabled ()); + now =ia64_get_itc (); delta_stime =cycle_to_cputime (ti->ac_stime + (now - ti->ac_stamp));
@@ -147,15 +142,6 @@ void vtime_account_idle(struct task_struct *tsk)account_idle_time (vtime_delta (tsk)); } -/* -* Called from the timer interrupt handler to charge accumulated user time -* to the current process. Must be called with interrupts disabled. -*/ -void account_process_tick (struct task_struct *p,int user_tick) -{ -vtime_account_user (p); -} -#endif /* CONFIG_VIRT_CPU_ACCOUNTING */ static irqreturn_t
arch/powerpc/include/asm/cputime.h +2 -0
@@ -228,6 +228,8 @@ static inline cputime_t clock_t_to_cputime(const unsigned long clk)#define cputime64_to_clock_t (ct) cputime_to_clock_t((cputime_t)(ct)) +static inline void arch_vtime_task_switch (struct task_struct *tsk) { } +#endif /* __KERNEL__ */ #endif /* CONFIG_VIRT_CPU_ACCOUNTING */ #endif /* __POWERPC_CPUTIME_H */
arch/powerpc/kernel/time.c +8 -12
@@ -297,6 +297,8 @@ static u64 vtime_delta(struct task_struct *tsk,u64 now, nowscaled, deltascaled;u64 udelta, delta, user_scaled; +WARN_ON_ONCE (!irqs_disabled ()); + now =mftb (); nowscaled =read_spurr (now);get_paca ()->system_time += now -get_paca ()->starttime;
@@ -355,15 +357,15 @@ void vtime_account_idle(struct task_struct *tsk) }/* -* Transfer the user and system times accumulated in the paca -* by the exception entry and exit code to the generic process -* user and system time records. +* Transfer the user time accumulated in the paca +* by the exception entry and exit code to the generic +* process user time records. * Must be called with interrupts disabled. -* Assumes that vtime_account() has been called recently -* (i.e. since the last entry from usermode) so that +* Assumes that vtime_account_system/idle() has been called +* recently (i.e. since the last entry from usermode) so that * get_paca()->user_time_scaled is up to date. */ -void account_process_tick (struct task_struct *tsk,int user_tick) +void vtime_account_user (struct task_struct *tsk) {cputime_t utime, utimescaled;
@@ -375,12 +377,6 @@ void account_process_tick(struct task_struct *tsk, int user_tick) account_user_time(tsk, utime, utimescaled); } -void vtime_task_switch (struct task_struct *prev) -{ -vtime_account (prev); -account_process_tick (prev,0 ); -} -#else /* ! CONFIG_VIRT_CPU_ACCOUNTING */ #define calc_cputime_factors ()#endif
arch/s390/include/asm/cputime.h +1 -0
@@ -14,6 +14,7 @@#define __ARCH_HAS_VTIME_ACCOUNT +#define __ARCH_HAS_VTIME_TASK_SWITCH/* We want to use full resolution of the CPU timer: 2**-12 micro-seconds. */
arch/s390/kernel/vtime.c +12 -1
@@ -112,7 +112,12 @@ void vtime_task_switch(struct task_struct *prev) S390_lowcore.system_timer = ti->system_timer; } -void account_process_tick (struct task_struct *tsk,int user_tick) +/* +* In s390, accounting pending user time also implies +* accounting system time in order to correctly compute +* the stolen time accounting. +*/ +void vtime_account_user (struct task_struct *tsk) {if (do_account_vtime (tsk,HARDIRQ_OFFSET ))virt_timer_expire ();
@@ -127,6 +132,8 @@ void vtime_account(struct task_struct *tsk)struct thread_info *ti =task_thread_info (tsk);u64 timer, system; +WARN_ON_ONCE (!irqs_disabled ()); + timer = S390_lowcore.last_update_timer; S390_lowcore.last_update_timer =get_vtimer (); S390_lowcore.system_timer += timer - S390_lowcore.last_update_timer;
@@ -140,6 +147,10 @@ void vtime_account(struct task_struct *tsk) }EXPORT_SYMBOL_GPL (vtime_account); +void vtime_account_system (struct task_struct *tsk) +__attribute__((alias ("vtime_account" ))); +EXPORT_SYMBOL_GPL (vtime_account_system); +void __kprobes vtime_stop_cpu (void ) {struct s390_idle_data *idle = &__get_cpu_var (s390_idle);
arch/s390/kvm/kvm-s390.c +0 -4
@@ -608,9 +608,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)kvm_s390_deliver_pending_interrupts (vcpu); vcpu->arch.sie_block->icptcode =0 ; -local_irq_disable ();kvm_guest_enter (); -local_irq_enable ();VCPU_EVENT (vcpu,6 ,"entering sie flags %x" ,atomic_read (&vcpu->arch.sie_block->cpuflags)); trace_kvm_s390_sie_enter(vcpu,
@@ -629,9 +627,7 @@ static int __vcpu_run(struct kvm_vcpu *vcpu)VCPU_EVENT (vcpu,6 ,"exit sie icptcode %d" , vcpu->arch.sie_block->icptcode);trace_kvm_s390_sie_exit (vcpu, vcpu->arch.sie_block->icptcode); -local_irq_disable ();kvm_guest_exit (); -local_irq_enable ();memcpy (&vcpu->run->s.regs.gprs[14 ], &vcpu->arch.sie_block->gg14,16 );return rc;
fs/proc/array.c +2 -2
@@ -438,7 +438,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, min_flt += sig->min_flt; maj_flt += sig->maj_flt; -thread_group_times (task, &utime, &stime); +thread_group_cputime_adjusted (task, &utime, &stime); gtime += sig->gtime; }
@@ -454,7 +454,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,if (!whole) { min_flt = task->min_flt; maj_flt = task->maj_flt; -task_times (task, &utime, &stime); +task_cputime_adjusted (task, &utime, &stime); gtime = task->gtime; }
include/linux/hardirq.h +3 -12
@@ -4,6 +4,7 @@#include <linux/preempt.h> #include <linux/lockdep.h> #include <linux/ftrace_irq.h> +#include <linux/vtime.h> #include <asm/hardirq.h> /*
@@ -129,16 +130,6 @@ extern void synchronize_irq(unsigned int irq);# define synchronize_irq (irq) barrier()#endif -struct task_struct ; - -#if !defined(CONFIG_VIRT_CPU_ACCOUNTING ) && !defined(CONFIG_IRQ_TIME_ACCOUNTING ) -static inline void vtime_account (struct task_struct *tsk) -{ -} -#else -extern void vtime_account (struct task_struct *tsk); -#endif -#if defined(CONFIG_TINY_RCU ) || defined(CONFIG_TINY_PREEMPT_RCU )static inline void rcu_nmi_enter (void )
@@ -162,7 +153,7 @@ extern void rcu_nmi_exit(void);*/ #define __irq_enter () \ do { \ - vtime_account(current); \ + vtime_account_irq_enter(current); \ add_preempt_count(HARDIRQ_OFFSET); \ trace_hardirq_enter(); \ } while (0)
@@ -178,7 +169,7 @@ extern void irq_enter(void);#define __irq_exit () \ do { \ trace_hardirq_exit(); \ - vtime_account(current); \ + vtime_account_irq_exit(current); \ sub_preempt_count(HARDIRQ_OFFSET); \ } while (0)
include/linux/kernel_stat.h +9 -8
@@ -7,6 +7,7 @@#include <linux/cpumask.h> #include <linux/interrupt.h> #include <linux/sched.h> +#include <linux/vtime.h> #include <asm/irq.h> #include <asm/cputime.h>
@@ -126,16 +127,16 @@ extern void account_system_time(struct task_struct *, int, cputime_t, cputime_t)extern void account_steal_time (cputime_t );extern void account_idle_time (cputime_t ); -extern void account_process_tick (struct task_struct *,int user); -extern void account_steal_ticks (unsigned long ticks); -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); +static inline void account_process_tick (struct task_struct *tsk,int user) +{ +vtime_account_user (tsk); +}#else -static inline void vtime_task_switch (struct task_struct *prev) { } +extern void account_process_tick (struct task_struct *,int user);#endif +extern void account_steal_ticks (unsigned long ticks); +extern void account_idle_ticks (unsigned long ticks); +#endif /* _LINUX_KERNEL_STAT_H */
include/linux/kvm_host.h +10 -2
@@ -726,7 +726,11 @@ static inline int kvm_deassign_device(struct kvm *kvm,static inline void kvm_guest_enter (void ) {BUG_ON (preemptible ()); -vtime_account (current); +/* +* This is running in ioctl context so we can avoid +* the call to vtime_account() with its unnecessary idle check. +*/ +vtime_account_system_irqsafe (current); current->flags |=PF_VCPU ;/* KVM does not hold any references to rcu protected data when it * switches CPU into a guest mode. In fact switching to a guest mode
@@ -740,7 +744,11 @@ static inline void kvm_guest_enter(void)static inline void kvm_guest_exit (void ) { -vtime_account (current); +/* +* This is running in ioctl context so we can avoid +* the call to vtime_account() with its unnecessary idle check. +*/ +vtime_account_system_irqsafe (current); current->flags &= ~PF_VCPU ; }
include/linux/sched.h +43 -6
96 lines not on this page · raw message
include/linux/vtime.h new file +48 -0
48 lines not on this page · raw message
kernel/exit.c +2 -2
@@ -1186,11 +1186,11 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)* as other threads in the parent group can be right * here reaping other children at the same time. * -* We use thread_group_times() to get times for the thread +* We use thread_group_cputime_adjusted() to get times for the thread * group, which consolidates times for all threads in the * group including the group leader. */ -thread_group_times (p, &tgutime, &tgstime); +thread_group_cputime_adjusted (p, &tgutime, &tgstime);spin_lock_irq (&p->real_parent->sighand->siglock); psig = p->real_parent->signal; sig = p->signal;
kernel/fork.c +1 -1
@@ -1222,7 +1222,7 @@ static struct task_struct *copy_process(unsigned long clone_flags, p->utime = p->stime = p->gtime =0 ; p->utimescaled = p->stimescaled =0 ;#ifndef CONFIG_VIRT_CPU_ACCOUNTING - p->prev_utime = p->prev_stime =0 ; + p->prev_cputime.utime = p->prev_cputime.stime =0 ;#endif #if defined(SPLIT_RSS_COUNTING )memset (&p->rss_stat,0 ,sizeof (p->rss_stat));
kernel/posix-cpu-timers.c +0 -24
@@ -217,30 +217,6 @@ static int cpu_clock_sample(const clockid_t which_clock, struct task_struct *p,return 0 ; } -void thread_group_cputime (struct task_struct *tsk,struct task_cputime *times) -{ -struct signal_struct *sig = tsk->signal; -struct task_struct *t; - - times->utime = sig->utime; - times->stime = sig->stime; - times->sum_exec_runtime = sig->sum_sched_runtime; - -rcu_read_lock (); -/* make sure we can trust tsk->thread_group list */ -if (!likely (pid_alive (tsk))) - goto out; - - t = tsk; - do { - times->utime += t->utime; - times->stime += t->stime; - times->sum_exec_runtime += task_sched_runtime(t); - } while_each_thread(tsk, t); -out: - rcu_read_unlock(); -} -static void update_gt_cputime (struct task_cputime *a,struct task_cputime *b) {if (b->utime > a->utime)
kernel/sched/auto_group.c +4 -0
@@ -143,11 +143,15 @@ autogroup_move_group(struct task_struct *p, struct autogroup *ag) p->signal->autogroup =autogroup_kref_get (ag); +if (!ACCESS_ONCE (sysctl_sched_autogroup_enabled)) + goto out; + t = p; do { sched_move_task(t); } while_each_thread(p, t); +out: unlock_task_sighand(p, &flags); autogroup_kref_put(prev); }
kernel/sched/auto_group.h +5 -0
@@ -4,6 +4,11 @@#include <linux/rwsem.h> struct autogroup { +/* +* reference doesn't mean how many thread attach to this +* autogroup now. It just stands for the number of task +* could use this autogroup. +*/ struct kref kref;struct task_group *tg;struct rw_semaphore lock;
kernel/sched/core.c +11 -0
@@ -952,6 +952,8 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)trace_sched_migrate_task (p, new_cpu);if (task_cpu (p) != new_cpu) { +if (p->sched_class->migrate_task_rq) + p->sched_class->migrate_task_rq (p, new_cpu); p->se.nr_migrations++;perf_sw_event (PERF_COUNT_SW_CPU_MIGRATIONS ,1 ,NULL ,0 ); }
@@ -1524,6 +1526,15 @@ static void __sched_fork(struct task_struct *p) p->se.vruntime =0 ;INIT_LIST_HEAD (&p->se.group_node); +/* +* Load-tracking only depends on SMP, FAIR_GROUP_SCHED dependency below may be +* removed when useful for applications beyond shares distribution (e.g. +* load-balance). +*/ +#if defined(CONFIG_SMP ) && defined(CONFIG_FAIR_GROUP_SCHED ) + p->se.avg.runnable_avg_period =0 ; + p->se.avg.runnable_avg_sum =0 ; +#endif #ifdef CONFIG_SCHEDSTATS memset (&p->se.statistics,0 ,sizeof (p->se.statistics));#endif
kernel/sched/cputime.c +95 -36
202 lines not on this page · raw message
kernel/sched/debug.c +26 -10
@@ -61,14 +61,20 @@ static unsigned long nsec_low(unsigned long long nsec)static void print_cfs_group_stats (struct seq_file *m,int cpu,struct task_group *tg) {struct sched_entity *se = tg->se[cpu]; -if (!se) -return ;#define P (F ) \ SEQ_printf(m, " .%-30s: %lld\n", #F, (long long)F)#define PN (F ) \ SEQ_printf(m, " .%-30s: %lld.%06ld\n", #F, SPLIT_NS((long long)F)) +if (!se) { +struct sched_avg *avg = &cpu_rq (cpu)->avg; +P (avg->runnable_avg_sum); +P (avg->runnable_avg_period); +return ; + } + +PN (se->exec_start);PN (se->vruntime);PN (se->sum_exec_runtime);
@@ -85,6 +91,12 @@ static void print_cfs_group_stats(struct seq_file *m, int cpu, struct task_groupP (se->statistics.wait_count);#endif P (se->load.weight); +#ifdef CONFIG_SMP +P (se->avg.runnable_avg_sum); +P (se->avg.runnable_avg_period); +P (se->avg.load_avg_contrib); +P (se->avg.decay_count); +#endif #undef PN#undef P }
@@ -206,14 +218,18 @@ void print_cfs_rq(struct seq_file *m, int cpu, struct cfs_rq *cfs_rq)SEQ_printf (m," .%-30s: %ld\n" ,"load" , cfs_rq->load.weight);#ifdef CONFIG_FAIR_GROUP_SCHED #ifdef CONFIG_SMP -SEQ_printf (m," .%-30s: %Ld.%06ld\n" ,"load_avg" , -SPLIT_NS (cfs_rq->load_avg)); -SEQ_printf (m," .%-30s: %Ld.%06ld\n" ,"load_period" , -SPLIT_NS (cfs_rq->load_period)); -SEQ_printf (m," .%-30s: %ld\n" ,"load_contrib" , - cfs_rq->load_contribution); -SEQ_printf (m," .%-30s: %d\n" ,"load_tg" , -atomic_read (&cfs_rq->tg->load_weight)); +SEQ_printf (m," .%-30s: %lld\n" ,"runnable_load_avg" , + cfs_rq->runnable_load_avg); +SEQ_printf (m," .%-30s: %lld\n" ,"blocked_load_avg" , + cfs_rq->blocked_load_avg); +SEQ_printf (m," .%-30s: %ld\n" ,"tg_load_avg" , +atomic64_read (&cfs_rq->tg->load_avg)); +SEQ_printf (m," .%-30s: %lld\n" ,"tg_load_contrib" , + cfs_rq->tg_load_contrib); +SEQ_printf (m," .%-30s: %d\n" ,"tg_runnable_contrib" , + cfs_rq->tg_runnable_contrib); +SEQ_printf (m," .%-30s: %d\n" ,"tg->runnable_avg" , +atomic_read (&cfs_rq->tg->runnable_avg));#endif print_cfs_group_stats (m, cpu, cfs_rq->tg);
kernel/sched/fair.c +746 -168
1,188 lines not on this page · raw message
kernel/sched/features.h +5 -0
@@ -32,6 +32,11 @@ SCHED_FEAT(LAST_BUDDY, true)SCHED_FEAT (CACHE_HOT_BUDDY , true)/* +* Allow wakeup-time preemption of the current task: + */ +SCHED_FEAT (WAKEUP_PREEMPTION , true) + +/* * Use arch dependent cpu power functions */SCHED_FEAT (ARCH_POWER , true)
kernel/sched/sched.h +37 -23
101 lines not on this page · raw message
kernel/softirq.c +3 -3
@@ -221,7 +221,7 @@ asmlinkage void __do_softirq(void) current->flags &= ~PF_MEMALLOC ; pending =local_softirq_pending (); -vtime_account (current); +vtime_account_irq_enter (current);__local_bh_disable ((unsigned long )__builtin_return_address (0 ),SOFTIRQ_OFFSET );
@@ -272,7 +272,7 @@ restart:lockdep_softirq_exit (); -vtime_account (current); +vtime_account_irq_exit (current);__local_bh_enable (SOFTIRQ_OFFSET );tsk_restore_flags (current, old_flags,PF_MEMALLOC ); }
@@ -341,7 +341,7 @@ static inline void invoke_softirq(void)*/ void irq_exit (void ) { -vtime_account (current); +vtime_account_irq_exit (current);trace_hardirq_exit ();sub_preempt_count (IRQ_EXIT_OFFSET );if (!in_interrupt () &&local_softirq_pending ())
kernel/sys.c +3 -3
@@ -1046,7 +1046,7 @@ void do_sys_times(struct tms *tms)cputime_t tgutime, tgstime, cutime, cstime;spin_lock_irq (¤t->sighand->siglock); -thread_group_times (current, &tgutime, &tgstime); +thread_group_cputime_adjusted (current, &tgutime, &tgstime); cutime = current->signal->cutime; cstime = current->signal->cstime;spin_unlock_irq (¤t->sighand->siglock);
@@ -1704,7 +1704,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r) utime = stime =0 ;if (who ==RUSAGE_THREAD ) { -task_times (current, &utime, &stime); +task_cputime_adjusted (current, &utime, &stime);accumulate_thread_rusage (p, r); maxrss = p->signal->maxrss; goto out;
@@ -1730,7 +1730,7 @@ static void k_getrusage(struct task_struct *p, int who, struct rusage *r)break ;case RUSAGE_SELF : -thread_group_times (p, &tgutime, &tgstime); +thread_group_cputime_adjusted (p, &tgutime, &tgstime); utime += tgutime; stime += tgstime; r->ru_nvcsw += p->signal->nvcsw;