All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCHv3] x86, fpu: remove the logic of non-eager fpu mem allocation at the first usage
@ 2014-09-02 16:06 David Vrabel
  2014-12-17 20:36 ` Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 2+ messages in thread
From: David Vrabel @ 2014-09-02 16:06 UTC (permalink / raw)
  To: linux-kernel
  Cc: David Vrabel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin, x86,
	Suresh Siddha

From: Suresh Siddha <sbsiddha@gmail.com>

For non-eager fpu mode, thread's fpu state is allocated during the first
fpu usage (in the context of device not available exception). This can be
a blocking call and hence we enable interrupts (which were originally
disabled when the exception happened), allocate memory and disable
interrupts etc. While this saves 512 bytes or so per-thread, there
are some issues in general.

a.  Most of the future cases will be anyway using eager
FPU (because of processor features like xsaveopt, LWP, MPX etc) and
they do the allocation at the thread creation itself. Nice to have
one common mechanism as all the state save/restore code is
shared. Avoids the confusion and minimizes the subtle bugs
in the core piece involved with context-switch.

b. If a parent thread uses FPU, during fork() we allocate
the FPU state in the child and copy the state etc. Shortly after this,
during exec() we free it up, so that we can later allocate during
the first usage of FPU. So this free/allocate might be slower
for some workloads.

c. math_state_restore() is called from multiple places
and it is error pone if the caller expects interrupts to be disabled
throughout the execution of math_state_restore(). Can lead to subtle
bugs like Ubuntu bug #1265841.

Memory savings will be small anyways and the code complexity
introducing subtle bugs is not worth it. So remove
the logic of non-eager fpu mem allocation at the first usage.

Signed-off-by: Suresh Siddha <sbsiddha@gmail.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>
---
v3:
- Rebase on 3.17-rc3.

v2:
- Tweak condition for allocating the first thread's FPU state.
---
 arch/x86/kernel/i387.c    |   20 +++++++++++---------
 arch/x86/kernel/process.c |    6 ------
 arch/x86/kernel/traps.c   |   16 ++--------------
 arch/x86/kernel/xsave.c   |    2 --
 4 files changed, 13 insertions(+), 31 deletions(-)

diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
index a9a4229..956ea86 100644
--- a/arch/x86/kernel/i387.c
+++ b/arch/x86/kernel/i387.c
@@ -5,6 +5,7 @@
  *  General FPU state handling cleanups
  *	Gareth Hughes <gareth@valinux.com>, May 2000
  */
+#include <linux/bootmem.h>
 #include <linux/module.h>
 #include <linux/regset.h>
 #include <linux/sched.h>
@@ -197,6 +198,16 @@ void fpu_init(void)
 
 	mxcsr_feature_mask_init();
 	xsave_init();
+
+	/*
+	 * Now we know the final size of the xsave data, allocate the
+	 * FPU state area for the first task. All other tasks have
+	 * this allocated in arch_dup_task_struct().
+	 */
+	if (!current->thread.fpu.state)
+		current->thread.fpu.state = alloc_bootmem_align(xstate_size,
+				__alignof__(struct xsave_struct));
+
 	eager_fpu_init();
 }
 
@@ -228,8 +239,6 @@ EXPORT_SYMBOL_GPL(fpu_finit);
  */
 int init_fpu(struct task_struct *tsk)
 {
-	int ret;
-
 	if (tsk_used_math(tsk)) {
 		if (cpu_has_fpu && tsk == current)
 			unlazy_fpu(tsk);
@@ -237,13 +246,6 @@ int init_fpu(struct task_struct *tsk)
 		return 0;
 	}
 
-	/*
-	 * Memory allocation at the first usage of the FPU and other state.
-	 */
-	ret = fpu_alloc(&tsk->thread.fpu);
-	if (ret)
-		return ret;
-
 	fpu_finit(&tsk->thread.fpu);
 
 	set_stopped_child_used_math(tsk);
diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
index f804dc9..4137f81 100644
--- a/arch/x86/kernel/process.c
+++ b/arch/x86/kernel/process.c
@@ -129,12 +129,6 @@ void flush_thread(void)
 	flush_ptrace_hw_breakpoint(tsk);
 	memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
 	drop_init_fpu(tsk);
-	/*
-	 * Free the FPU state for non xsave platforms. They get reallocated
-	 * lazily at the first use.
-	 */
-	if (!use_eager_fpu())
-		free_thread_xstate(tsk);
 }
 
 static void hard_disable_TSC(void)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 0d0e922..36fc898 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -652,20 +652,8 @@ void math_state_restore(void)
 {
 	struct task_struct *tsk = current;
 
-	if (!tsk_used_math(tsk)) {
-		local_irq_enable();
-		/*
-		 * does a slab alloc which can sleep
-		 */
-		if (init_fpu(tsk)) {
-			/*
-			 * ran out of memory!
-			 */
-			do_group_exit(SIGKILL);
-			return;
-		}
-		local_irq_disable();
-	}
+	if (!tsk_used_math(tsk))
+		init_fpu(tsk);
 
 	__thread_fpu_begin(tsk);
 
diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
index 940b142..eed95d6 100644
--- a/arch/x86/kernel/xsave.c
+++ b/arch/x86/kernel/xsave.c
@@ -677,8 +677,6 @@ void xsave_init(void)
 
 static inline void __init eager_fpu_init_bp(void)
 {
-	current->thread.fpu.state =
-	    alloc_bootmem_align(xstate_size, __alignof__(struct xsave_struct));
 	if (!init_xstate_buf)
 		setup_init_fpu_buf();
 }
-- 
1.7.10.4


^ permalink raw reply related	[flat|nested] 2+ messages in thread

* Re: [PATCHv3] x86, fpu: remove the logic of non-eager fpu mem allocation at the first usage
  2014-09-02 16:06 [PATCHv3] x86, fpu: remove the logic of non-eager fpu mem allocation at the first usage David Vrabel
@ 2014-12-17 20:36 ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 2+ messages in thread
From: Konrad Rzeszutek Wilk @ 2014-12-17 20:36 UTC (permalink / raw)
  To: David Vrabel, annie li, Xen Devel Mailing list
  Cc: H. Peter Anvin, X86, LKML, Ingo Molnar, Suresh Siddha, Thomas Gleixner


[-- Attachment #1.1: Type: text/plain, Size: 5901 bytes --]

On Tue, Sep 2, 2014 at 12:06 PM, David Vrabel <david.vrabel@citrix.com>
wrote:
>
> From: Suresh Siddha <sbsiddha@gmail.com>
>
> For non-eager fpu mode, thread's fpu state is allocated during the first
> fpu usage (in the context of device not available exception). This can be
> a blocking call and hence we enable interrupts (which were originally
> disabled when the exception happened), allocate memory and disable
> interrupts etc. While this saves 512 bytes or so per-thread, there
> are some issues in general.
>
> a.  Most of the future cases will be anyway using eager
> FPU (because of processor features like xsaveopt, LWP, MPX etc) and
> they do the allocation at the thread creation itself. Nice to have
> one common mechanism as all the state save/restore code is
> shared. Avoids the confusion and minimizes the subtle bugs
> in the core piece involved with context-switch.
>
> b. If a parent thread uses FPU, during fork() we allocate
> the FPU state in the child and copy the state etc. Shortly after this,
> during exec() we free it up, so that we can later allocate during
> the first usage of FPU. So this free/allocate might be slower
> for some workloads.
>
> c. math_state_restore() is called from multiple places
> and it is error pone if the caller expects interrupts to be disabled
> throughout the execution of math_state_restore(). Can lead to subtle
> bugs like Ubuntu bug #1265841.
>
> Memory savings will be small anyways and the code complexity
> introducing subtle bugs is not worth it. So remove
> the logic of non-eager fpu mem allocation at the first usage.
>


ping?

>
> Signed-off-by: Suresh Siddha <sbsiddha@gmail.com>
> Signed-off-by: David Vrabel <david.vrabel@citrix.com>
> ---
> v3:
> - Rebase on 3.17-rc3.
>
> v2:
> - Tweak condition for allocating the first thread's FPU state.
> ---
>  arch/x86/kernel/i387.c    |   20 +++++++++++---------
>  arch/x86/kernel/process.c |    6 ------
>  arch/x86/kernel/traps.c   |   16 ++--------------
>  arch/x86/kernel/xsave.c   |    2 --
>  4 files changed, 13 insertions(+), 31 deletions(-)
>
> diff --git a/arch/x86/kernel/i387.c b/arch/x86/kernel/i387.c
> index a9a4229..956ea86 100644
> --- a/arch/x86/kernel/i387.c
> +++ b/arch/x86/kernel/i387.c
> @@ -5,6 +5,7 @@
>   *  General FPU state handling cleanups
>   *     Gareth Hughes <gareth@valinux.com>, May 2000
>   */
> +#include <linux/bootmem.h>
>  #include <linux/module.h>
>  #include <linux/regset.h>
>  #include <linux/sched.h>
> @@ -197,6 +198,16 @@ void fpu_init(void)
>
>         mxcsr_feature_mask_init();
>         xsave_init();
> +
> +       /*
> +        * Now we know the final size of the xsave data, allocate the
> +        * FPU state area for the first task. All other tasks have
> +        * this allocated in arch_dup_task_struct().
> +        */
> +       if (!current->thread.fpu.state)
> +               current->thread.fpu.state =
> alloc_bootmem_align(xstate_size,
> +                               __alignof__(struct xsave_struct));
> +
>         eager_fpu_init();
>  }
>
> @@ -228,8 +239,6 @@ EXPORT_SYMBOL_GPL(fpu_finit);
>   */
>  int init_fpu(struct task_struct *tsk)
>  {
> -       int ret;
> -
>         if (tsk_used_math(tsk)) {
>                 if (cpu_has_fpu && tsk == current)
>                         unlazy_fpu(tsk);
> @@ -237,13 +246,6 @@ int init_fpu(struct task_struct *tsk)
>                 return 0;
>         }
>
> -       /*
> -        * Memory allocation at the first usage of the FPU and other state.
> -        */
> -       ret = fpu_alloc(&tsk->thread.fpu);
> -       if (ret)
> -               return ret;
> -
>         fpu_finit(&tsk->thread.fpu);
>
>         set_stopped_child_used_math(tsk);
> diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c
> index f804dc9..4137f81 100644
> --- a/arch/x86/kernel/process.c
> +++ b/arch/x86/kernel/process.c
> @@ -129,12 +129,6 @@ void flush_thread(void)
>         flush_ptrace_hw_breakpoint(tsk);
>         memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array));
>         drop_init_fpu(tsk);
> -       /*
> -        * Free the FPU state for non xsave platforms. They get reallocated
> -        * lazily at the first use.
> -        */
> -       if (!use_eager_fpu())
> -               free_thread_xstate(tsk);
>  }
>
>  static void hard_disable_TSC(void)
> diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
> index 0d0e922..36fc898 100644
> --- a/arch/x86/kernel/traps.c
> +++ b/arch/x86/kernel/traps.c
> @@ -652,20 +652,8 @@ void math_state_restore(void)
>  {
>         struct task_struct *tsk = current;
>
> -       if (!tsk_used_math(tsk)) {
> -               local_irq_enable();
> -               /*
> -                * does a slab alloc which can sleep
> -                */
> -               if (init_fpu(tsk)) {
> -                       /*
> -                        * ran out of memory!
> -                        */
> -                       do_group_exit(SIGKILL);
> -                       return;
> -               }
> -               local_irq_disable();
> -       }
> +       if (!tsk_used_math(tsk))
> +               init_fpu(tsk);
>
>         __thread_fpu_begin(tsk);
>
> diff --git a/arch/x86/kernel/xsave.c b/arch/x86/kernel/xsave.c
> index 940b142..eed95d6 100644
> --- a/arch/x86/kernel/xsave.c
> +++ b/arch/x86/kernel/xsave.c
> @@ -677,8 +677,6 @@ void xsave_init(void)
>
>  static inline void __init eager_fpu_init_bp(void)
>  {
> -       current->thread.fpu.state =
> -           alloc_bootmem_align(xstate_size, __alignof__(struct
> xsave_struct));
>         if (!init_xstate_buf)
>                 setup_init_fpu_buf();
>  }
> --
> 1.7.10.4
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>

[-- Attachment #1.2: Type: text/html, Size: 7729 bytes --]

[-- Attachment #2: Type: text/plain, Size: 126 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xen.org
http://lists.xen.org/xen-devel

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2014-12-17 20:36 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-09-02 16:06 [PATCHv3] x86, fpu: remove the logic of non-eager fpu mem allocation at the first usage David Vrabel
2014-12-17 20:36 ` Konrad Rzeszutek Wilk

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.