| /* 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 | 
 |    <http://www.gnu.org/licenses/>.  */ | 
 |  | 
 | #include <sys/cdefs.h> | 
 |  | 
 | 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 | 
 | # 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 */ |