x86/fpu: eagerfpu fixes, speedups, and default enablement
v2 cover x86/fpu: eagerfpu fixes, speedups, and default enablement
Hi all-
Here's v2 to celebrate the end of the merge window :)
Patches 1, 2, and 3 are fixes.
Patch 4 is probably a small speedup. It also only matters in lazy FPU mode, which means that, most likely, no one cares. Apply or don't -- I don't care much.
Patch 5 is, in some sense, a radical change. Currently we select eager or lazy mode depending on CPU type. I think that lazy mode sucks and that we should deprecate and remove it.
With patches 1-3 applied, I think that eagerfpu works on all systems. Patch 5 will use it on all systems subject to a chicken flag -- eagerfpu=off will still disable it.
I propose that we apply patch 5, let it soak in -next until the 4.6 merge window opens, possibly let it actually land in 4.6, and then remove lazy mode entirely for 4.7. This will open up enormous cleanup possibilities, and it will make the fpu code vastly more comprehensible.
Changes from v1:
- Get rid of cpu_has_fpu (Boris)
Andy Lutomirski (5):
x86/fpu: Fix math emulation in eager fpu mode
x86/fpu: Fix FNSAVE usage in eagerfpu mode
x86/fpu: Fold fpu_copy into fpu__copy
x86/fpu: Speed up lazy FPU restores slightly
x86/fpu: Default eagerfpu=on on all CPUs
arch/x86/include/asm/fpu/internal.h | 3 ++- arch/x86/kernel/fpu/core.c | 52 +++++++++++++++++++------------------ arch/x86/kernel/fpu/init.c | 13 ++++------ arch/x86/kernel/traps.c | 3 +-- 4 files changed, 35 insertions(+), 36 deletions(-)
Signature · 1 line
2.5.0
PATCH v2 1/5 x86/fpu: Fix math emulation in eager fpu mode
Systems without an FPU are generally old and therefore use lazy FPU switching. Unsurprisingly, math emulation in eager FPU mode is a bit buggy. Fix it.
There were two bugs involving kernel code trying to use the FPU registers in eager mode even if they didn't exist and one BUG_ON that was incorrect.
--- arch/x86/include/asm/fpu/internal.h | 3 ++- arch/x86/kernel/fpu/core.c | 2 +- arch/x86/kernel/traps.c | 1 - 3 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/include/asm/fpu/internal.h +2 -1
@@ -589,7 +589,8 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)* If the task has used the math, pre-load the FPU on xsave processors * or if the past 5 consecutive context-switches used math. */ - fpu.preload = new_fpu->fpstate_active && + fpu.preload =static_cpu_has (X86_FEATURE_FPU ) && + new_fpu->fpstate_active && (use_eager_fpu () || new_fpu->counter >5 );if (old_fpu->fpregs_active) {
arch/x86/kernel/fpu/core.c +1 -1
@@ -423,7 +423,7 @@ void fpu__clear(struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu);/* Almost certainly an anomaly */ -if (!use_eager_fpu ()) { +if (!use_eager_fpu () || !static_cpu_has (X86_FEATURE_FPU )) {/* FPU state will be reallocated lazily at the first use. */ fpu__drop (fpu); }else {
arch/x86/kernel/traps.c +0 -1
@@ -750,7 +750,6 @@ dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code) {RCU_LOCKDEP_WARN (!rcu_is_watching (),"entry code didn't wake RCU" ); -BUG_ON (use_eager_fpu ());#ifdef CONFIG_MATH_EMULATION if (read_cr0 () &X86_CR0_EM ) {
Signature · 1 line
2.5.0
tip-bot for Andy Lutomirski
merge bot[tip:x86/fpu] x86/fpu: Fix math emulation in eager fpu mode
x86/fpu: Fix math emulation in eager fpu mode
Commit-ID: 4ecd16ec7059390b430af34bd8bc3ca2b5dcef9a Gitweb: http://git.kernel.org/tip/4ecd16ec7059390b430af34bd8bc3ca2b5dcef9a Author: Andy Lutomirski <[email protected]> AuthorDate: Sun, 24 Jan 2016 14:38:06 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 9 Feb 2016 15:42:55 +0100
x86/fpu: Fix math emulation in eager fpu mode
Systems without an FPU are generally old and therefore use lazy FPU switching. Unsurprisingly, math emulation in eager FPU mode is a bit buggy. Fix it.
There were two bugs involving kernel code trying to use the FPU registers in eager mode even if they didn't exist and one BUG_ON() that was incorrect.
--- arch/x86/include/asm/fpu/internal.h | 3 ++- arch/x86/kernel/fpu/core.c | 2 +- arch/x86/kernel/traps.c | 1 - 3 files changed, 3 insertions(+), 3 deletions(-)
arch/x86/include/asm/fpu/internal.h +2 -1
@@ -589,7 +589,8 @@ switch_fpu_prepare(struct fpu *old_fpu, struct fpu *new_fpu, int cpu)* If the task has used the math, pre-load the FPU on xsave processors * or if the past 5 consecutive context-switches used math. */ - fpu.preload = new_fpu->fpstate_active && + fpu.preload =static_cpu_has (X86_FEATURE_FPU ) && + new_fpu->fpstate_active && (use_eager_fpu () || new_fpu->counter >5 );if (old_fpu->fpregs_active) {
arch/x86/kernel/fpu/core.c +1 -1
@@ -423,7 +423,7 @@ void fpu__clear(struct fpu *fpu) {WARN_ON_FPU (fpu != ¤t->thread.fpu);/* Almost certainly an anomaly */ -if (!use_eager_fpu ()) { +if (!use_eager_fpu () || !static_cpu_has (X86_FEATURE_FPU )) {/* FPU state will be reallocated lazily at the first use. */ fpu__drop (fpu); }else {
arch/x86/kernel/traps.c +0 -1
@@ -750,7 +750,6 @@ dotraplinkage void do_device_not_available(struct pt_regs *regs, long error_code) {RCU_LOCKDEP_WARN (!rcu_is_watching (),"entry code didn't wake RCU" ); -BUG_ON (use_eager_fpu ());#ifdef CONFIG_MATH_EMULATION if (read_cr0 () &X86_CR0_EM ) {
PATCH v2 2/5 x86/fpu: Fix FNSAVE usage in eagerfpu mode
In reply to Andy LutomirskiIn eager fpu mode, having deactivated fpu without immediately reloading some other context is illegal. Therefore, to recover from FNSAVE, we can't just deactivate the state -- we need to reload it if we're not actively context switching.
We had this wrong in fpu__save and fpu__copy. Fix both. __kernel_fpu_begin was fine -- add a comment.
This fixes a warning triggerable with nofxsr eagerfpu=on.
--- arch/x86/kernel/fpu/core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/core.c +15 -3
@@ -114,6 +114,10 @@ void __kernel_fpu_begin(void)kernel_fpu_disable ();if (fpu->fpregs_active) { +/* +* Ignore return value -- we don't care if reg state +* is clobbered. +*/ copy_fpregs_to_fpstate (fpu); }else {this_cpu_write (fpu_fpregs_owner_ctx,NULL );
@@ -189,8 +193,12 @@ void fpu__save(struct fpu *fpu)preempt_disable ();if (fpu->fpregs_active) { -if (!copy_fpregs_to_fpstate (fpu)) -fpregs_deactivate (fpu); +if (!copy_fpregs_to_fpstate (fpu)) { +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu); + } }preempt_enable (); }
@@ -259,7 +267,11 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)preempt_disable ();if (!copy_fpregs_to_fpstate (dst_fpu)) {memcpy (&src_fpu->state, &dst_fpu->state, xstate_size); -fpregs_deactivate (src_fpu); + +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&src_fpu->state); +else +fpregs_deactivate (src_fpu); }preempt_enable (); }
Signature · 1 line
2.5.0
Dave Hansen
maintainerRe: [PATCH v2 2/5] x86/fpu: Fix FNSAVE usage in eagerfpu mode
Quoted 12 lines · Andy Lutomirski
arch/x86/kernel/fpu/core.c +4
-0if (fpu->fpregs_active) { +/* +* Ignore return value -- we don't care if reg state +* is clobbered. +*/ copy_fpregs_to_fpstate (fpu); }else {this_cpu_write (fpu_fpregs_owner_ctx,NULL );@@ -189,8 +193,12 @@ void fpu__save(struct fpu *fpu)preempt_disable ();if (fpu->fpregs_active) {
arch/x86/kernel/fpu/core.c void fpu__save(struct fpu *fpu) · line 203
Quoted 10 lines
arch/x86/kernel/fpu/core.c +6
-2-if (!copy_fpregs_to_fpstate (fpu)) -fpregs_deactivate (fpu); +if (!copy_fpregs_to_fpstate (fpu)) { +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu); + } }preempt_enable ();
I wonder if we should just make the
arch/x86/kernel/fpu/core.c void fpu__save(struct fpu *fpu) · line 200
Quoted 4 lines
arch/x86/kernel/fpu/core.c +4
-0+if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu);
behavior the default _inside_ copy_fpregs_to_fpstate(fpu). We evidently got it wrong in 2/3 of the call sites that needed it. It ends up being an optimization for FNSAVE (because it allows us to avoid an FRSTOR), but we only take advantage of that in cases of kernel_fpu_begin/end().
FXSAVE has been around since at _least_ 1999, and I'd expect it to get used in place of FNSAVE everywhere that it is available.
If we don't want to do that, maybe we should add a "clobber" argument to copy_fpregs_to_fpstate() for when it's allowed to clobber the register state.
I just hate putting this logic at all the call sites.
Re: [PATCH v2 2/5] x86/fpu: Fix FNSAVE usage in eagerfpu mode
Quoted 37 lines · Dave Hansen
Quoted 12 lines · Andy Lutomirski
if (fpu->fpregs_active) {arch/x86/kernel/fpu/core.c +4
-0+/* +* Ignore return value -- we don't care if reg state +* is clobbered. +*/ copy_fpregs_to_fpstate (fpu); }else {this_cpu_write (fpu_fpregs_owner_ctx,NULL );@@ -189,8 +193,12 @@ void fpu__save(struct fpu *fpu)preempt_disable ();if (fpu->fpregs_active) {arch/x86/kernel/fpu/core.c void fpu__save(struct fpu *fpu) · line 203
Quoted 10 lines
arch/x86/kernel/fpu/core.c +6
-2-if (!copy_fpregs_to_fpstate (fpu)) -fpregs_deactivate (fpu); +if (!copy_fpregs_to_fpstate (fpu)) { +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu); + } }preempt_enable ();I wonder if we should just make the
arch/x86/kernel/fpu/core.c void fpu__save(struct fpu *fpu) · line 200
Quoted 4 lines
arch/x86/kernel/fpu/core.c +4
-0+if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu);behavior the default _inside_
copy_fpregs_to_fpstate(fpu). We evidently got it wrong in 2/3 of the call sites that needed it. It ends up being an optimization for FNSAVE (because it allows us to avoid an FRSTOR), but we only take advantage of that in cases of kernel_fpu_begin/end().
Quoted 8 lines
FXSAVE has been around since at _least_ 1999, and I'd expect it to get used in place of FNSAVE everywhere that it is available.
If we don't want to do that, maybe we should add a "clobber" argument to
copy_fpregs_to_fpstate()for when it's allowed to clobber the register state.I just hate putting this logic at all the call sites.
Me too. I was thinking about having a clobber and a non-clobber variant. The tricky part is that we have to think about preemption, too. In theory, copying fpregs to somewhere other then the normal spot can be okay with preemption on except in the FNSAVE case, but all the callers probably need preemption off anyway.
Even if we do the cleanup, I think I'd rather fix the bug in place first so the diff is clearer and then clean it up on top of that.
Does that seem reasonable?
--Andy
Dave Hansen
maintainerRe: [PATCH v2 2/5] x86/fpu: Fix FNSAVE usage in eagerfpu mode
Quoted 4 lines · Andy Lutomirski
Even if we do the cleanup, I think I'd rather fix the bug in place first so the diff is clearer and then clean it up on top of that.
Does that seem reasonable?
Yup, sounds fine to me.
tip-bot for Andy Lutomirski
merge bot[tip:x86/fpu] x86/fpu: Fix FNSAVE usage in eagerfpu mode
In reply to Andy Lutomirskix86/fpu: Fix FNSAVE usage in eagerfpu mode
Commit-ID: 5ed73f40735c68d8a656b46d09b1885d3b8740ae Gitweb: http://git.kernel.org/tip/5ed73f40735c68d8a656b46d09b1885d3b8740ae Author: Andy Lutomirski <[email protected]> AuthorDate: Sun, 24 Jan 2016 14:38:07 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 9 Feb 2016 15:42:55 +0100
x86/fpu: Fix FNSAVE usage in eagerfpu mode
In eager fpu mode, having deactivated FPU without immediately reloading some other context is illegal. Therefore, to recover from FNSAVE, we can't just deactivate the state -- we need to reload it if we're not actively context switching.
We had this wrong in fpu__save() and fpu__copy(). Fix both. __kernel_fpu_begin() was fine -- add a comment.
This fixes a warning triggerable with nofxsr eagerfpu=on.
--- arch/x86/kernel/fpu/core.c | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-)
arch/x86/kernel/fpu/core.c +15 -3
@@ -114,6 +114,10 @@ void __kernel_fpu_begin(void)kernel_fpu_disable ();if (fpu->fpregs_active) { +/* +* Ignore return value -- we don't care if reg state +* is clobbered. +*/ copy_fpregs_to_fpstate (fpu); }else {this_cpu_write (fpu_fpregs_owner_ctx,NULL );
@@ -189,8 +193,12 @@ void fpu__save(struct fpu *fpu)preempt_disable ();if (fpu->fpregs_active) { -if (!copy_fpregs_to_fpstate (fpu)) -fpregs_deactivate (fpu); +if (!copy_fpregs_to_fpstate (fpu)) { +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&fpu->state); +else +fpregs_deactivate (fpu); + } }preempt_enable (); }
@@ -259,7 +267,11 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)preempt_disable ();if (!copy_fpregs_to_fpstate (dst_fpu)) {memcpy (&src_fpu->state, &dst_fpu->state, xstate_size); -fpregs_deactivate (src_fpu); + +if (use_eager_fpu ()) +copy_kernel_to_fpregs (&src_fpu->state); +else +fpregs_deactivate (src_fpu); }preempt_enable (); }
PATCH v2 3/5 x86/fpu: Fold fpu_copy into fpu__copy
In reply to Andy LutomirskiSplitting it into two functions needlessly obfuscated the code. While we're at it, improve the comment slightly.
--- arch/x86/kernel/fpu/core.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-)
arch/x86/kernel/fpu/core.c +11 -21
@@ -231,14 +231,15 @@ void fpstate_init(union fpregs_state *state) }EXPORT_SYMBOL_GPL (fpstate_init); -/* -* Copy the current task's FPU state to a new task's FPU context. -* -* In both the 'eager' and the 'lazy' case we save hardware registers -* directly to the destination buffer. -*/ -static void fpu_copy (struct fpu *dst_fpu,struct fpu *src_fpu) +int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) { + dst_fpu->counter =0 ; + dst_fpu->fpregs_active =0 ; + dst_fpu->last_cpu =-1 ; + +if (!src_fpu->fpstate_active || !cpu_has_fpu) +return 0 ; +WARN_ON_FPU (src_fpu != ¤t->thread.fpu);/*
@@ -251,10 +252,9 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)/* * Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. -* -* If the FPU context got destroyed in the process (FNSAVE -* done on old CPUs) then copy it back into the source -* context and mark the current task for lazy restore. +* In lazy mode, if the FPU context isn't loaded into +* fpregs, CR0.TS will be set and do_device_not_available +* will load the FPU context. * * We have to do all this with preemption disabled, * mostly because of the FNSAVE case, because in that
@@ -274,16 +274,6 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)fpregs_deactivate (src_fpu); }preempt_enable (); -} - -int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) -{ - dst_fpu->counter =0 ; - dst_fpu->fpregs_active =0 ; - dst_fpu->last_cpu =-1 ; - -if (src_fpu->fpstate_active && cpu_has_fpu) -fpu_copy (dst_fpu, src_fpu);return 0 ; }
Signature · 1 line
2.5.0
tip-bot for Andy Lutomirski
merge bot[tip:x86/fpu] x86/fpu: Fold fpu_copy() into fpu__copy()
x86/fpu: Fold fpu_copy() into fpu__copy()
Commit-ID: a20d7297045f7fdcd676c15243192eb0e95a4306 Gitweb: http://git.kernel.org/tip/a20d7297045f7fdcd676c15243192eb0e95a4306 Author: Andy Lutomirski <[email protected]> AuthorDate: Sun, 24 Jan 2016 14:38:08 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 9 Feb 2016 15:42:55 +0100
x86/fpu: Fold fpu_copy() into fpu__copy()
Splitting it into two functions needlessly obfuscated the code. While we're at it, improve the comment slightly.
--- arch/x86/kernel/fpu/core.c | 32 +++++++++++--------------------- 1 file changed, 11 insertions(+), 21 deletions(-)
arch/x86/kernel/fpu/core.c +11 -21
@@ -231,14 +231,15 @@ void fpstate_init(union fpregs_state *state) }EXPORT_SYMBOL_GPL (fpstate_init); -/* -* Copy the current task's FPU state to a new task's FPU context. -* -* In both the 'eager' and the 'lazy' case we save hardware registers -* directly to the destination buffer. -*/ -static void fpu_copy (struct fpu *dst_fpu,struct fpu *src_fpu) +int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) { + dst_fpu->counter =0 ; + dst_fpu->fpregs_active =0 ; + dst_fpu->last_cpu =-1 ; + +if (!src_fpu->fpstate_active || !cpu_has_fpu) +return 0 ; +WARN_ON_FPU (src_fpu != ¤t->thread.fpu);/*
@@ -251,10 +252,9 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)/* * Save current FPU registers directly into the child * FPU context, without any memory-to-memory copying. -* -* If the FPU context got destroyed in the process (FNSAVE -* done on old CPUs) then copy it back into the source -* context and mark the current task for lazy restore. +* In lazy mode, if the FPU context isn't loaded into +* fpregs, CR0.TS will be set and do_device_not_available +* will load the FPU context. * * We have to do all this with preemption disabled, * mostly because of the FNSAVE case, because in that
@@ -274,16 +274,6 @@ static void fpu_copy(struct fpu *dst_fpu, struct fpu *src_fpu)fpregs_deactivate (src_fpu); }preempt_enable (); -} - -int fpu__copy (struct fpu *dst_fpu,struct fpu *src_fpu) -{ - dst_fpu->counter =0 ; - dst_fpu->fpregs_active =0 ; - dst_fpu->last_cpu =-1 ; - -if (src_fpu->fpstate_active && cpu_has_fpu) -fpu_copy (dst_fpu, src_fpu);return 0 ; }
PATCH v2 4/5 x86/fpu: Speed up lazy FPU restores slightly
In reply to Andy LutomirskiIf we have an FPU, there's no need to check CR0 for FPU emulation.
--- arch/x86/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/traps.c +1 -1
@@ -752,7 +752,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)RCU_LOCKDEP_WARN (!rcu_is_watching (),"entry code didn't wake RCU" );#ifdef CONFIG_MATH_EMULATION -if (read_cr0 () &X86_CR0_EM ) { +if (!boot_cpu_has (X86_FEATURE_FPU ) && (read_cr0 () &X86_CR0_EM )) {struct math_emu_info info = { };conditional_sti (regs);
Signature · 1 line
2.5.0
tip-bot for Andy Lutomirski
merge bot[tip:x86/fpu] x86/fpu: Speed up lazy FPU restores slightly
x86/fpu: Speed up lazy FPU restores slightly
Commit-ID: c6ab109f7e0eae3bae3bb10f8ddb0df67735c150 Gitweb: http://git.kernel.org/tip/c6ab109f7e0eae3bae3bb10f8ddb0df67735c150 Author: Andy Lutomirski <[email protected]> AuthorDate: Sun, 24 Jan 2016 14:38:09 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 9 Feb 2016 15:42:56 +0100
x86/fpu: Speed up lazy FPU restores slightly
If we have an FPU, there's no need to check CR0 for FPU emulation.
--- arch/x86/kernel/traps.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/x86/kernel/traps.c +1 -1
@@ -752,7 +752,7 @@ do_device_not_available(struct pt_regs *regs, long error_code)RCU_LOCKDEP_WARN (!rcu_is_watching (),"entry code didn't wake RCU" );#ifdef CONFIG_MATH_EMULATION -if (read_cr0 () &X86_CR0_EM ) { +if (!boot_cpu_has (X86_FEATURE_FPU ) && (read_cr0 () &X86_CR0_EM )) {struct math_emu_info info = { };conditional_sti (regs);
PATCH v2 5/5 x86/fpu: Default eagerfpu=on on all CPUs
In reply to Andy LutomirskiWe have eager and lazy fpu modes, introduced in 304bceda6a18 ("x86,
fpu: use non-lazy fpu restore for processors supporting xsave").
The result is rather messy. There are two code paths in almost all of the FPU code, and only one of them (the eager case) is tested frequently, since most kernel developers have new enough hardware that we use eagerfpu.
It seems that, on any remotely recent hardware, eagerfpu is a win:
glibc uses SSE2, so laziness is probably overoptimistic, and, in any case, manipulating TS is far slower that saving and restoring the full state. (Stores to CR0.TS are serializing and are poorly optimized.)
To try to shake out any latent issues on old hardware, this changes the default to eager on all CPUs. If no performance or functionality problems show up, a subsequent patch could remove lazy mode entirely.
--- arch/x86/kernel/fpu/init.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
arch/x86/kernel/fpu/init.c +5 -8
@@ -262,7 +262,10 @@ static void __init fpu__init_system_xstate_size_legacy(void)* not only saved the restores along the way, but we also have the * FPU ready to be used for the original task. * -* 'eager' switching is used on modern CPUs, there we switch the FPU +* 'lazy' is deprecated because it's almost never a performance win +* and it's much more complicated than 'eager'. +* +* 'eager' switching is by default on all CPUs, there we switch the FPU * state during every context switch, regardless of whether the task * has used FPU instructions in that time slice or not. This is done * because modern FPU context saving instructions are able to optimize
@@ -273,7 +276,7 @@ static void __init fpu__init_system_xstate_size_legacy(void)* to use 'eager' restores, if we detect that a task is using the FPU * frequently. See the fpu->counter logic in fpu/internal.h for that. ] */ -static enum {AUTO ,ENABLE ,DISABLE } eagerfpu =AUTO ; +static enum {ENABLE ,DISABLE } eagerfpu =ENABLE ;/* * Find supported xfeatures based on cpu features and command-line input.
@@ -350,15 +353,9 @@ static void __init fpu__init_system_ctx_switch(void)*/ static void __init fpu__init_parse_early_param (void ) { -/* -* No need to check "eagerfpu=auto" again, since it is the -* initial default. -*/ if (cmdline_find_option_bool (boot_command_line,"eagerfpu=off" )) { eagerfpu =DISABLE ;fpu__clear_eager_fpu_features (); - }else if (cmdline_find_option_bool (boot_command_line,"eagerfpu=on" )) { - eagerfpu =ENABLE ; }if (cmdline_find_option_bool (boot_command_line,"no387" ))
Signature · 1 line
2.5.0
tip-bot for Andy Lutomirski
merge bot[tip:x86/fpu] x86/fpu: Default eagerfpu=on on all CPUs
x86/fpu: Default eagerfpu=on on all CPUs
Commit-ID: 58122bf1d856a4ea9581d62a07c557d997d46a19 Gitweb: http://git.kernel.org/tip/58122bf1d856a4ea9581d62a07c557d997d46a19 Author: Andy Lutomirski <[email protected]> AuthorDate: Sun, 24 Jan 2016 14:38:10 -0800 Committer: Ingo Molnar <[email protected]> CommitDate: Tue, 9 Feb 2016 15:42:56 +0100
x86/fpu: Default eagerfpu=on on all CPUs
We have eager and lazy FPU modes, introduced in:
304bceda6a18 ("x86, fpu: use non-lazy fpu restore for processors supporting xsave")
The result is rather messy. There are two code paths in almost all of the FPU code, and only one of them (the eager case) is tested frequently, since most kernel developers have new enough hardware that we use eagerfpu.
It seems that, on any remotely recent hardware, eagerfpu is a win:
glibc uses SSE2, so laziness is probably overoptimistic, and, in any case, manipulating TS is far slower that saving and restoring the full state. (Stores to CR0.TS are serializing and are poorly optimized.)
To try to shake out any latent issues on old hardware, this changes the default to eager on all CPUs. If no performance or functionality problems show up, a subsequent patch could remove lazy mode entirely.
--- arch/x86/kernel/fpu/init.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-)
arch/x86/kernel/fpu/init.c +5 -8
@@ -260,7 +260,10 @@ static void __init fpu__init_system_xstate_size_legacy(void)* not only saved the restores along the way, but we also have the * FPU ready to be used for the original task. * -* 'eager' switching is used on modern CPUs, there we switch the FPU +* 'lazy' is deprecated because it's almost never a performance win +* and it's much more complicated than 'eager'. +* +* 'eager' switching is by default on all CPUs, there we switch the FPU * state during every context switch, regardless of whether the task * has used FPU instructions in that time slice or not. This is done * because modern FPU context saving instructions are able to optimize
@@ -271,7 +274,7 @@ static void __init fpu__init_system_xstate_size_legacy(void)* to use 'eager' restores, if we detect that a task is using the FPU * frequently. See the fpu->counter logic in fpu/internal.h for that. ] */ -static enum {AUTO ,ENABLE ,DISABLE } eagerfpu =AUTO ; +static enum {ENABLE ,DISABLE } eagerfpu =ENABLE ;/* * Find supported xfeatures based on cpu features and command-line input.
@@ -348,15 +351,9 @@ static void __init fpu__init_system_ctx_switch(void)*/ static void __init fpu__init_parse_early_param (void ) { -/* -* No need to check "eagerfpu=auto" again, since it is the -* initial default. -*/ if (cmdline_find_option_bool (boot_command_line,"eagerfpu=off" )) { eagerfpu =DISABLE ;fpu__clear_eager_fpu_features (); - }else if (cmdline_find_option_bool (boot_command_line,"eagerfpu=on" )) { - eagerfpu =ENABLE ; }if (cmdline_find_option_bool (boot_command_line,"no387" ))