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