powerpc: POWER7 optimised copy_to_user/copy_from_user using VMX
PATCH 1/1 powerpc: POWER7 optimised copy_to_user/copy_from_user using VMX
Implement a POWER7 optimised copy_to_user/copy_from_user using VMX. For large aligned copies this new loop is over 10% faster, and for large unaligned copies it is over 200% faster.
If we take a fault we fall back to the old version, this keeps things relatively simple and easy to verify.
On POWER7 unaligned stores rarely slow down - they only flush when a store crosses a 4KB page boundary. Furthermore this flush is handled completely in hardware and should be 20-30 cycles.
Unaligned loads on the other hand flush much more often - whenever crossing a 128 byte cache line, or a 32 byte sector if either sector is an L1 miss.
Considering this information we really want to get the loads aligned and not worry about the alignment of the stores. Microbenchmarks confirm that this approach is much faster than the current unaligned copy loop that uses shifts and rotates to ensure both loads and stores are aligned.
We also want to try and do the stores in cacheline aligned, cacheline sized chunks. If the store queue is unable to merge an entire cacheline of stores then the L2 cache will have to do a read/modify/write. Even worse, we will serialise this with the stores in the next iteration of the copy loop since both iterations hit the same cacheline.
Based on this, the new loop does the following things:
1 - 127 bytes
Get the source 8 byte aligned and use 8 byte loads and stores. Pretty boring and similar to how the current loop works.
128 - 4095 bytes
Get the source 8 byte aligned and use 8 byte loads and stores, 1 cacheline at a time. We aren't doing the stores in cacheline aligned chunks so we will potentially serialise once per cacheline. Even so it is much better than the loop we have today.
4096 - bytes
If both source and destination have the same alignment get them both 16 byte aligned, then get the destination cacheline aligned. Do cacheline sized loads and stores using VMX.
If source and destination do not have the same alignment, we get the destination cacheline aligned, and use permute to do aligned loads.
In both cases the VMX loop should be optimal - we always do aligned loads and stores and are always doing stores in cacheline aligned, cacheline sized chunks.
To be able to use VMX we must be careful about interrupts and sleeping. We don't use the VMX loop when in an interrupt (which should be rare anyway) and we wrap the VMX loop in disable/enable_pagefault and fall back to the existing copy_tofrom_user loop if we do need to sleep.
The VMX breakpoint of 4096 bytes was chosen using this microbenchmark:
http://ozlabs.org/~anton/junkcode/copy_to_user.c
Since we are using VMX and there is a cost to saving and restoring the user VMX state there are two broad cases we need to benchmark:
- Best case - userspace never uses VMX
- Worst case - userspace always uses VMX
In reality a userspace process will sit somewhere between these two extremes. Since we need to test both aligned and unaligned copies we end up with 4 combinations. The point at which the VMX loop begins to win is:
0% VMX
aligned 2048 bytes
unaligned 2048 bytes
100% VMX
aligned 16384 bytes
unaligned 8192 bytes
Considering this is a microbenchmark, the data is hot in cache and the VMX loop has better store queue merging properties we set the breakpoint to 4096 bytes, a little below the unaligned breakpoints.
Some future optimisations we can look at:
- Looking at the perf data, a significant part of the cost when a task is always using VMX is the extra exception we take to restore the VMX state. As such we should do something similar to the x86 optimisation that restores FPU state for heavy users. ie:
/*
* If the task has used fpu the last 5 timeslices, just do a full
* restore of the math state immediately to avoid the trap; the
* chances of needing FPU soon are obviously high now */
preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
and
/*
* fpu_counter contains the number of consecutive context switches
* that the FPU is used. If this is over a threshold, the lazy fpu
* saving becomes unlazy to save the trap. This is an unsigned char
* so that after 256 times the counter wraps and the behavior turns
* lazy again; this to deal with bursty apps that only use FPU for
* a short time
*/
- We could create a paca bit to mirror the VMX enabled MSR bit and check that first, avoiding multiple calls to calling enable_kernel_altivec. That should help with iovec based system calls like readv.
- We could have two VMX breakpoints, one for when we know the user VMX state is loaded into the registers and one when it isn't. This could be a second bit in the paca so we can calculate the break points quickly.
- One suggestion from Ben was to save and restore the VSX registers we use inline instead of using enable_kernel_altivec.
---
arch/powerpc/include/asm/cputable.h +2 -1
@@ -201,6 +201,7 @@ extern const char *powerpc_base_platform#define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0400000000000000)#define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000)#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000) +#define CPU_FTR_POWER7 LONG_ASM_CONST(0x2000000000000000)#ifndef __ASSEMBLY__
@@ -425,7 +426,7 @@ extern const char *powerpc_base_platform CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ - CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE) + CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_POWER7)#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
arch/powerpc/lib/copyuser_64.S +6 -0
@@ -11,6 +11,12 @@ .align 7 _GLOBAL(__copy_tofrom_user) +BEGIN_FTR_SECTION + nop +FTR_SECTION_ELSE + b __copy_tofrom_user_power7 +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POWER7) +_GLOBAL(__copy_tofrom_user_base) /* first check for a whole page copy on a page boundary */ cmpldi cr1,r5,16 cmpdi cr6,r5,4096
arch/powerpc/lib/copyuser_power7.S new file +669 -0
669 lines not on this page · raw message
arch/powerpc/lib/Makefile +2 -1
@@ -16,7 +16,8 @@ obj-$(CONFIG_HAS_IOMEM) += devres.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o \ - checksum_wrappers_64.o hweight_64.o + checksum_wrappers_64.o hweight_64.o \ + copyuser_power7.o copyuser_power7_vmx.o obj-$(CONFIG_XMON) += sstep.o ldstfp.o obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o
arch/powerpc/lib/copyuser_power7_vmx.c new file +44 -0
44 lines not on this page · raw message
Quoted 2 lines · Anton Blanchard
Index:
linux-build/arch/powerpc/include/asm/cputable.h=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Quoted 1 line
---
linux-build.orig/arch/powerpc/include/asm/cputable.h=
2011-09-07 15:15:49.096458526 +1000
Quoted 1 line
+++
linux-build/arch/powerpc/include/asm/cputable.h2011-12-08 =
15:38:46.627313507 +1100
Review extern const char *powerpc_base_platform · line 201
Quoted 2 lines
(quoted diff) +0
-0@@ -201,6 +201,7 @@ extern const char *powerpc_base_platform #define CPU_FTR_POPCNTB =
LONG_ASM_CONST(0x0400000000000000)
Review extern const char *powerpc_base_platform · line 202
Quoted 1 line
(quoted diff) +0
-0#define CPU_FTR_POPCNTD =
LONG_ASM_CONST(0x0800000000000000)
Review extern const char *powerpc_base_platform · line 203
Quoted 1 line
(quoted diff) +0
-0#define CPU_FTR_ICSWX =
LONG_ASM_CONST(0x1000000000000000)
Review extern const char *powerpc_base_platform · line 204
Quoted 1 line
(quoted diff) +1
-0+#define CPU_FTR_POWER7 =
LONG_ASM_CONST(0x2000000000000000)
arch/powerpc/include/asm/cputable.h extern const char *powerpc_base_platform · line 428
Quoted 7 lines
=20
#ifndef__ASSEMBLY__
=20arch/powerpc/include/asm/cputable.h +0
-0@@ -425,7 +426,7 @@ extern const char *powerpc_base_platformCPU_FTR_PURR |CPU_FTR_SPURR |CPU_FTR_REAL_LE | \CPU_FTR_DSCR |CPU_FTR_SAO |CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | =
CPU_FTR_POPCNTD | \
Review extern const char *powerpc_base_platform · line 429
Quoted 2 lines
(quoted diff) +1
-1- CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE) + CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | =
CPU_FTR_POWER7)
Quoted 5 lines
arch/powerpc/include/asm/cputable.h +0
-0#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \Index:
linux-build/arch/powerpc/lib/copyuser_64.S=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
Quoted 1 line
---
linux-build.orig/arch/powerpc/lib/copyuser_64.S2011-09-07 =
15:15:49.146459439 +1000
Quoted 1 line
+++
linux-build/arch/powerpc/lib/copyuser_64.S2011-12-08 =
15:38:42.491238635 +1100
Quoted 10 lines
(quoted diff) +0
-0@@ -11,6 +11,12 @@=20
.align 7
_GLOBAL(__copy_tofrom_user)arch/powerpc/lib/copyuser_64.S +6
-0+BEGIN_FTR_SECTION + nop +FTR_SECTION_ELSE + b __copy_tofrom_user_power7 +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_POWER7) +_GLOBAL(__copy_tofrom_user_base)
Quoted 3 lines
/* first check for a whole page copy on a page boundary */ cmpldi cr1,r5,16 cmpdi cr6,r5,4096
Can we find a means to do the fixup that does NOT require a FTR bit? I = have the feeling FSL will want to have various optimized copy functions = for our different cores and I hate to blow features bits just for this.
- k=
<snip>
Quoted 1 line
Quoted 1 line
+#define
CPU_FTR_POWER7=LONG_ASM_CONST(0x2000000000000000)
<snip>
Quoted 3 lines
Can we find a means to do the fixup that does NOT require a FTR bit? I have the feeling FSL will want to have various optimized copy functions for our different cores and I hate to blow features bits just for this.
+1
I hate the idea of having a POWER7 FTR bit. Every loon will (and has tried to in the past) attach every POWER7 related thing to it, rather than thinking about what the feature really is for.
What about other processors which could also benefit from this copy loop? Turning on CPU_FTR_POWER7 for them is gonna look a bit silly.
Mikey
Hi,
Quoted 6 lines
I hate the idea of having a POWER7 FTR bit. Every loon will (and has tried to in the past) attach every POWER7 related thing to it, rather than thinking about what the feature really is for.
What about other processors which could also benefit from this copy loop? Turning on
CPU_FTR_POWER7for them is gonna look a bit silly.
As we discussed online, we could call it CPU_FTR_VMX_COPY and start thinking about a better way to solve the CPU feature bit mess.
One idea would be to have a structure of function pointers for each CPU that gets runtime patched into the right places, similar to how we do some of the MMU fixups.
Anton
Quoted 9 lines
Quoted 6 lines
I hate the idea of having a POWER7 FTR bit. Every loon will (and has tried to in the past) attach every POWER7 related thing to it, rather than thinking about what the feature really is for.
What about other processors which could also benefit from this copy loop? Turning on
CPU_FTR_POWER7for them is gonna look a bit silly.As we discussed online, we could call it
CPU_FTR_VMX_COPYand start thinking about a better way to solve the CPU feature bit mess.
But then, most CPUs with VMX will not want that, because it is slower code for them. For things like copy loops it makes perfect sense to have them tuned per CPU core. For example, this code likes to use unaligned stores over more complicated shift-and-combine stuff; that works great on POWER7, but not on much else.
Maybe you should have the various kinds of loop ("source aligned, dest unaligned, using unaligned stores, 64 bytes") as asm routines, have some higher level code (which can be runtime patched) select which to run.
Quoted 3 lines
One idea would be to have a structure of function pointers for each CPU that gets runtime patched into the right places, similar to how we do some of the MMU fixups.
Sounds good to me :-)
Segher
=20
Quoted 5 lines
Quoted 3 lines
One idea would be to have a structure of function pointers for each CPU that gets runtime patched into the right places,=20 similar to how we do some of the MMU fixups.
=20
Sounds good to me :-)
Except the indirect jump/call is almost certainly never predicted - so will be slow.
You might want to patch jump instructions instead.
The same is true for in-kernel memcpy() and other similar operations.
I actually wonder sometimes what the typical lengths are for these sort of functions, and whether, in fact, small lengths dominate - where the fixed costs matter.
David
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines
One idea would be to have a structure of function pointers for each CPU that gets runtime patched into the right places, similar to how we do some of the MMU fixups.
Sounds good to me :-)
Except the indirect jump/call is almost certainly
never predicted - so will be slow.
What indirect jump? He said "runtime patched" :-)
Also, that "slow" is largely a myth.
Segher
Quoted 9 lines · Anton Blanchard
Hi,
Quoted 6 lines
I hate the idea of having a POWER7 FTR bit. Every loon will (and has tried to in the past) attach every POWER7 related thing to it, rather than thinking about what the feature really is for.
What about other processors which could also benefit from this copy loop? Turning on
CPU_FTR_POWER7for them is gonna look a bit silly.
Quoted 6 lines
As we discussed online, we could call it
CPU_FTR_VMX_COPYand start thinking about a better way to solve the CPU feature bit mess.One idea would be to have a structure of function pointers for each CPU that gets runtime patched into the right places, similar to how we do some of the MMU fixups.
Or the vdso... we have a table of some sort which is used to patch symbols.
But it's keyed off cpu features.
I'm reluctant to adding another table of PVRs, it needs to deal with the pseudo-PVRs from pHyp, and things will get out of sync.
CPU features are the way to go, tho we can use them to key off a branch patching mechanism if we want to. It's easy to add new bitmasks for in-kernel features at least (it's the user features which are more nasty but they are a separate thing).
So if we have to we can split cpu feature into another separate mask like I did for mmu features with the same macros etc... For example, the debug features could be moved out, or whatever.
Cheers,
Ben.
PATCH 1/1 powerpc: POWER7 optimised copy_to_user/copy_from_user using VMX
In reply to Michael NeulingImplement a POWER7 optimised copy_to_user/copy_from_user using VMX. For large aligned copies this new loop is over 10% faster, and for large unaligned copies it is over 200% faster.
If we take a fault we fall back to the old version, this keeps things relatively simple and easy to verify.
On POWER7 unaligned stores rarely slow down - they only flush when a store crosses a 4KB page boundary. Furthermore this flush is handled completely in hardware and should be 20-30 cycles.
Unaligned loads on the other hand flush much more often - whenever crossing a 128 byte cache line, or a 32 byte sector if either sector is an L1 miss.
Considering this information we really want to get the loads aligned and not worry about the alignment of the stores. Microbenchmarks confirm that this approach is much faster than the current unaligned copy loop that uses shifts and rotates to ensure both loads and stores are aligned.
We also want to try and do the stores in cacheline aligned, cacheline sized chunks. If the store queue is unable to merge an entire cacheline of stores then the L2 cache will have to do a read/modify/write. Even worse, we will serialise this with the stores in the next iteration of the copy loop since both iterations hit the same cacheline.
Based on this, the new loop does the following things:
1 - 127 bytes
Get the source 8 byte aligned and use 8 byte loads and stores. Pretty boring and similar to how the current loop works.
128 - 4095 bytes
Get the source 8 byte aligned and use 8 byte loads and stores, 1 cacheline at a time. We aren't doing the stores in cacheline aligned chunks so we will potentially serialise once per cacheline. Even so it is much better than the loop we have today.
4096 - bytes
If both source and destination have the same alignment get them both 16 byte aligned, then get the destination cacheline aligned. Do cacheline sized loads and stores using VMX.
If source and destination do not have the same alignment, we get the destination cacheline aligned, and use permute to do aligned loads.
In both cases the VMX loop should be optimal - we always do aligned loads and stores and are always doing stores in cacheline aligned, cacheline sized chunks.
To be able to use VMX we must be careful about interrupts and sleeping. We don't use the VMX loop when in an interrupt (which should be rare anyway) and we wrap the VMX loop in disable/enable_pagefault and fall back to the existing copy_tofrom_user loop if we do need to sleep.
The VMX breakpoint of 4096 bytes was chosen using this microbenchmark:
http://ozlabs.org/~anton/junkcode/copy_to_user.c
Since we are using VMX and there is a cost to saving and restoring the user VMX state there are two broad cases we need to benchmark:
- Best case - userspace never uses VMX
- Worst case - userspace always uses VMX
In reality a userspace process will sit somewhere between these two extremes. Since we need to test both aligned and unaligned copies we end up with 4 combinations. The point at which the VMX loop begins to win is:
0% VMX
aligned 2048 bytes
unaligned 2048 bytes
100% VMX
aligned 16384 bytes
unaligned 8192 bytes
Considering this is a microbenchmark, the data is hot in cache and the VMX loop has better store queue merging properties we set the breakpoint to 4096 bytes, a little below the unaligned breakpoints.
Some future optimisations we can look at:
- Looking at the perf data, a significant part of the cost when a task is always using VMX is the extra exception we take to restore the VMX state. As such we should do something similar to the x86 optimisation that restores FPU state for heavy users. ie:
/*
* If the task has used fpu the last 5 timeslices, just do a full
* restore of the math state immediately to avoid the trap; the
* chances of needing FPU soon are obviously high now */
preload_fpu = tsk_used_math(next_p) && next_p->fpu_counter > 5;
and
/*
* fpu_counter contains the number of consecutive context switches
* that the FPU is used. If this is over a threshold, the lazy fpu
* saving becomes unlazy to save the trap. This is an unsigned char
* so that after 256 times the counter wraps and the behavior turns
* lazy again; this to deal with bursty apps that only use FPU for
* a short time
*/
- We could create a paca bit to mirror the VMX enabled MSR bit and check that first, avoiding multiple calls to calling enable_kernel_altivec. That should help with iovec based system calls like readv.
- We could have two VMX breakpoints, one for when we know the user VMX state is loaded into the registers and one when it isn't. This could be a second bit in the paca so we can calculate the break points quickly.
- One suggestion from Ben was to save and restore the VSX registers we use inline instead of using enable_kernel_altivec.
---
arch/powerpc/include/asm/cputable.h +2 -1
@@ -201,6 +201,7 @@ extern const char *powerpc_base_platform#define CPU_FTR_POPCNTB LONG_ASM_CONST(0x0400000000000000)#define CPU_FTR_POPCNTD LONG_ASM_CONST(0x0800000000000000)#define CPU_FTR_ICSWX LONG_ASM_CONST(0x1000000000000000) +#define CPU_FTR_VMX_COPY LONG_ASM_CONST(0x2000000000000000)#ifndef __ASSEMBLY__
@@ -425,7 +426,7 @@ extern const char *powerpc_base_platform CPU_FTR_PURR | CPU_FTR_SPURR | CPU_FTR_REAL_LE | \ CPU_FTR_DSCR | CPU_FTR_SAO | CPU_FTR_ASYM_SMT | \ CPU_FTR_STCX_CHECKS_ADDRESS | CPU_FTR_POPCNTB | CPU_FTR_POPCNTD | \ - CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE) + CPU_FTR_ICSWX | CPU_FTR_CFAR | CPU_FTR_HVMODE | CPU_FTR_VMX_COPY)#define CPU_FTRS_CELL (CPU_FTR_USE_TB | CPU_FTR_LWSYNC | \ CPU_FTR_PPCAS_ARCH_V2 | CPU_FTR_CTRL | \ CPU_FTR_ALTIVEC_COMP | CPU_FTR_MMCRA | CPU_FTR_SMT | \
arch/powerpc/lib/copyuser_64.S +6 -0
@@ -11,6 +11,12 @@ .align 7 _GLOBAL(__copy_tofrom_user) +BEGIN_FTR_SECTION + nop +FTR_SECTION_ELSE + b __copy_tofrom_user_power7 +ALT_FTR_SECTION_END_IFCLR(CPU_FTR_VMX_COPY) +_GLOBAL(__copy_tofrom_user_base) /* first check for a whole page copy on a page boundary */ cmpldi cr1,r5,16 cmpdi cr6,r5,4096
arch/powerpc/lib/copyuser_power7.S new file +669 -0
669 lines not on this page · raw message
arch/powerpc/lib/Makefile +2 -1
@@ -16,7 +16,8 @@ obj-$(CONFIG_HAS_IOMEM) += devres.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o \ - checksum_wrappers_64.o hweight_64.o + checksum_wrappers_64.o hweight_64.o \ + copyuser_power7.o copyuser_power7_vmx.o obj-$(CONFIG_XMON) += sstep.o ldstfp.o obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o
arch/powerpc/lib/copyuser_power7_vmx.c new file +44 -0
44 lines not on this page · raw message
Quoted 3 lines · Anton Blanchard
Implement a POWER7 optimised copy_to_user/copy_from_user using VMX. For large aligned copies this new loop is over 10% faster, and for large unaligned copies it is over 200% faster.
Breaks !CONFIG_ALTIVEC build an pops some WARN's with preempt & lockdep, this seems to fix them:
arch/powerpc/lib/Makefile +2 -1
@@ -17,13 +17,14 @@ obj-$(CONFIG_HAS_IOMEM) += devres.o obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ memcpy_64.o usercopy_64.o mem_64.o string.o \ checksum_wrappers_64.o hweight_64.o \ - copyuser_power7.o copyuser_power7_vmx.o + copyuser_power7.o obj-$(CONFIG_XMON) += sstep.o ldstfp.o obj-$(CONFIG_KPROBES) += sstep.o ldstfp.o obj-$(CONFIG_HAVE_HW_BREAKPOINT) += sstep.o ldstfp.o ifeq ($(CONFIG_PPC64),y) obj-$(CONFIG_SMP) += locks.o +obj-$(CONFIG_ALTIVEC) += copyuser_power7_vmx.o endif obj-$(CONFIG_PPC_LIB_RHEAP) += rheap.o
arch/powerpc/lib/copyuser_power7.S +12 -0
@@ -85,6 +85,7 @@ _GLOBAL(__copy_tofrom_user_power7) +#ifdef CONFIG_ALTIVEC cmpldi r5,16 cmpldi cr1,r5,4096
@@ -94,6 +95,15 @@ _GLOBAL(__copy_tofrom_user_power7) blt .Lshort_copy bgt cr1,.Lvmx_copy +#else + cmpldi r5,16 + + std r3,48(r1) + std r4,56(r1) + std r5,64(r1) + + blt .Lshort_copy +#endif .Lnonvmx_copy: /* Get the source 8B aligned */
@@ -273,6 +283,7 @@ err1; stb r0,0(r3) addi r1,r1,STACKFRAMESIZE b .Lnonvmx_copy +#ifdef CONFIG_ALTIVEC .Lvmx_copy: mflr r0 std r0,16(r1)
@@ -667,3 +678,4 @@ err3; stb r0,0(r3) 15: addi r1,r1,STACKFRAMESIZE b .exit_vmx_copy /* tail call optimise */ +#endif /* CONFiG_ALTIVEC */
arch/powerpc/lib/copyuser_power7_vmx.c +8 -2
@@ -26,10 +26,16 @@ int enter_vmx_copy(void)if (in_interrupt ())return 0 ; -enable_kernel_altivec (); - +/* This acts as preempt_disable() as well and will make +* enable_kernel_altivec(). We need to disable page faults +* as they can call schedule and thus make us lose the VMX +* context. So on page faults, we just fail which will cause +* a fallback to the normal non-vmx copy. +*/ pagefault_disable (); +enable_kernel_altivec (); +return 1 ; }
Quoted 7 lines · Benjamin Herrenschmidt
Quoted 3 lines · Anton Blanchard
Implement a POWER7 optimised copy_to_user/copy_from_user using VMX. For large aligned copies this new loop is over 10% faster, and for large unaligned copies it is over 200% faster.
Breaks !CONFIG_ALTIVEC build an pops some WARN's with preempt & lockdep, this seems to fix them:
And it's missing another ifdef actually for !CONFIG_ALTIVEC, I'll fix it locally and will put a fixed version in -next.
Cheers,
Ben.