Tianqiang Xu <skyele@xxxxxxxxxxx> writes: > This patch aims to fix performance issue caused by current > para-virtualized scheduling design. > > The current para-virtualized scheduling design uses 'preempted' field of > kvm_steal_time to avoid scheduling task on the preempted vCPU. > However, when the pCPU where the preempted vCPU most recently run is idle, > it will result in low cpu utilization, and consequently poor performance. > > The new field: 'is_idle' of kvm_steal_time can precisely reveal the status of > pCPU where preempted vCPU most recently run, and then improve cpu utilization. > > Host OS sets this field to 1 if cpu_rq(this_cpu)->nr_running is 1 before > a vCPU being scheduled out. On this condition, there is no other task on > this pCPU to run. Thus, is_idle == 1 means the pCPU where the preempted > vCPU most recently run is idle. > > Guest OS uses this field to know if a pCPU is idle and decides whether > to schedule a task to a preempted vCPU or not. If the pCPU is idle, > scheduling a task to this pCPU will improve cpu utilization. If not, > avoiding scheduling a task to this preempted vCPU can avoid host/guest > switch, hence improving performance. > > Experiments on a VM with 16 vCPUs show that the patch can reduce around > 50% to 80% execution time for most PARSEC benchmarks. > This also holds true for a VM with 112 vCPUs. > > Experiments on 2 VMs with 112 vCPUs show that the patch can reduce around > 20% to 80% execution time for most PARSEC benchmarks. > > Test environment: > -- PowerEdge R740 > -- 56C-112T CPU Intel(R) Xeon(R) Gold 6238R CPU > -- Host 190G DRAM > -- QEMU 5.0.0 > -- PARSEC 3.0 Native Inputs > -- Host is idle during the test > -- Host and Guest kernel are both kernel-5.14.0 > > Results: > 1. 1 VM, 16 VCPU, 16 THREAD. > Host Topology: sockets=2 cores=28 threads=2 > VM Topology: sockets=1 cores=16 threads=1 > Command: <path to parsec>/bin/parsecmgmt -a run -p <benchmark> -i native -n 16 > Statistics below are the real time of running each benchmark.(lower is better) > > before patch after patch improvements > bodytrack 52.866s 22.619s 57.21% > fluidanimate 84.009s 38.148s 54.59% > streamcluster 270.17s 42.726s 84.19% > splash2x.ocean_cp 31.932s 9.539s 70.13% > splash2x.ocean_ncp 36.063s 14.189s 60.65% > splash2x.volrend 134.587s 21.79s 83.81% > > 2. 1VM, 112 VCPU. Some benchmarks require the number of threads to be the power of 2, > so we run them with 64 threads and 128 threads. > Host Topology: sockets=2 cores=28 threads=2 > VM Topology: sockets=1 cores=112 threads=1 > Command: <path to parsec>/bin/parsecmgmt -a run -p <benchmark> -i native -n <64,112,128> > Statistics below are the real time of running each benchmark.(lower is better) > > > > before patch after patch improvements > fluidanimate(64 thread) 124.235s 27.924s 77.52% > fluidanimate(128 thread) 169.127s 64.541s 61.84% > streamcluster(112 thread) 861.879s 496.66s 42.37% > splash2x.ocean_cp(64 thread) 46.415s 18.527s 60.08% > splash2x.ocean_cp(128 thread) 53.647s 28.929s 46.08% > splash2x.ocean_ncp(64 thread) 47.613s 19.576s 58.89% > splash2x.ocean_ncp(128 thread) 54.94s 29.199s 46.85% > splash2x.volrend(112 thread) 801.384s 144.824s 81.93% > > 3. 2VM, each VM: 112 VCPU. Some benchmarks require the number of threads to > be the power of 2, so we run them with 64 threads and 128 threads. > Host Topology: sockets=2 cores=28 threads=2 > VM Topology: sockets=1 cores=112 threads=1 > Command: <path to parsec>/bin/parsecmgmt -a run -p <benchmark> -i native -n <64,112,128> > Statistics below are the average real time of running each benchmark in 2 VMs.(lower is better) > before patch after patch improvements > fluidanimate(64 thread) 135.2125s 49.827s 63.15% > fluidanimate(128 thread) 178.309s 86.964s 51.23% > splash2x.ocean_cp(64 thread) 47.4505s 20.314s 57.19% > splash2x.ocean_cp(128 thread) 55.5645s 30.6515s 44.84% > splash2x.ocean_ncp(64 thread) 49.9775s 23.489s 53.00% > splash2x.ocean_ncp(128 thread) 56.847s 28.545s 49.79% > splash2x.volrend(112 thread) 838.939s 239.632s 71.44% > > For space limit, we list representative statistics here. > > -- > Authors: Tianqiang Xu, Dingji Li, Zeyu Mi > Shanghai Jiao Tong University > > Signed-off-by: Tianqiang Xu <skyele@xxxxxxxxxxx> > --- > arch/x86/hyperv/hv_spinlock.c | 7 +++ > arch/x86/include/asm/cpufeatures.h | 1 + > arch/x86/include/asm/kvm_host.h | 1 + > arch/x86/include/asm/paravirt.h | 8 +++ > arch/x86/include/asm/paravirt_types.h | 1 + > arch/x86/include/asm/qspinlock.h | 6 ++ > arch/x86/include/uapi/asm/kvm_para.h | 4 +- > arch/x86/kernel/asm-offsets_64.c | 1 + > arch/x86/kernel/kvm.c | 23 +++++++ > arch/x86/kernel/paravirt-spinlocks.c | 15 +++++ > arch/x86/kernel/paravirt.c | 2 + > arch/x86/kvm/x86.c | 90 ++++++++++++++++++++++++++- > include/linux/sched.h | 1 + > kernel/sched/core.c | 17 +++++ > kernel/sched/sched.h | 1 + > 15 files changed, 176 insertions(+), 2 deletions(-) Thank you for the patch! Please split this patch into a series, e.g.: - Introduce .pcpu_is_idle() stub infrastructure - Scheduler changes - Preparatory patch[es] for KVM creating 'is_idle' - KVM host implementation - KVM guest implementation - ... so it can be reviewed and ACKed. Just a couple of nitpicks below > > diff --git a/arch/x86/hyperv/hv_spinlock.c b/arch/x86/hyperv/hv_spinlock.c > index 91cfe698bde0..b8c32b719cab 100644 > --- a/arch/x86/hyperv/hv_spinlock.c > +++ b/arch/x86/hyperv/hv_spinlock.c > @@ -66,6 +66,12 @@ __visible bool hv_vcpu_is_preempted(int vcpu) > } > PV_CALLEE_SAVE_REGS_THUNK(hv_vcpu_is_preempted); > > +__visible bool hv_pcpu_is_idle(int vcpu) > +{ > + return false; > +} > +PV_CALLEE_SAVE_REGS_THUNK(hv_pcpu_is_idle); > + > void __init hv_init_spinlocks(void) > { > if (!hv_pvspin || !apic || > @@ -82,6 +88,7 @@ void __init hv_init_spinlocks(void) > pv_ops.lock.wait = hv_qlock_wait; > pv_ops.lock.kick = hv_qlock_kick; > pv_ops.lock.vcpu_is_preempted = PV_CALLEE_SAVE(hv_vcpu_is_preempted); > + pv_ops.lock.pcpu_is_idle = PV_CALLEE_SAVE(hv_pcpu_is_idle); > } > > static __init int hv_parse_nopvspin(char *arg) > diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h > index d0ce5cfd3ac1..8a078619c9de 100644 > --- a/arch/x86/include/asm/cpufeatures.h > +++ b/arch/x86/include/asm/cpufeatures.h > @@ -238,6 +238,7 @@ > #define X86_FEATURE_VMW_VMMCALL ( 8*32+19) /* "" VMware prefers VMMCALL hypercall instruction */ > #define X86_FEATURE_PVUNLOCK ( 8*32+20) /* "" PV unlock function */ > #define X86_FEATURE_VCPUPREEMPT ( 8*32+21) /* "" PV vcpu_is_preempted function */ > +#define X86_FEATURE_PCPUISIDLE ( 8*32+22) /* "" PV pcpu_is_idle function */ > > /* Intel-defined CPU features, CPUID level 0x00000007:0 (EBX), word 9 */ > #define X86_FEATURE_FSGSBASE ( 9*32+ 0) /* RDFSBASE, WRFSBASE, RDGSBASE, WRGSBASE instructions*/ > diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h > index 974cbfb1eefe..bed0ab7233be 100644 > --- a/arch/x86/include/asm/kvm_host.h > +++ b/arch/x86/include/asm/kvm_host.h > @@ -742,6 +742,7 @@ struct kvm_vcpu_arch { > > struct { > u8 preempted; > + u8 is_idle; > u64 msr_val; > u64 last_steal; > struct gfn_to_pfn_cache cache; > diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h > index da3a1ac82be5..f34dec6eb515 100644 > --- a/arch/x86/include/asm/paravirt.h > +++ b/arch/x86/include/asm/paravirt.h > @@ -609,8 +609,16 @@ static __always_inline bool pv_vcpu_is_preempted(long cpu) > ALT_NOT(X86_FEATURE_VCPUPREEMPT)); > } > > +static __always_inline bool pv_pcpu_is_idle(long cpu) > +{ > + return PVOP_ALT_CALLEE1(bool, lock.pcpu_is_idle, cpu, > + "xor %%" _ASM_AX ", %%" _ASM_AX ";", > + ALT_NOT(X86_FEATURE_PCPUISIDLE)); > +} > + > void __raw_callee_save___native_queued_spin_unlock(struct qspinlock *lock); > bool __raw_callee_save___native_vcpu_is_preempted(long cpu); > +bool __raw_callee_save___native_pcpu_is_idle(long cpu); > > #endif /* SMP && PARAVIRT_SPINLOCKS */ > > diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h > index d9d6b0203ec4..7d9b5906580c 100644 > --- a/arch/x86/include/asm/paravirt_types.h > +++ b/arch/x86/include/asm/paravirt_types.h > @@ -257,6 +257,7 @@ struct pv_lock_ops { > void (*kick)(int cpu); > > struct paravirt_callee_save vcpu_is_preempted; > + struct paravirt_callee_save pcpu_is_idle; > } __no_randomize_layout; > > /* This contains all the paravirt structures: we get a convenient > diff --git a/arch/x86/include/asm/qspinlock.h b/arch/x86/include/asm/qspinlock.h > index d86ab942219c..1832dd8308ca 100644 > --- a/arch/x86/include/asm/qspinlock.h > +++ b/arch/x86/include/asm/qspinlock.h > @@ -61,6 +61,12 @@ static inline bool vcpu_is_preempted(long cpu) > { > return pv_vcpu_is_preempted(cpu); > } > + > +#define pcpu_is_idle pcpu_is_idle > +static inline bool pcpu_is_idle(long cpu) > +{ > + return pv_pcpu_is_idle(cpu); > +} > #endif > > #ifdef CONFIG_PARAVIRT > diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h > index 5146bbab84d4..2af305ba030a 100644 > --- a/arch/x86/include/uapi/asm/kvm_para.h > +++ b/arch/x86/include/uapi/asm/kvm_para.h > @@ -63,12 +63,14 @@ struct kvm_steal_time { > __u32 version; > __u32 flags; > __u8 preempted; > - __u8 u8_pad[3]; > + __u8 is_idle; > + __u8 u8_pad[2]; > __u32 pad[11]; > }; > > #define KVM_VCPU_PREEMPTED (1 << 0) > #define KVM_VCPU_FLUSH_TLB (1 << 1) > +#define KVM_PCPU_IS_IDLE (1 << 0) > > #define KVM_CLOCK_PAIRING_WALLCLOCK 0 > struct kvm_clock_pairing { > diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c > index b14533af7676..b587bbe44470 100644 > --- a/arch/x86/kernel/asm-offsets_64.c > +++ b/arch/x86/kernel/asm-offsets_64.c > @@ -22,6 +22,7 @@ int main(void) > > #if defined(CONFIG_KVM_GUEST) && defined(CONFIG_PARAVIRT_SPINLOCKS) > OFFSET(KVM_STEAL_TIME_preempted, kvm_steal_time, preempted); > + OFFSET(KVM_STEAL_TIME_is_idle, kvm_steal_time, is_idle); > BLANK(); > #endif > > diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c > index a26643dc6bd6..274d205b744c 100644 > --- a/arch/x86/kernel/kvm.c > +++ b/arch/x86/kernel/kvm.c > @@ -900,11 +900,20 @@ __visible bool __kvm_vcpu_is_preempted(long cpu) > } > PV_CALLEE_SAVE_REGS_THUNK(__kvm_vcpu_is_preempted); > > +__visible bool __kvm_pcpu_is_idle(long cpu) > +{ > + struct kvm_steal_time *src = &per_cpu(steal_time, cpu); > + > + return !!(src->is_idle & KVM_PCPU_IS_IDLE); > +} > +PV_CALLEE_SAVE_REGS_THUNK(__kvm_pcpu_is_idle); > + > #else > > #include <asm/asm-offsets.h> > > extern bool __raw_callee_save___kvm_vcpu_is_preempted(long); > +extern bool __raw_callee_save___kvm_pcpu_is_idle(long); > > /* > * Hand-optimize version for x86-64 to avoid 8 64-bit register saving and > @@ -922,6 +931,18 @@ asm( > ".size __raw_callee_save___kvm_vcpu_is_preempted, .-__raw_callee_save___kvm_vcpu_is_preempted;" > ".popsection"); > > +asm( > +".pushsection .text;" > +".global __raw_callee_save___kvm_pcpu_is_idle;" > +".type __raw_callee_save___kvm_pcpu_is_idle, @function;" > +"__raw_callee_save___kvm_pcpu_is_idle:" > +"movq __per_cpu_offset(,%rdi,8), %rax;" > +"cmpb $0, " __stringify(KVM_STEAL_TIME_is_idle) "+steal_time(%rax);" > +"setne %al;" > +"ret;" > +".size __raw_callee_save___kvm_pcpu_is_idle, .-__raw_callee_save___kvm_pcpu_is_idle;" > +".popsection"); > + > #endif > > /* > @@ -970,6 +991,8 @@ void __init kvm_spinlock_init(void) > if (kvm_para_has_feature(KVM_FEATURE_STEAL_TIME)) { > pv_ops.lock.vcpu_is_preempted = > PV_CALLEE_SAVE(__kvm_vcpu_is_preempted); > + pv_ops.lock.pcpu_is_idle = > + PV_CALLEE_SAVE(__kvm_pcpu_is_idle); > } > /* > * When PV spinlock is enabled which is preferred over > diff --git a/arch/x86/kernel/paravirt-spinlocks.c b/arch/x86/kernel/paravirt-spinlocks.c > index 9e1ea99ad9df..d7f6a461d0a5 100644 > --- a/arch/x86/kernel/paravirt-spinlocks.c > +++ b/arch/x86/kernel/paravirt-spinlocks.c > @@ -27,12 +27,24 @@ __visible bool __native_vcpu_is_preempted(long cpu) > } > PV_CALLEE_SAVE_REGS_THUNK(__native_vcpu_is_preempted); > > +__visible bool __native_pcpu_is_idle(long cpu) > +{ > + return false; > +} > +PV_CALLEE_SAVE_REGS_THUNK(__native_pcpu_is_idle); > + > bool pv_is_native_vcpu_is_preempted(void) > { > return pv_ops.lock.vcpu_is_preempted.func == > __raw_callee_save___native_vcpu_is_preempted; > } > > +bool pv_is_native_pcpu_is_idle(void) Just 'pv_native_pcpu_is_idle' or 'pv_is_native_pcpu_idle' maybe? > +{ > + return pv_ops.lock.pcpu_is_idle.func == > + __raw_callee_save___native_pcpu_is_idle; > +} > + > void __init paravirt_set_cap(void) > { > if (!pv_is_native_spin_unlock()) > @@ -40,4 +52,7 @@ void __init paravirt_set_cap(void) > > if (!pv_is_native_vcpu_is_preempted()) > setup_force_cpu_cap(X86_FEATURE_VCPUPREEMPT); > + > + if (!pv_is_native_pcpu_is_idle()) > + setup_force_cpu_cap(X86_FEATURE_PCPUISIDLE); > } > diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c > index 04cafc057bed..4489ca6d28c3 100644 > --- a/arch/x86/kernel/paravirt.c > +++ b/arch/x86/kernel/paravirt.c > @@ -366,6 +366,8 @@ struct paravirt_patch_template pv_ops = { > .lock.kick = paravirt_nop, > .lock.vcpu_is_preempted = > PV_CALLEE_SAVE(__native_vcpu_is_preempted), > + .lock.pcpu_is_idle = > + PV_CALLEE_SAVE(__native_pcpu_is_idle), > #endif /* SMP */ > #endif > }; > diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c > index e5d5c5ed7dd4..61bd01f82cdb 100644 > --- a/arch/x86/kvm/x86.c > +++ b/arch/x86/kvm/x86.c > @@ -3181,6 +3181,72 @@ static void kvm_vcpu_flush_tlb_guest(struct kvm_vcpu *vcpu) > static_call(kvm_x86_tlb_flush_guest)(vcpu); > } > > +static void kvm_steal_time_set_is_idle(struct kvm_vcpu *vcpu) > +{ > + struct kvm_host_map map; > + struct kvm_steal_time *st; > + > + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) > + return; > + > + if (vcpu->arch.st.is_idle) > + return; > + > + if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map, > + &vcpu->arch.st.cache, true)) > + return; > + > + st = map.hva + > + offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS); > + > + st->is_idle = vcpu->arch.st.is_idle = KVM_PCPU_IS_IDLE; > + > + kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true); > +} > + > +static void kvm_steal_time_clear_is_idle(struct kvm_vcpu *vcpu) > +{ > + struct kvm_host_map map; > + struct kvm_steal_time *st; > + > + if (!(vcpu->arch.st.msr_val & KVM_MSR_ENABLED)) > + return; > + > + if (!vcpu->arch.st.is_idle) > + return; > + > + if (kvm_map_gfn(vcpu, vcpu->arch.st.msr_val >> PAGE_SHIFT, &map, > + &vcpu->arch.st.cache, false)) > + return; > + > + st = map.hva + > + offset_in_page(vcpu->arch.st.msr_val & KVM_STEAL_VALID_BITS); > + > + if (guest_pv_has(vcpu, KVM_FEATURE_PV_TLB_FLUSH)) > + xchg(&st->is_idle, 0); > + else > + st->is_idle = 0; > + > + vcpu->arch.st.is_idle = 0; > + > + kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, false); > +} > + > + > +static DEFINE_PER_CPU(struct kvm_vcpu *, this_cpu_pre_run_vcpu); > + > +static void vcpu_load_update_pre_vcpu_callback(struct kvm_vcpu *new_vcpu, struct kvm_steal_time *st) > +{ > + struct kvm_vcpu *old_vcpu = __this_cpu_read(this_cpu_pre_run_vcpu); > + > + if (!old_vcpu) > + return; > + if (old_vcpu != new_vcpu) > + kvm_steal_time_clear_is_idle(old_vcpu); > + else > + st->is_idle = new_vcpu->arch.st.is_idle = KVM_PCPU_IS_IDLE; > +} > + > static void record_steal_time(struct kvm_vcpu *vcpu) > { > struct kvm_host_map map; > @@ -3219,6 +3285,8 @@ static void record_steal_time(struct kvm_vcpu *vcpu) > > vcpu->arch.st.preempted = 0; > > + vcpu_load_update_pre_vcpu_callback(vcpu, st); > + > if (st->version & 1) > st->version += 1; /* first time write, random junk */ > > @@ -4290,6 +4358,8 @@ static void kvm_steal_time_set_preempted(struct kvm_vcpu *vcpu) > kvm_unmap_gfn(vcpu, &map, &vcpu->arch.st.cache, true, true); > } > > +extern int get_cpu_nr_running(int cpu); > + > void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) > { > int idx; > @@ -4304,8 +4374,15 @@ void kvm_arch_vcpu_put(struct kvm_vcpu *vcpu) > idx = srcu_read_lock(&vcpu->kvm->srcu); > if (kvm_xen_msr_enabled(vcpu->kvm)) > kvm_xen_runstate_set_preempted(vcpu); > - else > + else { > kvm_steal_time_set_preempted(vcpu); > + > + if (get_cpu_nr_running(smp_processor_id()) <= 1) > + kvm_steal_time_set_is_idle(vcpu); > + else > + kvm_steal_time_clear_is_idle(vcpu); > + } > + > srcu_read_unlock(&vcpu->kvm->srcu, idx); > > static_call(kvm_x86_vcpu_put)(vcpu); > @@ -9693,6 +9770,8 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu) > local_irq_enable(); > preempt_enable(); > > + __this_cpu_write(this_cpu_pre_run_vcpu, vcpu); > + > vcpu->srcu_idx = srcu_read_lock(&vcpu->kvm->srcu); > > /* > @@ -11253,6 +11332,15 @@ void kvm_arch_pre_destroy_vm(struct kvm *kvm) > > void kvm_arch_destroy_vm(struct kvm *kvm) > { > + int cpu; > + struct kvm_vcpu *vcpu; > + > + for_each_possible_cpu(cpu) { > + vcpu = per_cpu(this_cpu_pre_run_vcpu, cpu); > + if (vcpu && vcpu->kvm == kvm) > + per_cpu(this_cpu_pre_run_vcpu, cpu) = NULL; > + } > + > if (current->mm == kvm->mm) { > /* > * Free memory regions allocated on behalf of userspace, > diff --git a/include/linux/sched.h b/include/linux/sched.h > index ec8d07d88641..dd4c41d2d8d3 100644 > --- a/include/linux/sched.h > +++ b/include/linux/sched.h > @@ -1736,6 +1736,7 @@ extern int can_nice(const struct task_struct *p, const int nice); > extern int task_curr(const struct task_struct *p); > extern int idle_cpu(int cpu); > extern int available_idle_cpu(int cpu); > +extern int available_idle_cpu_sched(int cpu); > extern int sched_setscheduler(struct task_struct *, int, const struct sched_param *); > extern int sched_setscheduler_nocheck(struct task_struct *, int, const struct sched_param *); > extern void sched_set_fifo(struct task_struct *p); > diff --git a/kernel/sched/core.c b/kernel/sched/core.c > index 20ffcc044134..1bcc023ce581 100644 > --- a/kernel/sched/core.c > +++ b/kernel/sched/core.c > @@ -6664,6 +6664,17 @@ int available_idle_cpu(int cpu) > return 1; > } > > +int available_idle_cpu_sched(int cpu) > +{ > + if (!idle_cpu(cpu)) > + return 0; > + > + if (!pcpu_is_idle(cpu)) > + return 0; > + > + return 1; > +} > + > /** > * idle_task - return the idle task for a given CPU. > * @cpu: the processor in question. > @@ -10413,3 +10424,9 @@ void call_trace_sched_update_nr_running(struct rq *rq, int count) > { > trace_sched_update_nr_running_tp(rq, count); > } > + > +int get_cpu_nr_running(int cpu) > +{ > + return cpu_rq(cpu)->nr_running; > +} > +EXPORT_SYMBOL_GPL(get_cpu_nr_running); > diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h > index 14a41a243f7b..49daefa91470 100644 > --- a/kernel/sched/sched.h > +++ b/kernel/sched/sched.h > @@ -101,6 +101,7 @@ extern void calc_global_load_tick(struct rq *this_rq); > extern long calc_load_fold_active(struct rq *this_rq, long adjust); > > extern void call_trace_sched_update_nr_running(struct rq *rq, int count); > + Stray change? > /* > * Helpers for converting nanosecond timing to jiffy resolution > */ -- Vitaly