/* Measure string and memory functions. Copyright (C) 2013-2016 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 . */ #include 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 # include # include # include # include # include # include # include # include # include # include # define GL(x) _##x # define GLRO(x) _##x # include "bench-timing.h" # define TEST_FUNCTION test_main () # define TIMEOUT (4 * 60) # define OPT_ITERATIONS 10000 # define OPT_RANDOM 10001 # define OPT_SEED 10002 # define INNER_LOOP_ITERS 64 unsigned char *buf1, *buf2; int ret, do_srandom; unsigned int seed; size_t page_size; # 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 }, # define CMDLINE_PROCESS ITERATIONS_PROCESS \ case OPT_RANDOM: \ { \ int fdr = open ("/dev/urandom", O_RDONLY); \ \ if (fdr < 0 || read (fdr, &seed, sizeof(seed)) != sizeof (seed)) \ 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 CALL(impl, ...) \ (* (proto_t) (impl)->fn) (__VA_ARGS__) # ifdef TEST_NAME /* 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) # else /* !TEST_NAME */ # define FOR_EACH_IMPL(impl, notall) \ for (impl_t *impl = __start_impls; impl < __stop_impls; ++impl) \ if (!notall || impl->test) # endif /* !TEST_NAME */ # ifndef BUF1PAGES # define BUF1PAGES 1 # endif 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 page_size = 2 * getpagesize (); # ifdef MIN_PAGE_SIZE if (page_size < MIN_PAGE_SIZE) page_size = MIN_PAGE_SIZE; # endif buf1 = mmap (0, (BUF1PAGES + 1) * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (buf1 == MAP_FAILED) error (EXIT_FAILURE, errno, "mmap failed"); if (mprotect (buf1 + BUF1PAGES * page_size, page_size, PROT_NONE)) error (EXIT_FAILURE, errno, "mprotect failed"); buf2 = mmap (0, 2 * page_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); if (buf2 == MAP_FAILED) error (EXIT_FAILURE, errno, "mmap failed"); if (mprotect (buf2 + page_size, page_size, PROT_NONE)) error (EXIT_FAILURE, errno, "mprotect failed"); if (do_srandom) { printf ("Setting seed to 0x%x\n", seed); srandom (seed); } memset (buf1, 0xa5, BUF1PAGES * page_size); memset (buf2, 0x5a, page_size); } #endif /* TEST_MAIN */