2013-04-16 20:07:24 +08:00
|
|
|
/* Measure string and memory functions.
|
2020-01-01 08:14:33 +08:00
|
|
|
Copyright (C) 2013-2020 Free Software Foundation, Inc.
|
2013-04-16 20:07:24 +08:00
|
|
|
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
|
Prefer https to http for gnu.org and fsf.org URLs
Also, change sources.redhat.com to sourceware.org.
This patch was automatically generated by running the following shell
script, which uses GNU sed, and which avoids modifying files imported
from upstream:
sed -ri '
s,(http|ftp)(://(.*\.)?(gnu|fsf|sourceware)\.org($|[^.]|\.[^a-z])),https\2,g
s,(http|ftp)(://(.*\.)?)sources\.redhat\.com($|[^.]|\.[^a-z]),https\2sourceware.org\4,g
' \
$(find $(git ls-files) -prune -type f \
! -name '*.po' \
! -name 'ChangeLog*' \
! -path COPYING ! -path COPYING.LIB \
! -path manual/fdl-1.3.texi ! -path manual/lgpl-2.1.texi \
! -path manual/texinfo.tex ! -path scripts/config.guess \
! -path scripts/config.sub ! -path scripts/install-sh \
! -path scripts/mkinstalldirs ! -path scripts/move-if-change \
! -path INSTALL ! -path locale/programs/charmap-kw.h \
! -path po/libc.pot ! -path sysdeps/gnu/errlist.c \
! '(' -name configure \
-execdir test -f configure.ac -o -f configure.in ';' ')' \
! '(' -name preconfigure \
-execdir test -f preconfigure.ac ';' ')' \
-print)
and then by running 'make dist-prepare' to regenerate files built
from the altered files, and then executing the following to cleanup:
chmod a+x sysdeps/unix/sysv/linux/riscv/configure
# Omit irrelevant whitespace and comment-only changes,
# perhaps from a slightly-different Autoconf version.
git checkout -f \
sysdeps/csky/configure \
sysdeps/hppa/configure \
sysdeps/riscv/configure \
sysdeps/unix/sysv/linux/csky/configure
# Omit changes that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/powerpc/powerpc64/ppc-mcount.S: trailing lines
git checkout -f \
sysdeps/powerpc/powerpc64/ppc-mcount.S \
sysdeps/unix/sysv/linux/s390/s390-64/syscall.S
# Omit change that caused a pre-commit check to fail like this:
# remote: *** error: sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S: last line does not end in newline
git checkout -f sysdeps/sparc/sparc64/multiarch/memcpy-ultra3.S
2019-09-07 13:40:42 +08:00
|
|
|
<https://www.gnu.org/licenses/>. */
|
2013-04-16 20:07:24 +08:00
|
|
|
|
2016-12-17 01:35:06 +08:00
|
|
|
#include <getopt.h>
|
2013-04-16 20:07:24 +08:00
|
|
|
#include <sys/cdefs.h>
|
|
|
|
|
2018-03-15 23:44:58 +08:00
|
|
|
/* We are compiled under _ISOMAC, so libc-symbols.h does not do this
|
|
|
|
for us. */
|
|
|
|
#include "config.h"
|
|
|
|
#ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL
|
|
|
|
# define inhibit_loop_to_libcall \
|
|
|
|
__attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
|
|
|
|
#else
|
|
|
|
# define inhibit_loop_to_libcall
|
|
|
|
#endif
|
|
|
|
|
2013-04-16 20:07:24 +08:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
void (*fn) (void);
|
|
|
|
long test;
|
|
|
|
} impl_t;
|
|
|
|
extern impl_t __start_impls[], __stop_impls[];
|
|
|
|
|
|
|
|
#define IMPL(name, test) \
|
|
|
|
impl_t tst_ ## name \
|
|
|
|
__attribute__ ((section ("impls"), aligned (sizeof (void *)))) \
|
|
|
|
= { __STRING (name), (void (*) (void))name, test };
|
|
|
|
|
|
|
|
#ifdef TEST_MAIN
|
|
|
|
|
|
|
|
# ifndef _GNU_SOURCE
|
|
|
|
# define _GNU_SOURCE
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# undef __USE_STRING_INLINES
|
|
|
|
|
|
|
|
# include <stdio.h>
|
|
|
|
# include <stdlib.h>
|
|
|
|
# include <string.h>
|
|
|
|
# include <sys/mman.h>
|
|
|
|
# include <sys/param.h>
|
|
|
|
# include <unistd.h>
|
|
|
|
# include <fcntl.h>
|
|
|
|
# include <error.h>
|
|
|
|
# include <errno.h>
|
|
|
|
# include <time.h>
|
|
|
|
# include <ifunc-impl-list.h>
|
|
|
|
# define GL(x) _##x
|
|
|
|
# define GLRO(x) _##x
|
2013-09-02 21:13:50 +08:00
|
|
|
# include "bench-timing.h"
|
2013-04-16 20:07:24 +08:00
|
|
|
|
2018-12-22 02:52:40 +08:00
|
|
|
# ifndef WIDE
|
|
|
|
# define CHAR char
|
|
|
|
# define UCHAR unsigned char
|
|
|
|
# define CHARBYTES 1
|
|
|
|
# define MAX_CHAR CHAR_MAX
|
|
|
|
# define MEMCHR memchr
|
|
|
|
# define MEMCMP memcmp
|
|
|
|
# define MEMCPY memcpy
|
|
|
|
# define MEMSET memset
|
|
|
|
# define STRCAT strcat
|
|
|
|
# define STRLEN strlen
|
|
|
|
# define STRCMP strcmp
|
|
|
|
# define STRCHR strchr
|
|
|
|
# define STRCPY strcpy
|
|
|
|
# define STRNLEN strnlen
|
|
|
|
# define STRCSPN strcspn
|
|
|
|
# define STRNCAT strncat
|
|
|
|
# define STRNCMP strncmp
|
|
|
|
# define STRNCPY strncpy
|
|
|
|
# define STRPBRK strpbrk
|
|
|
|
# define STRRCHR strrchr
|
|
|
|
# define STRSPN strspn
|
|
|
|
# define STPCPY stpcpy
|
|
|
|
# define STPNCPY stpncpy
|
|
|
|
# else
|
|
|
|
# include <wchar.h>
|
|
|
|
# define CHAR wchar_t
|
|
|
|
# define UCHAR wchar_t
|
|
|
|
# define CHARBYTES 4
|
|
|
|
# define MAX_CHAR WCHAR_MAX
|
|
|
|
# define MEMCHR wmemchr
|
|
|
|
# define MEMCMP wmemcmp
|
|
|
|
# define MEMCPY wmemcpy
|
|
|
|
# define MEMSET wmemset
|
|
|
|
# define STRCAT wcscat
|
|
|
|
# define STRLEN wcslen
|
|
|
|
# define STRCMP wcscmp
|
|
|
|
# define STRCHR wcschr
|
|
|
|
# define STRCPY wcscpy
|
|
|
|
# define STRNLEN wcsnlen
|
|
|
|
# define STRCSPN wcscspn
|
|
|
|
# define STRNCAT wcsncat
|
|
|
|
# define STRNCMP wcsncmp
|
|
|
|
# define STRNCPY wcsncpy
|
|
|
|
# define STRPBRK wcspbrk
|
|
|
|
# define STRRCHR wcsrchr
|
|
|
|
# define STRSPN wcsspn
|
|
|
|
# define STPCPY wcpcpy
|
|
|
|
# define STPNCPY wcpncpy
|
|
|
|
# endif /* WIDE */
|
2013-04-16 20:07:24 +08:00
|
|
|
|
2016-12-17 01:35:06 +08:00
|
|
|
# define TEST_FUNCTION test_main
|
2016-04-06 23:37:20 +08:00
|
|
|
# ifndef TIMEOUT
|
|
|
|
# define TIMEOUT (4 * 60)
|
|
|
|
# endif
|
2013-04-16 20:07:24 +08:00
|
|
|
# define OPT_ITERATIONS 10000
|
|
|
|
# define OPT_RANDOM 10001
|
|
|
|
# define OPT_SEED 10002
|
|
|
|
|
2019-05-21 22:19:06 +08:00
|
|
|
# define INNER_LOOP_ITERS 8192
|
2019-06-28 20:42:36 +08:00
|
|
|
# define INNER_LOOP_ITERS8 32768
|
2019-06-28 20:38:07 +08:00
|
|
|
# define INNER_LOOP_ITERS_LARGE 131072
|
2019-06-28 20:42:36 +08:00
|
|
|
# define INNER_LOOP_ITERS_MEDIUM 2048
|
|
|
|
# define INNER_LOOP_ITERS_SMALL 256
|
2013-09-02 21:13:50 +08:00
|
|
|
|
2013-04-16 20:07:24 +08:00
|
|
|
int ret, do_srandom;
|
|
|
|
unsigned int seed;
|
|
|
|
|
|
|
|
# ifndef ITERATIONS
|
|
|
|
size_t iterations = 100000;
|
|
|
|
# define ITERATIONS_OPTIONS \
|
|
|
|
{ "iterations", required_argument, NULL, OPT_ITERATIONS },
|
|
|
|
# define ITERATIONS_PROCESS \
|
|
|
|
case OPT_ITERATIONS: \
|
|
|
|
iterations = strtoul (optarg, NULL, 0); \
|
|
|
|
break;
|
|
|
|
# define ITERATIONS iterations
|
|
|
|
# else
|
|
|
|
# define ITERATIONS_OPTIONS
|
|
|
|
# define ITERATIONS_PROCESS
|
|
|
|
# endif
|
|
|
|
|
|
|
|
# define CMDLINE_OPTIONS ITERATIONS_OPTIONS \
|
|
|
|
{ "random", no_argument, NULL, OPT_RANDOM }, \
|
|
|
|
{ "seed", required_argument, NULL, OPT_SEED },
|
|
|
|
|
2016-12-17 01:35:06 +08:00
|
|
|
static void __attribute__ ((used))
|
|
|
|
cmdline_process_function (int c)
|
|
|
|
{
|
|
|
|
switch (c)
|
|
|
|
{
|
|
|
|
ITERATIONS_PROCESS
|
|
|
|
case OPT_RANDOM:
|
|
|
|
{
|
|
|
|
int fdr = open ("/dev/urandom", O_RDONLY);
|
2019-02-27 21:55:45 +08:00
|
|
|
if (fdr < 0 || read (fdr, &seed, sizeof (seed)) != sizeof (seed))
|
2016-12-17 01:35:06 +08:00
|
|
|
seed = time (NULL);
|
|
|
|
if (fdr >= 0)
|
|
|
|
close (fdr);
|
|
|
|
do_srandom = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case OPT_SEED:
|
|
|
|
seed = strtoul (optarg, NULL, 0);
|
|
|
|
do_srandom = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
# define CMDLINE_PROCESS cmdline_process_function
|
2013-04-16 20:07:24 +08:00
|
|
|
# define CALL(impl, ...) \
|
|
|
|
(* (proto_t) (impl)->fn) (__VA_ARGS__)
|
|
|
|
|
2014-11-26 20:53:36 +08:00
|
|
|
# ifdef TEST_NAME
|
2013-04-16 20:07:24 +08:00
|
|
|
/* Increase size of FUNC_LIST if assert is triggered at run-time. */
|
|
|
|
static struct libc_ifunc_impl func_list[32];
|
|
|
|
static int func_count;
|
|
|
|
static int impl_count = -1;
|
|
|
|
static impl_t *impl_array;
|
|
|
|
|
|
|
|
# define FOR_EACH_IMPL(impl, notall) \
|
|
|
|
impl_t *impl; \
|
|
|
|
int count; \
|
|
|
|
if (impl_count == -1) \
|
|
|
|
{ \
|
|
|
|
impl_count = 0; \
|
|
|
|
if (func_count != 0) \
|
|
|
|
{ \
|
|
|
|
int f; \
|
|
|
|
impl_t *skip = NULL, *a; \
|
|
|
|
for (impl = __start_impls; impl < __stop_impls; ++impl) \
|
|
|
|
if (strcmp (impl->name, TEST_NAME) == 0) \
|
|
|
|
skip = impl; \
|
|
|
|
else \
|
|
|
|
impl_count++; \
|
|
|
|
a = impl_array = malloc ((impl_count + func_count) * \
|
|
|
|
sizeof (impl_t)); \
|
|
|
|
for (impl = __start_impls; impl < __stop_impls; ++impl) \
|
|
|
|
if (impl != skip) \
|
|
|
|
*a++ = *impl; \
|
|
|
|
for (f = 0; f < func_count; f++) \
|
|
|
|
if (func_list[f].usable) \
|
|
|
|
{ \
|
|
|
|
a->name = func_list[f].name; \
|
|
|
|
a->fn = func_list[f].fn; \
|
|
|
|
a->test = 1; \
|
|
|
|
a++; \
|
|
|
|
} \
|
|
|
|
impl_count = a - impl_array; \
|
|
|
|
} \
|
|
|
|
else \
|
|
|
|
{ \
|
|
|
|
impl_count = __stop_impls - __start_impls; \
|
|
|
|
impl_array = __start_impls; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
impl = impl_array; \
|
|
|
|
for (count = 0; count < impl_count; ++count, ++impl) \
|
|
|
|
if (!notall || impl->test)
|
2014-11-26 20:53:36 +08:00
|
|
|
# else /* !TEST_NAME */
|
2013-04-16 20:07:24 +08:00
|
|
|
# define FOR_EACH_IMPL(impl, notall) \
|
|
|
|
for (impl_t *impl = __start_impls; impl < __stop_impls; ++impl) \
|
|
|
|
if (!notall || impl->test)
|
2014-11-26 20:53:36 +08:00
|
|
|
# endif /* !TEST_NAME */
|
2013-04-16 20:07:24 +08:00
|
|
|
|
|
|
|
# ifndef BUF1PAGES
|
|
|
|
# define BUF1PAGES 1
|
|
|
|
# endif
|
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
unsigned char *buf1, *buf2;
|
|
|
|
static size_t buf1_size, buf2_size, page_size;
|
|
|
|
|
2013-04-16 20:07:24 +08:00
|
|
|
static void
|
2018-08-08 03:14:56 +08:00
|
|
|
init_sizes (void)
|
2013-04-16 20:07:24 +08:00
|
|
|
{
|
|
|
|
page_size = 2 * getpagesize ();
|
|
|
|
# ifdef MIN_PAGE_SIZE
|
|
|
|
if (page_size < MIN_PAGE_SIZE)
|
|
|
|
page_size = MIN_PAGE_SIZE;
|
|
|
|
# endif
|
2018-08-08 03:14:56 +08:00
|
|
|
|
|
|
|
buf1_size = BUF1PAGES * page_size;
|
|
|
|
buf2_size = page_size;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
exit_error (const char *id, const char *func)
|
|
|
|
{
|
|
|
|
error (EXIT_FAILURE, errno, "%s: %s failed", id, func);
|
2017-09-15 01:09:49 +08:00
|
|
|
}
|
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
/* Allocate a buffer of size SIZE with a guard page at the end. */
|
2017-09-15 01:09:49 +08:00
|
|
|
static void
|
2018-08-08 03:14:56 +08:00
|
|
|
alloc_buf (const char *id, size_t size, unsigned char **retbuf)
|
2017-09-15 01:09:49 +08:00
|
|
|
{
|
2018-08-08 03:14:56 +08:00
|
|
|
size_t alloc_size = size + page_size;
|
2017-09-15 01:09:49 +08:00
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
if (*retbuf != NULL)
|
|
|
|
{
|
|
|
|
int ret = munmap (*retbuf, alloc_size);
|
|
|
|
if (ret != 0)
|
|
|
|
exit_error (id, "munmap");
|
|
|
|
}
|
2017-09-15 01:09:49 +08:00
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
unsigned char *buf = mmap (0, alloc_size, PROT_READ | PROT_WRITE,
|
|
|
|
MAP_PRIVATE | MAP_ANON, -1, 0);
|
2017-09-15 01:09:49 +08:00
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
if (buf == MAP_FAILED)
|
|
|
|
exit_error (id, "mmap");
|
|
|
|
if (mprotect (buf + size, page_size, PROT_NONE))
|
|
|
|
exit_error (id, "mprotect");
|
2017-09-15 01:09:49 +08:00
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
*retbuf = buf;
|
|
|
|
}
|
2017-09-15 01:09:49 +08:00
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
static void
|
|
|
|
alloc_bufs (void)
|
|
|
|
{
|
|
|
|
alloc_buf ("buf1", buf1_size, &buf1);
|
|
|
|
alloc_buf ("buf2", buf2_size, &buf2);
|
2017-09-15 01:09:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_init (void)
|
|
|
|
{
|
|
|
|
# ifdef TEST_NAME
|
|
|
|
func_count = __libc_ifunc_impl_list (TEST_NAME, func_list,
|
|
|
|
(sizeof func_list
|
|
|
|
/ sizeof func_list[0]));
|
|
|
|
# endif
|
|
|
|
|
2018-08-08 03:14:56 +08:00
|
|
|
init_sizes ();
|
2017-09-15 01:09:49 +08:00
|
|
|
alloc_bufs ();
|
|
|
|
|
2013-04-16 20:07:24 +08:00
|
|
|
if (do_srandom)
|
|
|
|
{
|
|
|
|
printf ("Setting seed to 0x%x\n", seed);
|
|
|
|
srandom (seed);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* TEST_MAIN */
|