powerpc: Optimise enable_kernel_altivec
authorAnton Blanchard <anton@samba.org>
Sun, 15 Apr 2012 20:56:45 +0000 (20:56 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Mon, 30 Apr 2012 05:37:17 +0000 (15:37 +1000)
Add two optimisations to enable_kernel_altivec:

- enable_kernel_altivec has already determined if we need to
save the previous task's state but we call giveup_altivec
in both cases, requiring an extra branch in giveup_altivec. Create
giveup_altivec_notask which only turns on the VMX bit in the
MSR.

- We write the VMX MSR bit each time we call enable_kernel_altivec
even it was already set. Check the bit and branch out if we have
already set it. The classic case for this is vectored IO
where we have to copy multiple buffers to or from userspace.

The following testcase was used to confirm this patch improves
performance:

http://ozlabs.org/~anton/junkcode/copy_to_user.c

Since the current breakpoint for using VMX in copy_tofrom_user is
4096 bytes, I'm using buffers of 4096 + 1 cacheline (4224) bytes.
A benchmark of 16 entry readvs (-s 16):

time copy_to_user -l 4224 -s 16 -i 1000000

completes 5.2% faster on a POWER7 PS700.

Signed-off-by: Anton Blanchard <anton@samba.org>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/include/asm/switch_to.h
arch/powerpc/kernel/process.c
arch/powerpc/kernel/vector.S

index 2824609319c7c33145e869cec35e611e7394b185..1a6320290d2616d971c2c09ca6da2281e5b766fb 100644 (file)
@@ -40,6 +40,7 @@ static inline void discard_lazy_cpu_state(void)
 #ifdef CONFIG_ALTIVEC
 extern void flush_altivec_to_thread(struct task_struct *);
 extern void giveup_altivec(struct task_struct *);
+extern void giveup_altivec_notask(void);
 #else
 static inline void flush_altivec_to_thread(struct task_struct *t)
 {
index 4937c9690090d0e9bf3809b7ae923ae24d181d93..bb58f41fc045c673ab333f5a1a1ac8c097d4e0e2 100644 (file)
@@ -124,7 +124,7 @@ void enable_kernel_altivec(void)
        if (current->thread.regs && (current->thread.regs->msr & MSR_VEC))
                giveup_altivec(current);
        else
-               giveup_altivec(NULL);   /* just enable AltiVec for kernel - force */
+               giveup_altivec_notask();
 #else
        giveup_altivec(last_task_used_altivec);
 #endif /* CONFIG_SMP */
index 4d5a3edff49ebfe5f660c9233c8bb94f39deb41c..e830289d2e4874af433f856d565813c949bee0a4 100644 (file)
@@ -89,6 +89,16 @@ _GLOBAL(load_up_altivec)
        /* restore registers and return */
        blr
 
+_GLOBAL(giveup_altivec_notask)
+       mfmsr   r3
+       andis.  r4,r3,MSR_VEC@h
+       bnelr                           /* Already enabled? */
+       oris    r3,r3,MSR_VEC@h
+       SYNC
+       MTMSRD(r3)                      /* enable use of VMX now */
+       isync
+       blr
+
 /*
  * giveup_altivec(tsk)
  * Disable VMX for the task given as the argument,