[PATCH] powerpc: Optimized strcpy for POWER9

Adhemerval Zanella adhemerval.zanella@linaro.org
Tue May 5 19:01:53 GMT 2020



On 04/05/2020 23:40, Anton Blanchard wrote:
> Hi Adhemerval,
> 
>>> This version is significantly faster on small strings and relatively
>>> unaligned large strings.  
>>
>> So it seems that it uses the ISA 3.0 partial stores to optimize vector
>> instructions usage, could you add it on the commit message?
> 
> Will do.
> 
>> The power8 version also adds an stpcpy version (which I am not sure is
>> really a gain for short strings) based on its strcpy.  Maybe it could
>> be a good thing to check if this could be adapted to be build as
>> stpcpy as well.
> 
> Good idea. I modified it to also implement stpcpy, and it shows decent
> gains - 40% faster on small strings and 90% faster on long relatively
> unaligned strings.

Nice.

> 
>> Usually for such optimizations we try to get a baseline benchmark
>> results using glibc benchtests.  Could you post the results for
>> before and after?
> 
> How do you want the results? Should I just mail the output of the
> relevant glibc benchtest?

Yes, just attach the bench-st{r,p}cpy.out. pre and pos patch.

> 
>> (Some of the glibc benchtests does have some shortcomings, but at
>> least it documents some of the expected gains and performance
>> differences with the new implementation.)
> 
> I wonder if an option to do more thorough testing would be useful. For
> example, I have a local modification to do an exhaustive test of all
> alignments and lengths up to a certain point (eg 128 bytes) to make
> sure there aren't any corner cases.

Sure, testing improvements is always welcomed!

> 
> More random argument benchmarks would be useful too.

And benchtests improvements as well.

> 
> Thanks,
> Anton
> 
>>
>>> ---
>>>  sysdeps/powerpc/powerpc64/le/power9/strcpy.S  | 144
>>> ++++++++++++++++++ sysdeps/powerpc/powerpc64/multiarch/Makefile  |
>>>  2 +- .../powerpc64/multiarch/ifunc-impl-list.c     |   4 +
>>>  .../powerpc64/multiarch/strcpy-power9.S       |  26 ++++
>>>  sysdeps/powerpc/powerpc64/multiarch/strcpy.c  |   7 +
>>>  5 files changed, 182 insertions(+), 1 deletion(-)
>>>  create mode 100644 sysdeps/powerpc/powerpc64/le/power9/strcpy.S
>>>  create mode 100644
>>> sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S
>>>
>>> diff --git a/sysdeps/powerpc/powerpc64/le/power9/strcpy.S
>>> b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S new file mode 100644
>>> index 0000000000..5749228054
>>> --- /dev/null
>>> +++ b/sysdeps/powerpc/powerpc64/le/power9/strcpy.S
>>> @@ -0,0 +1,144 @@
>>> +/* Optimized strcpy implementation for PowerPC64/POWER9.
>>> +   Copyright (C) 2020 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it
>>> and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later
>>> version. +
>>> +   The GNU C Library is distributed in the hope that it will be
>>> useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>> +
>>> +#include <sysdep.h>
>>> +
>>> +#ifndef STRCPY
>>> +# define STRCPY strcpy
>>> +#endif
>>> +
>>> +/* Implements the function
>>> +
>>> +   char * [r3] strcpy (char *dest [r3], const char *src [r4])
>>> +
>>> +   The implementation can load bytes past a null terminator, but
>>> only
>>> +   up to the next 16B boundary, so it never crosses a page.  */
>>> +
>>> +.machine power9
>>> +ENTRY_TOCLESS (STRCPY, 4)
>>> +	CALL_MCOUNT 2
>>> +
>>> +	/* NULL string optimisation  */
>>> +	lbz	r0,0(r4)
>>> +	stb	r0,0(r3)
>>> +	cmpwi	r0,0
>>> +	beqlr  
>>
>> Is it a worth optimization? None of other strcpy arch optimizations
>> does it.
>>
>>> +
>>> +	addi	r4,r4,1
>>> +	addi	r11,r3,1
>>> +
>>> +	vspltisb v18,0		/* Zeroes in v18  */
>>> +
>>> +	neg	r5,r4
>>> +	rldicl	r9,r5,0,60	/* How many bytes to get
>>> source 16B aligned?  */ +
>>> +	/* Get source 16B aligned  */
>>> +	lvx	v0,0,r4
>>> +	lvsr	v1,0,r4
>>> +	vperm	v0,v18,v0,v1
>>> +
>>> +	vcmpequb v6,v0,v18	/* 0xff if byte is NULL, 0x00
>>> otherwise  */
>>> +	vctzlsbb r8,v6		/* Number of trailing zeroes
>>>  */
>>> +	addi	r8,r8,1		/* Add null terminator
>>> */ +
>>> +	/* r8 = bytes including null
>>> +	   r9 = bytes to get source 16B aligned
>>> +	   if r8 > r9
>>> +	      no null, copy r9 bytes
>>> +	   else
>>> +	      there is a null, copy r8 bytes and return.  */
>>> +	cmpd	r8,r9
>>> +	bgt	L(no_null)
>>> +
>>> +	sldi	r10,r8,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	stxvl	32+v0,r11,r10	/* Partial store  */
>>> +
>>> +	blr
>>> +
>>> +L(no_null):
>>> +	sldi	r10,r9,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	stxvl	32+v0,r11,r10	/* Partial store  */
>>> +
>>> +	add	r4,r4,r9
>>> +	add	r11,r11,r9
>>> +
>>> +L(loop):  
>>
>> Should we eforce alignment here?
>>
>>> +	lxv	32+v0,0(r4)
>>> +	vcmpequb. v6,v0,v18	/* Any zero bytes?  */
>>> +	bne	cr6,L(tail1)
>>> +
>>> +	lxv	32+v1,16(r4)
>>> +	vcmpequb. v6,v1,v18	/* Any zero bytes?  */
>>> +	bne	cr6,L(tail2)
>>> +
>>> +	lxv	32+v2,32(r4)
>>> +	vcmpequb. v6,v2,v18	/* Any zero bytes?  */
>>> +	bne	cr6,L(tail3)
>>> +
>>> +	lxv	32+v3,48(r4)
>>> +	vcmpequb. v6,v3,v18	/* Any zero bytes?  */
>>> +	bne	cr6,L(tail4)
>>> +
>>> +	stxv	32+v0,0(r11)
>>> +	stxv	32+v1,16(r11)
>>> +	stxv	32+v2,32(r11)
>>> +	stxv	32+v3,48(r11)  
>>
>> Out of curiosity, why unroll 4x time here?
>>
>>> +
>>> +	addi	r4,r4,64
>>> +	addi	r11,r11,64
>>> +
>>> +	b	L(loop)
>>> +
>>> +L(tail1):
>>> +	vctzlsbb r8,v6
>>> +	addi	r8,r8,1
>>> +	sldi	r9,r8,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	stxvl	32+v0,r11,r9
>>> +	blr
>>> +
>>> +L(tail2):
>>> +	stxv	32+v0,0(r11)
>>> +	vctzlsbb r8,v6		/* Number of trailing zeroes
>>>  */
>>> +	addi	r8,r8,1		/* Add null terminator
>>> */
>>> +	sldi	r10,r8,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	addi	r11,r11,16
>>> +	stxvl	32+v1,r11,r10	/* Partial store  */
>>> +	blr
>>> +
>>> +L(tail3):
>>> +	stxv	32+v0,0(r11)
>>> +	stxv	32+v1,16(r11)
>>> +	vctzlsbb r8,v6		/* Number of trailing zeroes
>>>  */
>>> +	addi	r8,r8,1		/* Add null terminator
>>> */
>>> +	sldi	r10,r8,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	addi	r11,r11,32
>>> +	stxvl	32+v2,r11,r10	/* Partial store  */
>>> +	blr
>>> +
>>> +L(tail4):
>>> +	stxv	32+v0,0(r11)
>>> +	stxv	32+v1,16(r11)
>>> +	stxv	32+v2,32(r11)
>>> +	vctzlsbb r8,v6		/* Number of trailing zeroes
>>>  */
>>> +	addi	r8,r8,1		/* Add null terminator
>>> */
>>> +	sldi	r10,r8,56	/* stxvl wants size in top 8
>>> bits  */
>>> +	addi	r11,r11,48
>>> +	stxvl	32+v3,r11,r10	/* Partial store  */
>>> +	blr
>>> +END (STRCPY)
>>> +libc_hidden_builtin_def (strcpy)
>>> diff --git a/sysdeps/powerpc/powerpc64/multiarch/Makefile
>>> b/sysdeps/powerpc/powerpc64/multiarch/Makefile index
>>> ea936bf9ed..db11345053 100644 ---
>>> a/sysdeps/powerpc/powerpc64/multiarch/Makefile +++
>>> b/sysdeps/powerpc/powerpc64/multiarch/Makefile @@ -32,7 +32,7 @@
>>> sysdep_routines += memcpy-power8-cached memcpy-power7 memcpy-a2
>>> memcpy-power6 \ strncase-power8 
>>>  ifneq (,$(filter %le,$(config-machine)))
>>> -sysdep_routines += strcmp-power9 strncmp-power9
>>> +sysdep_routines += strcmp-power9 strncmp-power9 strcpy-power9
>>>  endif
>>>  CFLAGS-strncase-power7.c += -mcpu=power7 -funroll-loops
>>>  CFLAGS-strncase_l-power7.c += -mcpu=power7 -funroll-loops  
>>
>> Ok.
>>
>>> diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
>>> b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c index
>>> b9fef3f43c..ad11ede20e 100644 ---
>>> a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c +++
>>> b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c @@ -85,6
>>> +85,10 @@ __libc_ifunc_impl_list (const char *name, struct
>>> libc_ifunc_impl *array, /* Support
>>> sysdeps/powerpc/powerpc64/multiarch/strcpy.c.  */ IFUNC_IMPL (i,
>>> name, strcpy, +#ifdef __LITTLE_ENDIAN__
>>> +	      IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 &
>>> PPC_FEATURE2_ARCH_3_00,
>>> +			      __strcpy_power9)
>>> +#endif
>>>  	      IFUNC_IMPL_ADD (array, i, strcpy, hwcap2 &
>>> PPC_FEATURE2_ARCH_2_07, __strcpy_power8)
>>>  	      IFUNC_IMPL_ADD (array, i, strcpy, hwcap &
>>> PPC_FEATURE_HAS_VSX,  
>>
>> Ok.
>>
>>> diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S
>>> b/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S new file mode
>>> 100644 index 0000000000..d22aa0a8d6
>>> --- /dev/null
>>> +++ b/sysdeps/powerpc/powerpc64/multiarch/strcpy-power9.S
>>> @@ -0,0 +1,26 @@
>>> +/* Optimized strcpy implementation for POWER9/PPC64.
>>> +   Copyright (C) 2016-2020 Free Software Foundation, Inc.
>>> +   This file is part of the GNU C Library.
>>> +
>>> +   The GNU C Library is free software; you can redistribute it
>>> and/or
>>> +   modify it under the terms of the GNU Lesser General Public
>>> +   License as published by the Free Software Foundation; either
>>> +   version 2.1 of the License, or (at your option) any later
>>> version. +
>>> +   The GNU C Library is distributed in the hope that it will be
>>> useful,
>>> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
>>> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>>> GNU
>>> +   Lesser General Public License for more details.
>>> +
>>> +   You should have received a copy of the GNU Lesser General Public
>>> +   License along with the GNU C Library; if not, see
>>> +   <https://www.gnu.org/licenses/>.  */
>>> +
>>> +#if defined __LITTLE_ENDIAN__ && IS_IN (libc)
>>> +#define STRCPY __strcpy_power9
>>> +
>>> +#undef libc_hidden_builtin_def
>>> +#define libc_hidden_builtin_def(name)
>>> +
>>> +#include <sysdeps/powerpc/powerpc64/le/power9/strcpy.S>
>>> +#endif  
>>
>> Ok.
>>
>>> diff --git a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c
>>> b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c index
>>> 66ea93b8f4..dcdee5181f 100644 ---
>>> a/sysdeps/powerpc/powerpc64/multiarch/strcpy.c +++
>>> b/sysdeps/powerpc/powerpc64/multiarch/strcpy.c @@ -25,9 +25,16 @@
>>>  extern __typeof (strcpy) __strcpy_ppc attribute_hidden;
>>>  extern __typeof (strcpy) __strcpy_power7 attribute_hidden;
>>>  extern __typeof (strcpy) __strcpy_power8 attribute_hidden;
>>> +# ifdef __LITTLE_ENDIAN__
>>> +extern __typeof (strcpy) __strcpy_power9 attribute_hidden;
>>> +# endif
>>>  #undef strcpy
>>>  
>>>  libc_ifunc_redirected (__redirect_strcpy, strcpy,
>>> +# ifdef __LITTLE_ENDIAN__
>>> +			(hwcap2 & PPC_FEATURE2_ARCH_3_00)
>>> +			? __strcpy_power9 :
>>> +# endif
>>>  		       (hwcap2 & PPC_FEATURE2_ARCH_2_07)
>>>  		       ? __strcpy_power8
>>>  		       : (hwcap & PPC_FEATURE_HAS_VSX)
>>>   
>>
>> Ok.
>>
> 


More information about the Libc-alpha mailing list