This is the mail archive of the glibc-cvs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

GNU C Library master sources branch master updated. glibc-2.26-532-gdd5bc7f


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "GNU C Library master sources".

The branch, master has been updated
       via  dd5bc7f1b385b29d0f90aefe4d9756b35011709b (commit)
       via  5bfb04042dfadc335cde63afe892be140cbe6f31 (commit)
       via  36bb8edf5178247933dfeee71812cda93587d32e (commit)
       via  9ec87fd2b11ffce5c27c8eacb9deaa20e2373ff5 (commit)
      from  1e9522c61c7a544d59db32cb7fbbd42e6793d848 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=dd5bc7f1b385b29d0f90aefe4d9756b35011709b

commit dd5bc7f1b385b29d0f90aefe4d9756b35011709b
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Thu Oct 5 21:55:31 2017 +0530

    aarch64: Optimized implementation of memmove for Qualcomm Falkor
    
    This is an optimized memmove implementation for the Qualcomm Falkor
    processor core.  Due to the way the falkor memcpy needs to be written,
    code cannot be easily shared between memmove and memcpy like in case
    of other aarch64 memcpy implementations due to which this routine is
    separate.  The underlying principle is the same as that of memcpy
    where it tries to use registers with the same lower 4 bits for
    fetching the same stream, thus optimizing hardware prefetcher
    performance.
    
    The memcpy copy loop copies 64 bytes at a time using the same register
    pair since that's the way to train the hardware prefetcher on the
    falkor core.  memmove cannot quite do that since it needs to avoid
    overlaps, so it does the next best thing, i.e. has a 32 byte loop with
    a 32 byte end (prefetch a loop ahead to account for overlapping
    locations) with register pairs that alias so that they hit the same
    prefetcher.  Due to this difference in loop size, they have to
    currently be separate implementations but efforts are on to try and
    get memmove to fall back into memcpy whenever it can without simply
    duplicating all of the code.
    
    Performance:
    
    The routine fares around 20-25% better than the generic memmove for
    most medium to large sizes (i.e. > 128 bytes) for the new walking
    memmove benchmark (memmove-walk) with an unexplained regression
    between 1K and 2K.  The minor regression is something worth looking
    into for us, but the remaining gains are significant enough that we
    would like this included upstream as we looking into the cause for the
    regression.  Here is a snippet of the numbers as generated from the
    microbenchmark by the compare_strings script.  Comparisons are against
    __memmove_generic:
    
    Function: memmove
    Variant: walk
                                        __memmove_thunderx	__memmove_falkor	__memmove_generic
    ========================================================================================================================
    <snip>
                            length=16384:  12508800.00 (  6.09%)	 11486800.00 ( 13.76%)	 13319600.00
                            length=16400:  13614200.00 ( -0.67%)	 11585000.00 ( 14.33%)	 13523600.00
                            length=16385:  13448400.00 (  0.10%)	 11732700.00 ( 12.84%)	 13461200.00
                            length=16399:  13594100.00 ( -0.22%)	 11859600.00 ( 12.57%)	 13564400.00
                            length=16386:  13211600.00 (  1.13%)	 11503800.00 ( 13.91%)	 13362400.00
                            length=16398:  13218600.00 (  2.12%)	 11573200.00 ( 14.30%)	 13504700.00
                            length=16387:  13510900.00 ( -0.37%)	 11744200.00 ( 12.76%)	 13461300.00
                            length=16397:  13603700.00 ( -0.15%)	 11878200.00 ( 12.55%)	 13583200.00
                            length=16388:  13461700.00 ( -0.13%)	 11558000.00 ( 14.03%)	 13444100.00
                            length=16396:  13517500.00 ( -0.03%)	 11561300.00 ( 14.45%)	 13513900.00
                            length=16389:  13534100.00 (  0.17%)	 11756800.00 ( 13.28%)	 13556900.00
                            length=16395:  13585600.00 (  0.11%)	 11791800.00 ( 13.30%)	 13601200.00
                            length=16390:  13480100.00 ( -0.13%)	 11685500.00 ( 13.20%)	 13462100.00
                            length=16394:  13529900.00 ( -0.23%)	 11549800.00 ( 14.43%)	 13498200.00
                            length=16391:  13595400.00 ( -0.26%)	 11768200.00 ( 13.22%)	 13560600.00
                            length=16393:  13567000.00 (  0.20%)	 11779700.00 ( 13.35%)	 13594700.00
                            length=32768:  71308800.00 ( -6.53%)	 50220800.00 ( 24.98%)	 66939200.00
                            length=32784:  72100800.00 (-11.55%)	 50114100.00 ( 22.47%)	 64636300.00
                            length=32769:  71767000.00 ( -7.10%)	 51238400.00 ( 23.54%)	 67010000.00
                            length=32783:  70113700.00 (-40.95%)	 51129000.00 ( -2.78%)	 49744400.00
                            length=32770:  71367600.00 ( -6.52%)	 50244700.00 ( 25.01%)	 67000900.00
                            length=32782:  64366700.00 (  4.71%)	 50101400.00 ( 25.83%)	 67545600.00
                            length=32771:  71440100.00 ( -6.51%)	 51263900.00 ( 23.57%)	 67074900.00
                            length=32781:  66993000.00 (  0.34%)	 51108300.00 ( 23.97%)	 67220300.00
                            length=32772:  71443900.00 (-60.50%)	 50062100.00 (-12.47%)	 44512600.00
                            length=32780:  71759100.00 ( -6.58%)	 50263200.00 ( 25.35%)	 67328600.00
                            length=32773:  71714900.00 (-33.21%)	 51076600.00 (  5.12%)	 53835400.00
                            length=32779:  71756900.00 ( -6.56%)	 51290800.00 ( 23.83%)	 67337800.00
                            length=32774:  59689300.00 (-34.55%)	 50068400.00 (-12.86%)	 44363300.00
                            length=32778:  71847500.00 (-18.20%)	 50084100.00 ( 17.61%)	 60786500.00
                            length=32775:  71599300.00 ( -6.54%)	 51278200.00 ( 23.70%)	 67204800.00
                            length=32777:  71862900.00 (-60.85%)	 51094000.00 (-14.36%)	 44677900.00
                            length=65536: 282848000.00 ( -6.60%)	199187000.00 ( 24.93%)	265325000.00
                            length=65552: 243285000.00 (-41.61%)	198512000.00 (-15.54%)	171805000.00
                            length=65537: 255415000.00 (-23.47%)	202499000.00 (  2.11%)	206858000.00
                            length=65551: 280122000.00 (-62.95%)	203349000.00 (-18.29%)	171911000.00
                            length=65538: 283676000.00 (-14.46%)	198368000.00 ( 19.96%)	247848000.00
                            length=65550: 275566000.00 (-51.76%)	198494000.00 ( -9.31%)	181581000.00
                            length=65539: 283699000.00 ( -6.58%)	203453000.00 ( 23.57%)	266195000.00
                            length=65549: 286572000.00 ( -6.65%)	202607000.00 ( 24.60%)	268712000.00
                            length=65540: 283710000.00 ( -6.59%)	199161000.00 ( 25.17%)	266160000.00
                            length=65548: 237573000.00 ( 11.48%)	198462000.00 ( 26.06%)	268395000.00
                            length=65541: 284150000.00 ( -6.58%)	203273000.00 ( 23.75%)	266600000.00
                            length=65547: 286250000.00 ( -6.70%)	202594000.00 ( 24.48%)	268263000.00
                            length=65542: 284167000.00 ( -6.60%)	199122000.00 ( 25.31%)	266584000.00
                            length=65546: 285656000.00 ( -6.59%)	198443000.00 ( 25.95%)	268002000.00
                            length=65543: 284600000.00 ( -6.58%)	203247000.00 ( 23.89%)	267030000.00
                            length=65545: 285665000.00 ( -6.40%)	202575000.00 ( 24.55%)	268472000.00
    <snip>
    
    	* sysdeps/aarch64/multiarch/Makefile (sysdep_routines): Add
    	memmove_falkor.
    	* sysdeps/aarch64/multiarch/ifunc-impl-list.c
    	(__libc_ifunc_impl_list): Likewise.
    	* sysdeps/aarch64/multiarch/memmove.c: Likewise.
    	* sysdeps/aarch64/multiarch/memmove_falkor.S: New file.

diff --git a/ChangeLog b/ChangeLog
index 6d4b5f2..74c51ea 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,12 @@
 2017-10-05  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
+	* sysdeps/aarch64/multiarch/Makefile (sysdep_routines): Add
+	memmove_falkor.
+	* sysdeps/aarch64/multiarch/ifunc-impl-list.c
+	(__libc_ifunc_impl_list): Likewise.
+	* sysdeps/aarch64/multiarch/memmove.c: Likewise.
+	* sysdeps/aarch64/multiarch/memmove_falkor.S: New file.
+
 	* benchtests/bench-memmove-walk.c: New file.
 	* benchtests/Makefile (string-benchset): Add it.
 
diff --git a/sysdeps/aarch64/multiarch/Makefile b/sysdeps/aarch64/multiarch/Makefile
index 164ba1a..9aa1e79 100644
--- a/sysdeps/aarch64/multiarch/Makefile
+++ b/sysdeps/aarch64/multiarch/Makefile
@@ -1,3 +1,4 @@
 ifeq ($(subdir),string)
-sysdep_routines += memcpy_generic memcpy_thunderx memcpy_falkor
+sysdep_routines += memcpy_generic memcpy_thunderx memcpy_falkor \
+		   memmove_falkor
 endif
diff --git a/sysdeps/aarch64/multiarch/ifunc-impl-list.c b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
index 8e873b3..2cb74d5 100644
--- a/sysdeps/aarch64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/aarch64/multiarch/ifunc-impl-list.c
@@ -44,6 +44,7 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 	      IFUNC_IMPL_ADD (array, i, memcpy, 1, __memcpy_generic))
   IFUNC_IMPL (i, name, memmove,
 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_thunderx)
+	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_falkor)
 	      IFUNC_IMPL_ADD (array, i, memmove, 1, __memmove_generic))
 
   return i;
diff --git a/sysdeps/aarch64/multiarch/memmove.c b/sysdeps/aarch64/multiarch/memmove.c
index 34c6b29..016f03e 100644
--- a/sysdeps/aarch64/multiarch/memmove.c
+++ b/sysdeps/aarch64/multiarch/memmove.c
@@ -30,9 +30,14 @@ extern __typeof (__redirect_memmove) __libc_memmove;
 
 extern __typeof (__redirect_memmove) __memmove_generic attribute_hidden;
 extern __typeof (__redirect_memmove) __memmove_thunderx attribute_hidden;
+extern __typeof (__redirect_memmove) __memmove_falkor attribute_hidden;
 
 libc_ifunc (__libc_memmove,
-            IS_THUNDERX (midr) ? __memmove_thunderx : __memmove_generic);
+            (IS_THUNDERX (midr)
+	     ? __memmove_thunderx
+	     : (IS_FALKOR (midr)
+		? __memmove_falkor
+		: __memmove_generic)));
 
 # undef memmove
 strong_alias (__libc_memmove, memmove);
diff --git a/sysdeps/aarch64/multiarch/memmove_falkor.S b/sysdeps/aarch64/multiarch/memmove_falkor.S
new file mode 100644
index 0000000..3a4e6a2
--- /dev/null
+++ b/sysdeps/aarch64/multiarch/memmove_falkor.S
@@ -0,0 +1,232 @@
+/* Copyright (C) 2017 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
+   <http://www.gnu.org/licenses/>.  */
+
+#include <sysdep.h>
+
+/* Assumptions: ARMv8-a, AArch64, falkor, unaligned accesses.  */
+
+#define dstin	x0
+#define src	x1
+#define count	x2
+#define dstlen	x3
+#define dst	x3
+#define srcend	x4
+#define dstend	x5
+#define A_l	x6
+#define A_lw	w6
+#define A_h	x7
+#define A_hw	w7
+#define B_l	x8
+#define B_lw	w8
+#define B_h	x9
+#define C_l	x10
+#define C_h	x11
+#define D_l	x12
+#define D_h	x13
+#define E_l	src
+#define E_h	count
+#define F_l	srcend
+#define F_h	dst
+#define tmp1	x14
+
+/* Alias with A_l and A_h to train the prefetcher.  */
+#define Q_l	x22
+#define Q_h	x23
+
+/* RATIONALE:
+
+   The copy has 4 distinct parts:
+   * Small copies of 16 bytes and under
+   * Medium sized copies of 17-96 bytes
+   * Large copies where the source address is higher than the destination
+     (forward copies)
+   * Large copies where the destination address is higher than the source
+     (copy backward, or move).
+
+   We use only two registerpairs x6,x7 and x22,x23 for the copies and copy 32
+   bytes at a time to correctly train the hardware prefetcher for better
+   throughput.  */
+ENTRY_ALIGN (__memmove_falkor, 6)
+
+	sub	tmp1, dstin, src
+	add	srcend, src, count
+	add	dstend, dstin, count
+	cmp	count, 96
+	ccmp	tmp1, count, 2, hi
+	b.lo	L(move_long)
+
+	cmp	count, 16
+	b.ls	L(copy16)
+	cmp	count, 96
+	b.hi	L(copy_long)
+
+	/* Medium copies: 17..96 bytes.  */
+	sub	tmp1, count, 1
+	ldp	A_l, A_h, [src]
+	tbnz	tmp1, 6, L(copy96)
+	ldp	D_l, D_h, [srcend, -16]
+	tbz	tmp1, 5, 1f
+	ldp	B_l, B_h, [src, 16]
+	ldp	C_l, C_h, [srcend, -32]
+	stp	B_l, B_h, [dstin, 16]
+	stp	C_l, C_h, [dstend, -32]
+1:
+	stp	A_l, A_h, [dstin]
+	stp	D_l, D_h, [dstend, -16]
+	ret
+
+	.p2align 4
+	/* Small copies: 0..16 bytes.  */
+L(copy16):
+	cmp	count, 8
+	b.lo	1f
+	ldr	A_l, [src]
+	ldr	A_h, [srcend, -8]
+	str	A_l, [dstin]
+	str	A_h, [dstend, -8]
+	ret
+	.p2align 4
+1:
+	/* 4-7 */
+	tbz	count, 2, 1f
+	ldr	A_lw, [src]
+	ldr	A_hw, [srcend, -4]
+	str	A_lw, [dstin]
+	str	A_hw, [dstend, -4]
+	ret
+	.p2align 4
+1:
+	/* 2-3 */
+	tbz	count, 1, 1f
+	ldrh	A_lw, [src]
+	ldrh	A_hw, [srcend, -2]
+	strh	A_lw, [dstin]
+	strh	A_hw, [dstend, -2]
+	ret
+	.p2align 4
+1:
+	/* 0-1 */
+	tbz	count, 0, 1f
+	ldrb	A_lw, [src]
+	strb	A_lw, [dstin]
+1:	ret
+
+	.p2align 4
+	/* Copy 64..96 bytes.  Copy 64 bytes from the start and
+	   32 bytes from the end.  */
+L(copy96):
+	ldp	B_l, B_h, [src, 16]
+	ldp	C_l, C_h, [src, 32]
+	ldp	D_l, D_h, [src, 48]
+	ldp	E_l, E_h, [srcend, -32]
+	ldp	F_l, F_h, [srcend, -16]
+	stp	A_l, A_h, [dstin]
+	stp	B_l, B_h, [dstin, 16]
+	stp	C_l, C_h, [dstin, 32]
+	stp	D_l, D_h, [dstin, 48]
+	stp	E_l, E_h, [dstend, -32]
+	stp	F_l, F_h, [dstend, -16]
+	ret
+
+	/* Align SRC to 16 byte alignment so that we don't cross cache line
+	   boundaries on both loads and stores.  There are at least 96 bytes
+	   to copy, so copy 16 bytes unaligned and then align.  The loop
+	   copies 32 bytes per iteration and prefetches one iteration ahead.  */
+
+	.p2align 4
+L(copy_long):
+	sub	count, count, 64 + 16	/* Test and readjust count.  */
+	mov	B_l, Q_l
+	mov	B_h, Q_h
+	ldp	A_l, A_h, [src]
+	and	tmp1, src, 15
+	bic	src, src, 15
+	sub	dst, dstin, tmp1
+	add	count, count, tmp1	/* Count is now 16 too large.  */
+	ldp	Q_l, Q_h, [src, 16]!
+	stp	A_l, A_h, [dstin]
+	ldp	A_l, A_h, [src, 16]!
+
+L(loop64):
+	subs	count, count, 32
+	stp	Q_l, Q_h, [dst, 16]
+	ldp	Q_l, Q_h, [src, 16]!
+	stp	A_l, A_h, [dst, 32]!
+	ldp	A_l, A_h, [src, 16]!
+	b.hi	L(loop64)
+
+	/* Write the last full set of 32 bytes.  The remainder is at most 32
+	   bytes, so it is safe to always copy 32 bytes from the end even if
+	   there is just 1 byte left.  */
+L(last64):
+	ldp	C_l, C_h, [srcend, -32]
+	stp	Q_l, Q_h, [dst, 16]
+	ldp	Q_l, Q_h, [srcend, -16]
+	stp	A_l, A_h, [dst, 32]
+	stp	C_l, C_h, [dstend, -32]
+	stp	Q_l, Q_h, [dstend, -16]
+	mov	Q_l, B_l
+	mov	Q_h, B_h
+	ret
+
+	.p2align 4
+L(move_long):
+	cbz	tmp1, 3f
+
+	mov	B_l, Q_l
+	mov	B_h, Q_h
+
+	/* Align SRCEND to 16 byte alignment so that we don't cross cache line
+	   boundaries on both loads and stores.  There are at least 96 bytes
+	   to copy, so copy 16 bytes unaligned and then align.  The loop
+	   copies 32 bytes per iteration and prefetches one iteration ahead.  */
+
+	ldp	A_l, A_h, [srcend, -16]
+	and	tmp1, srcend, 15
+	sub	srcend, srcend, tmp1
+	ldp	Q_l, Q_h, [srcend, -16]!
+	stp	A_l, A_h, [dstend, -16]
+	sub	count, count, tmp1
+	ldp	A_l, A_h, [srcend, -16]!
+	sub	dstend, dstend, tmp1
+	sub	count, count, 64
+
+1:
+	subs	count, count, 32
+	stp	Q_l, Q_h, [dstend, -16]
+	ldp	Q_l, Q_h, [srcend, -16]!
+	stp	A_l, A_h, [dstend, -32]!
+	ldp	A_l, A_h, [srcend, -16]!
+	b.hi	1b
+
+	/* Write the last full set of 32 bytes.  The remainder is at most 32
+	   bytes, so it is safe to always copy 32 bytes from the start even if
+	   there is just 1 byte left.  */
+2:
+	ldp	C_l, C_h, [src, 16]
+	stp	Q_l, Q_h, [dstend, -16]
+	ldp	Q_l, Q_h, [src]
+	stp	A_l, A_h, [dstend, -32]
+	stp	C_l, C_h, [dstin, 16]
+	stp	Q_l, Q_h, [dstin]
+	mov	Q_l, B_l
+	mov	Q_h, B_h
+3:	ret
+
+END (__memmove_falkor)
+libc_hidden_builtin_def (__memmove_falkor)

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=5bfb04042dfadc335cde63afe892be140cbe6f31

commit 5bfb04042dfadc335cde63afe892be140cbe6f31
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Thu Oct 5 21:53:13 2017 +0530

    benchtests: Memory walking benchmark for memmove
    
    This benchmark is an attempt to eliminate cache effects from string
    benchmarks.  The benchmark walks both ways through a large memory area
    and copies different sizes of memory and alignments one at a time
    instead of looping around in the same memory area.  This is a good
    metric to have alongside the simple memmove benchmark (which is only
    really useful for smaller sizes) especially for larger sizes where the
    likelihood of the call being done only once is pretty high.
    
    This benchmark is different from memcpy in that it also tests
    overlapping copies.
    
    	* benchtests/bench-memmove-walk.c: New file.
    	* benchtests/Makefile (string-benchset): Add it.

diff --git a/ChangeLog b/ChangeLog
index 5821c5d..6d4b5f2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2017-10-05  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
+	* benchtests/bench-memmove-walk.c: New file.
+	* benchtests/Makefile (string-benchset): Add it.
+
 	* benchtests/bench-memset-walk.c: New file.
 	* benchtests/Makefile (string-benchset): Add it.
 
diff --git a/benchtests/Makefile b/benchtests/Makefile
index 5a07639..d8681fc 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -38,7 +38,7 @@ string-benchset := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
 		   strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
 		   strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \
 		   strcoll memcpy-large memcpy-random memmove-large memset-large \
-		   memcpy-walk memset-walk
+		   memcpy-walk memset-walk memmove-walk
 
 # Build and run locale-dependent benchmarks only if we're building natively.
 ifeq (no,$(cross-compiling))
diff --git a/benchtests/bench-memmove-walk.c b/benchtests/bench-memmove-walk.c
new file mode 100644
index 0000000..54dcd64
--- /dev/null
+++ b/benchtests/bench-memmove-walk.c
@@ -0,0 +1,143 @@
+/* Measure memmove function combined throughput for different alignments.
+   Copyright (C) 2017 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
+   <http://www.gnu.org/licenses/>.  */
+
+/* This microbenchmark measures the throughput of memmove for various sizes from
+   1 byte to 32MiB, doubling every iteration and then misaligning by 0-15
+   bytes.  The copies are done from source to destination and then back and the
+   source walks forward across the array and the destination walks backward by
+   one byte each, thus measuring misaligned accesses as well.  The idea is to
+   avoid caching effects by copying a different string and far enough from each
+   other, walking in different directions so that we can measure prefetcher
+   efficiency (software or hardware) more closely than with a loop copying the
+   same data over and over, which eventually only gives us L1 cache
+   performance.  */
+
+#ifndef MEMMOVE_RESULT
+# define MEMMOVE_RESULT(dst, len) dst
+# define START_SIZE 1
+# define MIN_PAGE_SIZE (getpagesize () + 32 * 1024 * 1024)
+# define TEST_MAIN
+# define TEST_NAME "memmove"
+# define TIMEOUT (20 * 60)
+# include "bench-string.h"
+
+IMPL (memmove, 1)
+#endif
+
+#include "json-lib.h"
+
+typedef char *(*proto_t) (char *, const char *, size_t);
+
+static void
+do_one_test (json_ctx_t *json_ctx, impl_t *impl, char *dst, char *src,
+	     size_t len)
+{
+  size_t i, iters = MIN_PAGE_SIZE / len;
+  timing_t start, stop, cur;
+
+  char *dst_end = dst + MIN_PAGE_SIZE - len;
+  char *src_end = src + MIN_PAGE_SIZE - len;
+
+  TIMING_NOW (start);
+  /* Copy the entire buffer back and forth, LEN at a time.  */
+  for (i = 0; i < iters && dst_end >= dst && src <= src_end; src++, dst_end--)
+    {
+      CALL (impl, dst_end, src, len);
+      CALL (impl, src, dst_end, len);
+      i += 2;
+    }
+  TIMING_NOW (stop);
+
+  TIMING_DIFF (cur, start, stop);
+
+  /* Get time taken per function call.  */
+  json_element_double (json_ctx, (double) cur * len / i);
+}
+
+static void
+do_test (json_ctx_t *json_ctx, size_t len, bool overlap)
+{
+  json_element_object_begin (json_ctx);
+  json_attr_uint (json_ctx, "length", (double) len);
+  json_array_begin (json_ctx, "timings");
+
+  if (overlap)
+    buf2 = buf1;
+
+  /* First the non-overlapping moves.  */
+  FOR_EACH_IMPL (impl, 0)
+    do_one_test (json_ctx, impl, (char *) buf2, (char *) buf1, len);
+
+  json_array_end (json_ctx);
+  json_element_object_end (json_ctx);
+}
+
+int
+test_main (void)
+{
+  json_ctx_t json_ctx;
+  size_t i;
+
+  test_init ();
+
+  json_init (&json_ctx, 0, stdout);
+
+  json_document_begin (&json_ctx);
+  json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
+
+  json_attr_object_begin (&json_ctx, "functions");
+  json_attr_object_begin (&json_ctx, "memmove");
+  json_attr_string (&json_ctx, "bench-variant", "walk");
+
+  json_array_begin (&json_ctx, "ifuncs");
+  FOR_EACH_IMPL (impl, 0)
+    json_element_string (&json_ctx, impl->name);
+  json_array_end (&json_ctx);
+
+  json_array_begin (&json_ctx, "results");
+  /* Non-overlapping buffers.  */
+  for (i = START_SIZE; i <= MIN_PAGE_SIZE; i <<= 1)
+    {
+      /* Test length alignments from 0-16 bytes.  */
+      for (int j = 0; j < 8; j++)
+	{
+	  do_test (&json_ctx, i + j, false);
+	  do_test (&json_ctx, i + 16 - j, false);
+	}
+    }
+
+  /* Overlapping buffers.  */
+  for (i = START_SIZE; i <= MIN_PAGE_SIZE; i <<= 1)
+    {
+      /* Test length alignments from 0-16 bytes.  */
+      for (int j = 0; j < 8; j++)
+	{
+	  do_test (&json_ctx, i + j, true);
+	  do_test (&json_ctx, i + 16 - j, true);
+	}
+    }
+
+  json_array_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_document_end (&json_ctx);
+
+  return ret;
+}
+
+#include <support/test-driver.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=36bb8edf5178247933dfeee71812cda93587d32e

commit 36bb8edf5178247933dfeee71812cda93587d32e
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Thu Oct 5 21:51:41 2017 +0530

    benchtests: Memory walking benchmark for memset
    
    This benchmark is an attempt to eliminate cache effects from string
    benchmarks.  The benchmark walks backward through a large memory area
    and sets different sizes of memory and alignments one at a time
    instead of looping around in the same memory area.  This is a good
    metric to have alongside the simple memset benchmark (which is only
    really useful for smaller sizes) especially for larger sizes where the
    likelihood of the call being done only once is pretty high.
    
    	* benchtests/bench-memset-walk.c: New file.
    	* benchtests/Makefile (string-benchset): Add it.

diff --git a/ChangeLog b/ChangeLog
index a86faeb..5821c5d 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
 2017-10-05  Siddhesh Poyarekar  <siddhesh@sourceware.org>
 
+	* benchtests/bench-memset-walk.c: New file.
+	* benchtests/Makefile (string-benchset): Add it.
+
 	* benchtests/bench-memcpy-walk.c: New file.
 	* benchtests/Makefile (string-benchset): Add it.
 
diff --git a/benchtests/Makefile b/benchtests/Makefile
index d086cc6..5a07639 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -38,7 +38,7 @@ string-benchset := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
 		   strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
 		   strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \
 		   strcoll memcpy-large memcpy-random memmove-large memset-large \
-		   memcpy-walk
+		   memcpy-walk memset-walk
 
 # Build and run locale-dependent benchmarks only if we're building natively.
 ifeq (no,$(cross-compiling))
diff --git a/benchtests/bench-memset-walk.c b/benchtests/bench-memset-walk.c
new file mode 100644
index 0000000..59d2626
--- /dev/null
+++ b/benchtests/bench-memset-walk.c
@@ -0,0 +1,138 @@
+/* Measure memset function throughput with large data sizes.
+   Copyright (C) 2017 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
+   <http://www.gnu.org/licenses/>.  */
+
+#define TEST_MAIN
+#ifndef WIDE
+# define TEST_NAME "memset"
+#else
+# define TEST_NAME "wmemset"
+#endif /* WIDE */
+#define START_SIZE (1)
+#define MIN_PAGE_SIZE (getpagesize () + 32 * 1024 * 1024)
+#define TIMEOUT (20 * 60)
+#include "bench-string.h"
+
+#ifndef WIDE
+# define MEMSET memset
+# define CHAR char
+# define SIMPLE_MEMSET simple_memset
+# define MEMCMP memcmp
+#else
+# include <wchar.h>
+# define MEMSET wmemset
+# define CHAR wchar_t
+# define SIMPLE_MEMSET simple_wmemset
+# define MEMCMP wmemcmp
+#endif /* WIDE */
+
+#include <assert.h>
+#include "json-lib.h"
+
+
+typedef CHAR *(*proto_t) (CHAR *, int, size_t);
+
+CHAR *
+inhibit_loop_to_libcall
+SIMPLE_MEMSET (CHAR *s, int c, size_t n)
+{
+  CHAR *r = s, *end = s + n;
+  while (r < end)
+    *r++ = c;
+  return s;
+}
+
+IMPL (SIMPLE_MEMSET, 1)
+
+static void
+do_one_test (json_ctx_t *json_ctx, impl_t *impl, CHAR *s, CHAR *s_end,
+	     int c __attribute ((unused)), size_t n)
+{
+  size_t i, iters = MIN_PAGE_SIZE / n;
+  timing_t start, stop, cur;
+
+  TIMING_NOW (start);
+  for (i = 0; i < iters && s <= s_end; s++, i++)
+    CALL (impl, s, c, n);
+  TIMING_NOW (stop);
+
+  TIMING_DIFF (cur, start, stop);
+
+  /* Get time taken per function call.  */
+  json_element_double (json_ctx, (double) cur * n / i);
+}
+
+static void
+do_test (json_ctx_t *json_ctx, int c, size_t len)
+{
+  json_element_object_begin (json_ctx);
+  json_attr_uint (json_ctx, "length", len);
+  json_attr_uint (json_ctx, "char", c);
+  json_array_begin (json_ctx, "timings");
+
+  FOR_EACH_IMPL (impl, 0)
+    {
+      do_one_test (json_ctx, impl, (CHAR *) buf1,
+		   (CHAR *) buf1 + MIN_PAGE_SIZE - len, c, len);
+      realloc_bufs ();
+    }
+
+  json_array_end (json_ctx);
+  json_element_object_end (json_ctx);
+}
+
+int
+test_main (void)
+{
+  json_ctx_t json_ctx;
+  size_t i;
+
+  test_init ();
+
+  json_init (&json_ctx, 0, stdout);
+
+  json_document_begin (&json_ctx);
+  json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
+
+  json_attr_object_begin (&json_ctx, "functions");
+  json_attr_object_begin (&json_ctx, TEST_NAME);
+  json_attr_string (&json_ctx, "bench-variant", "walk");
+
+  json_array_begin (&json_ctx, "ifuncs");
+  FOR_EACH_IMPL (impl, 0)
+    json_element_string (&json_ctx, impl->name);
+  json_array_end (&json_ctx);
+
+  json_array_begin (&json_ctx, "results");
+  for (i = START_SIZE; i <= MIN_PAGE_SIZE; i <<= 1)
+      /* Test length alignments from 0-16 bytes.  */
+      for (int j = 0; j < i && j < 16; j++)
+	do_test (&json_ctx, 65, i + j);
+
+  for (i = START_SIZE; i <= MIN_PAGE_SIZE; i <<= 1)
+      for (int j = 0; j < i && j < 16; j++)
+	do_test (&json_ctx, 0, i + j);
+
+  json_array_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_document_end (&json_ctx);
+
+  return ret;
+}
+
+#include <support/test-driver.c>

http://sourceware.org/git/gitweb.cgi?p=glibc.git;a=commitdiff;h=9ec87fd2b11ffce5c27c8eacb9deaa20e2373ff5

commit 9ec87fd2b11ffce5c27c8eacb9deaa20e2373ff5
Author: Siddhesh Poyarekar <siddhesh@sourceware.org>
Date:   Thu Oct 5 21:49:37 2017 +0530

    benchtests: Memory walking benchmark for memcpy
    
    This benchmark is an attempt to eliminate cache effects from string
    benchmarks.  The benchmark walks both ways through a large memory area
    and copies different sizes of memory and alignments one at a time
    instead of looping around in the same memory area.  This is a good
    metric to have alongside the other memcpy benchmarks, especially for
    larger sizes where the likelihood of the call being done only once is
    pretty high.
    
    	* benchtests/bench-memcpy-walk.c: New file.
    	* benchtests/Makefile (string-benchset): Add it.

diff --git a/ChangeLog b/ChangeLog
index 7ddff74..a86faeb 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2017-10-05  Siddhesh Poyarekar  <siddhesh@sourceware.org>
+
+	* benchtests/bench-memcpy-walk.c: New file.
+	* benchtests/Makefile (string-benchset): Add it.
+
 2017-10-05  Florian Weimer  <fweimer@redhat.com>
 
 	nscd: Eliminate compilation time dependency in the build output.
diff --git a/benchtests/Makefile b/benchtests/Makefile
index 3acc39c..d086cc6 100644
--- a/benchtests/Makefile
+++ b/benchtests/Makefile
@@ -37,7 +37,8 @@ string-benchset := bcopy bzero memccpy memchr memcmp memcpy memmem memmove \
 		   strcat strchr strchrnul strcmp strcpy strcspn strlen \
 		   strncasecmp strncat strncmp strncpy strnlen strpbrk strrchr \
 		   strspn strstr strcpy_chk stpcpy_chk memrchr strsep strtok \
-		   strcoll memcpy-large memcpy-random memmove-large memset-large
+		   strcoll memcpy-large memcpy-random memmove-large memset-large \
+		   memcpy-walk
 
 # Build and run locale-dependent benchmarks only if we're building natively.
 ifeq (no,$(cross-compiling))
diff --git a/benchtests/bench-memcpy-walk.c b/benchtests/bench-memcpy-walk.c
new file mode 100644
index 0000000..69d467d
--- /dev/null
+++ b/benchtests/bench-memcpy-walk.c
@@ -0,0 +1,127 @@
+/* Measure memcpy function combined throughput for different alignments.
+   Copyright (C) 2017 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
+   <http://www.gnu.org/licenses/>.  */
+
+/* This microbenchmark measures the throughput of memcpy for various sizes from
+   1 byte to 32MiB, doubling every iteration and then misaligning by 0-15
+   bytes.  The copies are done from source to destination and then back and the
+   source walks forward across the array and the destination walks backward by
+   one byte each, thus measuring misaligned accesses as well.  The idea is to
+   avoid caching effects by copying a different string and far enough from each
+   other, walking in different directions so that we can measure prefetcher
+   efficiency (software or hardware) more closely than with a loop copying the
+   same data over and over, which eventually only gives us L1 cache
+   performance.  */
+
+#ifndef MEMCPY_RESULT
+# define MEMCPY_RESULT(dst, len) dst
+# define START_SIZE 1
+# define MIN_PAGE_SIZE (getpagesize () + 32 * 1024 * 1024)
+# define TEST_MAIN
+# define TEST_NAME "memcpy"
+# define TIMEOUT (20 * 60)
+# include "bench-string.h"
+
+IMPL (memcpy, 1)
+#endif
+
+#include "json-lib.h"
+
+typedef char *(*proto_t) (char *, const char *, size_t);
+
+static void
+do_one_test (json_ctx_t *json_ctx, impl_t *impl, char *dst, char *src,
+	     size_t len)
+{
+  size_t i, iters = MIN_PAGE_SIZE / len;
+  timing_t start, stop, cur;
+
+  char *dst_end = dst + MIN_PAGE_SIZE - len;
+  char *src_end = src + MIN_PAGE_SIZE - len;
+
+  TIMING_NOW (start);
+  /* Copy the entire buffer back and forth, LEN at a time.  */
+  for (i = 0; i < iters && dst_end >= dst && src <= src_end; src++, dst_end--)
+    {
+      CALL (impl, dst_end, src, len);
+      CALL (impl, src, dst_end, len);
+      i += 2;
+    }
+  TIMING_NOW (stop);
+
+  TIMING_DIFF (cur, start, stop);
+
+  /* Get time taken per function call.  */
+  json_element_double (json_ctx, (double) cur * len / i);
+}
+
+static void
+do_test (json_ctx_t *json_ctx, size_t len)
+{
+  json_element_object_begin (json_ctx);
+  json_attr_uint (json_ctx, "length", (double) len);
+  json_array_begin (json_ctx, "timings");
+
+  FOR_EACH_IMPL (impl, 0)
+    do_one_test (json_ctx, impl, (char *) buf2, (char *) buf1, len);
+
+  json_array_end (json_ctx);
+  json_element_object_end (json_ctx);
+}
+
+int
+test_main (void)
+{
+  json_ctx_t json_ctx;
+  size_t i;
+
+  test_init ();
+
+  json_init (&json_ctx, 0, stdout);
+
+  json_document_begin (&json_ctx);
+  json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
+
+  json_attr_object_begin (&json_ctx, "functions");
+  json_attr_object_begin (&json_ctx, "memcpy");
+  json_attr_string (&json_ctx, "bench-variant", "walk");
+
+  json_array_begin (&json_ctx, "ifuncs");
+  FOR_EACH_IMPL (impl, 0)
+    json_element_string (&json_ctx, impl->name);
+  json_array_end (&json_ctx);
+
+  json_array_begin (&json_ctx, "results");
+  for (i = START_SIZE; i <= MIN_PAGE_SIZE; i <<= 1)
+    {
+      /* Test length alignments from 0-16 bytes.  */
+      for (int j = 0; j < 8; j++)
+	{
+	  do_test (&json_ctx, i + j);
+	  do_test (&json_ctx, i + 16 - j);
+	}
+    }
+
+  json_array_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_attr_object_end (&json_ctx);
+  json_document_end (&json_ctx);
+
+  return ret;
+}
+
+#include <support/test-driver.c>

-----------------------------------------------------------------------

Summary of changes:
 ChangeLog                                   |   18 ++
 benchtests/Makefile                         |    3 +-
 benchtests/bench-memcpy-walk.c              |  127 +++++++++++++++
 benchtests/bench-memmove-walk.c             |  143 ++++++++++++++++
 benchtests/bench-memset-walk.c              |  138 ++++++++++++++++
 sysdeps/aarch64/multiarch/Makefile          |    3 +-
 sysdeps/aarch64/multiarch/ifunc-impl-list.c |    1 +
 sysdeps/aarch64/multiarch/memmove.c         |    7 +-
 sysdeps/aarch64/multiarch/memmove_falkor.S  |  232 +++++++++++++++++++++++++++
 9 files changed, 669 insertions(+), 3 deletions(-)
 create mode 100644 benchtests/bench-memcpy-walk.c
 create mode 100644 benchtests/bench-memmove-walk.c
 create mode 100644 benchtests/bench-memset-walk.c
 create mode 100644 sysdeps/aarch64/multiarch/memmove_falkor.S


hooks/post-receive
-- 
GNU C Library master sources


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]