Need a way to test ifunc functions
H.J. Lu
hjl.tools@gmail.com
Thu Nov 11 02:58:00 GMT 2010
On Wed, Nov 10, 2010 at 1:11 PM, Ulrich Drepper <drepper@gmail.com> wrote:
> On Wed, Nov 10, 2010 at 12:29, H.J. Lu <hjl.tools@gmail.com> wrote:
>> With IFUNC functions, glibc testsuite can only test one implementation.
>> We need a way to test SSE2/SSSE3/SSE4 implementations on SSE4
>> machines.
>
> You do unit testing. Link the test app against the .o/.os file and
> call the function y its real name (__strcmp_sse4 etc).
>
It has to be done by hand whenever the change is made.
Here is a prove of concept to test multiple copy of memcpy.
--
H.J.
-------------- next part --------------
diff --git a/debug/test-stpcpy_chk.c b/debug/test-stpcpy_chk.c
index d717ca7..1f8f588 100644
--- a/debug/test-stpcpy_chk.c
+++ b/debug/test-stpcpy_chk.c
@@ -20,6 +20,7 @@
#define STRCPY_RESULT(dst, len) ((dst) + (len))
#define TEST_MAIN
+#define TEST_NAME "stpcpy_chk"
#include "../string/test-string.h"
extern void __attribute__ ((noreturn)) __chk_fail (void);
diff --git a/debug/test-strcpy_chk.c b/debug/test-strcpy_chk.c
index e08141d..05bd0cb 100644
--- a/debug/test-strcpy_chk.c
+++ b/debug/test-strcpy_chk.c
@@ -21,6 +21,7 @@
#ifndef STRCPY_RESULT
# define STRCPY_RESULT(dst, len) dst
# define TEST_MAIN
+# define TEST_NAME "strcpy_chk"
# include "../string/test-string.h"
extern void __attribute__ ((noreturn)) __chk_fail (void);
diff --git a/include/libc-test.h b/include/libc-test.h
new file mode 100644
index 0000000..edd814f
--- /dev/null
+++ b/include/libc-test.h
@@ -0,0 +1,33 @@
+/* Copyright (C) 2010 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#ifndef _LIBC_TEST_H
+#define _LIBC_TEST_H 1
+
+struct libc_func_test
+{
+ /* The name of function to be tested. */
+ const char *name;
+ /* The address of function to be tested. */
+ void (*fn) (void);
+};
+
+/* Return the NULL terminated array of functions. */
+extern const struct libc_func_test *__libc_func (const char *);
+
+#endif /* libc-symbols.h */
diff --git a/string/Makefile b/string/Makefile
index f836f59..d25d23d 100644
--- a/string/Makefile
+++ b/string/Makefile
@@ -40,7 +40,7 @@ routines := strcat strchr strcmp strcoll strcpy strcspn \
addsep replace) \
envz basename \
strcoll_l strxfrm_l string-inlines memrchr \
- xpg-strerror strerror_l
+ xpg-strerror strerror_l libc-test
# Gcc internally generates calls to unbounded memcpy and memset
# for -fbounded-pointer compiles. Glibc uses memchr for explicit checks.
diff --git a/string/Versions b/string/Versions
index f145fd3..fe6a418 100644
--- a/string/Versions
+++ b/string/Versions
@@ -80,4 +80,7 @@ libc {
GLIBC_2.6 {
strerror_l;
}
+ GLIBC_2.13 {
+ __libc_func;
+ }
}
diff --git a/string/test-memccpy.c b/string/test-memccpy.c
index 2653263..c5676cf 100644
--- a/string/test-memccpy.c
+++ b/string/test-memccpy.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memccpy"
#include "test-string.h"
void *simple_memccpy (void *, const void *, int, size_t);
diff --git a/string/test-memchr.c b/string/test-memchr.c
index cd9a01e..ab510ef 100644
--- a/string/test-memchr.c
+++ b/string/test-memchr.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memchr"
#include "test-string.h"
typedef char *(*proto_t) (const char *, int, size_t);
diff --git a/string/test-memcmp.c b/string/test-memcmp.c
index 3040e21..4fbfa54 100644
--- a/string/test-memcmp.c
+++ b/string/test-memcmp.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memcmp"
#include "test-string.h"
typedef int (*proto_t) (const char *, const char *, size_t);
diff --git a/string/test-memcpy.c b/string/test-memcpy.c
index 7b0723a..5b5c657 100644
--- a/string/test-memcpy.c
+++ b/string/test-memcpy.c
@@ -22,6 +22,7 @@
# define MEMCPY_RESULT(dst, len) dst
# define MIN_PAGE_SIZE 131072
# define TEST_MAIN
+# define TEST_NAME "memcpy"
# include "test-string.h"
char *simple_memcpy (char *, const char *, size_t);
diff --git a/string/test-memmem.c b/string/test-memmem.c
index 91b661b..4402623 100644
--- a/string/test-memmem.c
+++ b/string/test-memmem.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memmem"
#define BUF1PAGES 20
#define ITERATIONS 500
#include "test-string.h"
diff --git a/string/test-memmove.c b/string/test-memmove.c
index 2f3a8f7..cf3fa1e 100644
--- a/string/test-memmove.c
+++ b/string/test-memmove.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memmove"
#include "test-string.h"
typedef char *(*proto_t) (char *, const char *, size_t);
diff --git a/string/test-mempcpy.c b/string/test-mempcpy.c
index f8b0267..9bf2e86 100644
--- a/string/test-mempcpy.c
+++ b/string/test-mempcpy.c
@@ -20,6 +20,7 @@
#define MEMCPY_RESULT(dst, len) (dst) + (len)
#define TEST_MAIN
+#define TEST_NAME "mempcpy"
#include "test-string.h"
char *simple_mempcpy (char *, const char *, size_t);
diff --git a/string/test-memset.c b/string/test-memset.c
index 601ace4..cdc51d0 100644
--- a/string/test-memset.c
+++ b/string/test-memset.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "memset"
#define MIN_PAGE_SIZE 131072
#include "test-string.h"
diff --git a/string/test-stpcpy.c b/string/test-stpcpy.c
index c8d4cc4..0582aaa 100644
--- a/string/test-stpcpy.c
+++ b/string/test-stpcpy.c
@@ -20,6 +20,7 @@
#define STRCPY_RESULT(dst, len) ((dst) + (len))
#define TEST_MAIN
+#define TEST_NAME "stpcpy"
#include "test-string.h"
char *simple_stpcpy (char *, const char *);
diff --git a/string/test-stpncpy.c b/string/test-stpncpy.c
index 8784588..115cf79 100644
--- a/string/test-stpncpy.c
+++ b/string/test-stpncpy.c
@@ -20,6 +20,7 @@
#define STRNCPY_RESULT(dst, len, n) ((dst) + ((len) > (n) ? (n) : (len)))
#define TEST_MAIN
+#define TEST_NAME "stpncpy"
#include "test-string.h"
char *simple_stpncpy (char *, const char *, size_t);
diff --git a/string/test-strcasecmp.c b/string/test-strcasecmp.c
index 7d1d110..261af13 100644
--- a/string/test-strcasecmp.c
+++ b/string/test-strcasecmp.c
@@ -20,6 +20,7 @@
#include <ctype.h>
#define TEST_MAIN
+#define TEST_NAME "strcasecmp"
#include "test-string.h"
typedef int (*proto_t) (const char *, const char *);
diff --git a/string/test-strcasestr.c b/string/test-strcasestr.c
index edc41f3..9981c23 100644
--- a/string/test-strcasestr.c
+++ b/string/test-strcasestr.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strcasestr"
#include "test-string.h"
diff --git a/string/test-strcat.c b/string/test-strcat.c
index 4437520..83b133a 100644
--- a/string/test-strcat.c
+++ b/string/test-strcat.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strcat"
#include "test-string.h"
typedef char *(*proto_t) (char *, const char *);
diff --git a/string/test-strchr.c b/string/test-strchr.c
index cf25b44..200327c 100644
--- a/string/test-strchr.c
+++ b/string/test-strchr.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strchr"
#include "test-string.h"
typedef char *(*proto_t) (const char *, int);
diff --git a/string/test-strcmp.c b/string/test-strcmp.c
index 769e982..71242e3 100644
--- a/string/test-strcmp.c
+++ b/string/test-strcmp.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strcmp"
#include "test-string.h"
typedef int (*proto_t) (const char *, const char *);
diff --git a/string/test-strcpy.c b/string/test-strcpy.c
index 6a2ea25..7a4e3be 100644
--- a/string/test-strcpy.c
+++ b/string/test-strcpy.c
@@ -21,6 +21,7 @@
#ifndef STRCPY_RESULT
# define STRCPY_RESULT(dst, len) dst
# define TEST_MAIN
+# define TEST_NAME "strcpy"
# include "test-string.h"
char *simple_strcpy (char *, const char *);
diff --git a/string/test-strcspn.c b/string/test-strcspn.c
index b563179..403a2fd 100644
--- a/string/test-strcspn.c
+++ b/string/test-strcspn.c
@@ -21,6 +21,7 @@
#define STRPBRK_RESULT(s, pos) (pos)
#define RES_TYPE size_t
#define TEST_MAIN
+#define TEST_NAME "strcspn"
#include "test-string.h"
typedef size_t (*proto_t) (const char *, const char *);
diff --git a/string/test-string.h b/string/test-string.h
index 1aea4c9..db7d02e 100644
--- a/string/test-string.h
+++ b/string/test-string.h
@@ -48,6 +48,7 @@ extern impl_t __start_impls[], __stop_impls[];
#include <error.h>
#include <errno.h>
#include <time.h>
+#include <libc-test.h>
#define GL(x) _##x
#define GLRO(x) _##x
#include <hp-timing.h>
@@ -105,7 +106,32 @@ size_t iterations = 100000;
(* (proto_t) (impl)->fn) (__VA_ARGS__)
#define FOR_EACH_IMPL(impl, notall) \
- for (impl_t *impl = __start_impls; impl < __stop_impls; ++impl) \
+ impl_t *impl; \
+ int count; \
+ if (impl_count == -1) \
+ { \
+ const struct libc_func_test *p; \
+ impl_count = 0; \
+ for (impl = __start_impls; impl < __stop_impls; ++impl) \
+ impl_count++; \
+ for (p = func_list; p && p->name; ++p) \
+ impl_count++; \
+ if (impl_count) \
+ { \
+ impl_t *a; \
+ a = impl_array = malloc (impl_count * sizeof (impl_t)); \
+ for (impl = __start_impls; impl < __stop_impls; ++impl, ++a) \
+ *a = *impl; \
+ for (p = func_list; p && p->name; ++p, a++) \
+ { \
+ a->name = p->name; \
+ a->fn = p->fn; \
+ a->test = 1; \
+ } \
+ } \
+ } \
+ impl = impl_array; \
+ for (count = 0; count < impl_count; ++count, ++impl) \
if (!notall || impl->test)
#define HP_TIMING_BEST(best_time, start, end) \
@@ -122,9 +148,15 @@ size_t iterations = 100000;
# define BUF1PAGES 1
#endif
+static const struct libc_func_test *func_list;
+static int impl_count = -1;
+static impl_t *impl_array;
+
static void
test_init (void)
{
+ func_list = __libc_func (TEST_NAME);
+
page_size = 2 * getpagesize ();
#ifdef MIN_PAGE_SIZE
if (page_size < MIN_PAGE_SIZE)
diff --git a/string/test-strlen.c b/string/test-strlen.c
index e01befb..feb1c5d 100644
--- a/string/test-strlen.c
+++ b/string/test-strlen.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strlen"
#include "test-string.h"
typedef size_t (*proto_t) (const char *);
diff --git a/string/test-strncasecmp.c b/string/test-strncasecmp.c
index daff6ed..9ec8955 100644
--- a/string/test-strncasecmp.c
+++ b/string/test-strncasecmp.c
@@ -20,6 +20,7 @@
#include <ctype.h>
#define TEST_MAIN
+#define TEST_NAME "strncasecmp"
#include "test-string.h"
typedef int (*proto_t) (const char *, const char *, size_t);
diff --git a/string/test-strncmp.c b/string/test-strncmp.c
index 3687879..891acb0 100644
--- a/string/test-strncmp.c
+++ b/string/test-strncmp.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strncmp"
#include "test-string.h"
typedef int (*proto_t) (const char *, const char *, size_t);
diff --git a/string/test-strncpy.c b/string/test-strncpy.c
index d7a714c..f89b27d 100644
--- a/string/test-strncpy.c
+++ b/string/test-strncpy.c
@@ -21,6 +21,7 @@
#ifndef STRNCPY_RESULT
# define STRNCPY_RESULT(dst, len, n) dst
# define TEST_MAIN
+# define TEST_NAME "strncpy"
# include "test-string.h"
char *simple_strncpy (char *, const char *, size_t);
diff --git a/string/test-strnlen.c b/string/test-strnlen.c
index cb8c80f..d078729 100644
--- a/string/test-strnlen.c
+++ b/string/test-strnlen.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strnlen"
#include "test-string.h"
typedef size_t (*proto_t) (const char *, size_t);
diff --git a/string/test-strpbrk.c b/string/test-strpbrk.c
index f3ed208..76ac8c7 100644
--- a/string/test-strpbrk.c
+++ b/string/test-strpbrk.c
@@ -22,6 +22,7 @@
# define STRPBRK_RESULT(s, pos) ((s)[(pos)] ? (s) + (pos) : NULL)
# define RES_TYPE char *
# define TEST_MAIN
+# define TEST_NAME "strpbrk"
# include "test-string.h"
typedef char *(*proto_t) (const char *, const char *);
diff --git a/string/test-strrchr.c b/string/test-strrchr.c
index 92e8ab1..64af621 100644
--- a/string/test-strrchr.c
+++ b/string/test-strrchr.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strrchr"
#include "test-string.h"
typedef char *(*proto_t) (const char *, int);
diff --git a/string/test-strspn.c b/string/test-strspn.c
index 15cf492..ad7b845 100644
--- a/string/test-strspn.c
+++ b/string/test-strspn.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strspn"
#include "test-string.h"
typedef size_t (*proto_t) (const char *, const char *);
diff --git a/string/test-strstr.c b/string/test-strstr.c
index c1da686..6116d70 100644
--- a/string/test-strstr.c
+++ b/string/test-strstr.c
@@ -19,6 +19,7 @@
02111-1307 USA. */
#define TEST_MAIN
+#define TEST_NAME "strstr"
#include "test-string.h"
diff --git a/sysdeps/generic/libc-test.c b/sysdeps/generic/libc-test.c
new file mode 100644
index 0000000..672e1e4
--- /dev/null
+++ b/sysdeps/generic/libc-test.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2010 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdlib.h>
+#include <libc-test.h>
+
+/* Return the NULL terminated array of functions. */
+
+const struct libc_func_test *
+__libc_func (const char *name __attribute__ ((unused)))
+{
+ return NULL;
+}
diff --git a/sysdeps/x86_64/multiarch/libc-test.c b/sysdeps/x86_64/multiarch/libc-test.c
new file mode 100644
index 0000000..5975e0b
--- /dev/null
+++ b/sysdeps/x86_64/multiarch/libc-test.c
@@ -0,0 +1,57 @@
+/* Copyright (C) 2010 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, write to the Free
+ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+ 02111-1307 USA. */
+
+#include <stdlib.h>
+#include <string.h>
+#include <libc-test.h>
+#include "init-arch.h"
+
+#if defined SHARED && !defined NOT_IN_libc
+extern void *__memcpy_sse2 (void *, const void *, size_t);
+extern void *__memcpy_ssse3 (void *, const void *, size_t);
+extern void *__memcpy_ssse3_back (void *, const void *, size_t);
+
+static const struct libc_func_test memcpy_list [] =
+{
+ { "__memcpy_ssse3_back", (void (*) (void)) __memcpy_ssse3_back },
+ { "__memcpy_ssse3", (void (*) (void)) __memcpy_ssse3 },
+ { "__memcpy_sse2", (void (*) (void)) __memcpy_sse2 },
+ { NULL, NULL },
+};
+
+static const struct libc_func_test *
+find_memcpy (void)
+{
+ return memcpy_list + (HAS_SSSE3 ? 0 : 2);
+}
+#else
+static const struct libc_func_test *
+find_memcpy (void)
+{
+ return NULL;
+}
+#endif
+
+const struct libc_func_test *
+__libc_func (const char *name)
+{
+ if (strcmp (name, "memcpy") == 0)
+ return find_memcpy ();
+
+ return NULL;
+}
diff --git a/sysdeps/x86_64/multiarch/memcpy.S b/sysdeps/x86_64/multiarch/memcpy.S
index 8e9fb19..a45ca9f 100644
--- a/sysdeps/x86_64/multiarch/memcpy.S
+++ b/sysdeps/x86_64/multiarch/memcpy.S
@@ -44,6 +44,8 @@ END(memcpy)
# undef ENTRY
# define ENTRY(name) \
.type __memcpy_sse2, @function; \
+ .globl __memcpy_sse2; \
+ .hidden __memcpy_sse2; \
.p2align 4; \
__memcpy_sse2: cfi_startproc; \
CALL_MCOUNT
More information about the Libc-alpha
mailing list