bench-string.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /* Measure string and memory functions.
  2. Copyright (C) 2013-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #include <getopt.h>
  16. #include <sys/cdefs.h>
  17. #include <programs/xmalloc.h>
  18. /* We are compiled under _ISOMAC, so libc-symbols.h does not do this
  19. for us. */
  20. #include "config.h"
  21. #ifdef HAVE_CC_INHIBIT_LOOP_TO_LIBCALL
  22. # define inhibit_loop_to_libcall \
  23. __attribute__ ((__optimize__ ("-fno-tree-loop-distribute-patterns")))
  24. #else
  25. # define inhibit_loop_to_libcall
  26. #endif
  27. typedef struct
  28. {
  29. const char *name;
  30. void (*fn) (void);
  31. long test;
  32. } impl_t;
  33. extern impl_t __start_impls[], __stop_impls[];
  34. #define IMPL(name, test) \
  35. impl_t tst_ ## name \
  36. __attribute__ ((section ("impls"), aligned (sizeof (void *)))) \
  37. = { __STRING (name), (void (*) (void))name, test };
  38. #ifdef TEST_MAIN
  39. # ifndef _GNU_SOURCE
  40. # define _GNU_SOURCE
  41. # endif
  42. # undef __USE_STRING_INLINES
  43. # include <stdio.h>
  44. # include <stdlib.h>
  45. # include <string.h>
  46. # include <sys/mman.h>
  47. # include <sys/param.h>
  48. # include <unistd.h>
  49. # include <fcntl.h>
  50. # include <error.h>
  51. # include <errno.h>
  52. # include <time.h>
  53. # include <ifunc-impl-list.h>
  54. # define GL(x) _##x
  55. # define GLRO(x) _##x
  56. # include "bench-timing.h"
  57. # ifndef WIDE
  58. # define CHAR char
  59. # define UCHAR unsigned char
  60. # define CHARBYTES 1
  61. # define MAX_CHAR CHAR_MAX
  62. # define MEMCHR memchr
  63. # define MEMCMP memcmp
  64. # define MEMCPY memcpy
  65. # define MEMSET memset
  66. # define STRCAT strcat
  67. # define STRLEN strlen
  68. # define STRCMP strcmp
  69. # define STRCHR strchr
  70. # define STRCPY strcpy
  71. # define STRNLEN strnlen
  72. # define STRCSPN strcspn
  73. # define STRNCAT strncat
  74. # define STRNCMP strncmp
  75. # define STRNCPY strncpy
  76. # define STRPBRK strpbrk
  77. # define STRRCHR strrchr
  78. # define STRSPN strspn
  79. # define STPCPY stpcpy
  80. # define STPNCPY stpncpy
  81. # else
  82. # include <wchar.h>
  83. # define CHAR wchar_t
  84. # define UCHAR wchar_t
  85. # define CHARBYTES 4
  86. # define MAX_CHAR WCHAR_MAX
  87. # define MEMCHR wmemchr
  88. # define MEMCMP wmemcmp
  89. # define MEMCPY wmemcpy
  90. # define MEMSET wmemset
  91. # define STRCAT wcscat
  92. # define STRLEN wcslen
  93. # define STRCMP wcscmp
  94. # define STRCHR wcschr
  95. # define STRCPY wcscpy
  96. # define STRNLEN wcsnlen
  97. # define STRCSPN wcscspn
  98. # define STRNCAT wcsncat
  99. # define STRNCMP wcsncmp
  100. # define STRNCPY wcsncpy
  101. # define STRPBRK wcspbrk
  102. # define STRRCHR wcsrchr
  103. # define STRSPN wcsspn
  104. # define STPCPY wcpcpy
  105. # define STPNCPY wcpncpy
  106. # endif /* WIDE */
  107. # define TEST_FUNCTION test_main
  108. # ifndef TIMEOUT
  109. # define TIMEOUT (4 * 60)
  110. # endif
  111. # define OPT_ITERATIONS 10000
  112. # define OPT_RANDOM 10001
  113. # define OPT_SEED 10002
  114. # define INNER_LOOP_ITERS 8192
  115. # define INNER_LOOP_ITERS8 32768
  116. # define INNER_LOOP_ITERS_LARGE 131072
  117. # define INNER_LOOP_ITERS_MEDIUM 2048
  118. # define INNER_LOOP_ITERS_SMALL 256
  119. int ret, do_srandom;
  120. unsigned int seed;
  121. # ifndef ITERATIONS
  122. size_t iterations = 100000;
  123. # define ITERATIONS_OPTIONS \
  124. { "iterations", required_argument, NULL, OPT_ITERATIONS },
  125. # define ITERATIONS_PROCESS \
  126. case OPT_ITERATIONS: \
  127. iterations = strtoul (optarg, NULL, 0); \
  128. break;
  129. # define ITERATIONS iterations
  130. # else
  131. # define ITERATIONS_OPTIONS
  132. # define ITERATIONS_PROCESS
  133. # endif
  134. # define CMDLINE_OPTIONS ITERATIONS_OPTIONS \
  135. { "random", no_argument, NULL, OPT_RANDOM }, \
  136. { "seed", required_argument, NULL, OPT_SEED },
  137. static void __attribute__ ((used))
  138. cmdline_process_function (int c)
  139. {
  140. switch (c)
  141. {
  142. ITERATIONS_PROCESS
  143. case OPT_RANDOM:
  144. {
  145. int fdr = open ("/dev/urandom", O_RDONLY);
  146. if (fdr < 0 || read (fdr, &seed, sizeof (seed)) != sizeof (seed))
  147. seed = time (NULL);
  148. if (fdr >= 0)
  149. close (fdr);
  150. do_srandom = 1;
  151. break;
  152. }
  153. case OPT_SEED:
  154. seed = strtoul (optarg, NULL, 0);
  155. do_srandom = 1;
  156. break;
  157. }
  158. }
  159. # define CMDLINE_PROCESS cmdline_process_function
  160. # define CALL(impl, ...) \
  161. (* (proto_t) (impl)->fn) (__VA_ARGS__)
  162. # ifdef TEST_NAME
  163. /* Increase size of FUNC_LIST if assert is triggered at run-time. */
  164. static struct libc_ifunc_impl func_list[32];
  165. static int func_count;
  166. static int impl_count = -1;
  167. static impl_t *impl_array;
  168. # define FOR_EACH_IMPL(impl, notall) \
  169. impl_t *impl; \
  170. int count; \
  171. if (impl_count == -1) \
  172. { \
  173. impl_count = 0; \
  174. if (func_count != 0) \
  175. { \
  176. int f; \
  177. impl_t *skip = NULL, *a; \
  178. for (impl = __start_impls; impl < __stop_impls; ++impl) \
  179. if (strcmp (impl->name, TEST_NAME) == 0) \
  180. skip = impl; \
  181. else \
  182. impl_count++; \
  183. a = impl_array = xmalloc ((impl_count + func_count) * \
  184. sizeof (impl_t)); \
  185. for (impl = __start_impls; impl < __stop_impls; ++impl) \
  186. if (impl != skip) \
  187. *a++ = *impl; \
  188. for (f = 0; f < func_count; f++) \
  189. if (func_list[f].usable) \
  190. { \
  191. a->name = func_list[f].name; \
  192. a->fn = func_list[f].fn; \
  193. a->test = 1; \
  194. a++; \
  195. } \
  196. impl_count = a - impl_array; \
  197. } \
  198. else \
  199. { \
  200. impl_count = __stop_impls - __start_impls; \
  201. impl_array = __start_impls; \
  202. } \
  203. } \
  204. impl = impl_array; \
  205. for (count = 0; count < impl_count; ++count, ++impl) \
  206. if (!notall || impl->test)
  207. # else /* !TEST_NAME */
  208. # define FOR_EACH_IMPL(impl, notall) \
  209. for (impl_t *impl = __start_impls; impl < __stop_impls; ++impl) \
  210. if (!notall || impl->test)
  211. # endif /* !TEST_NAME */
  212. # ifndef BUF1PAGES
  213. # define BUF1PAGES 1
  214. # endif
  215. unsigned char *buf1, *buf2;
  216. static size_t buf1_size, buf2_size, page_size;
  217. static void
  218. init_sizes (void)
  219. {
  220. page_size = 2 * getpagesize ();
  221. # ifdef MIN_PAGE_SIZE
  222. if (page_size < MIN_PAGE_SIZE)
  223. page_size = MIN_PAGE_SIZE;
  224. # endif
  225. buf1_size = BUF1PAGES * page_size;
  226. buf2_size = page_size;
  227. }
  228. static void
  229. exit_error (const char *id, const char *func)
  230. {
  231. error (EXIT_FAILURE, errno, "%s: %s failed", id, func);
  232. }
  233. /* Allocate a buffer of size SIZE with a guard page at the end. */
  234. static void
  235. alloc_buf (const char *id, size_t size, unsigned char **retbuf)
  236. {
  237. size_t alloc_size = size + page_size;
  238. if (*retbuf != NULL)
  239. {
  240. int ret = munmap (*retbuf, alloc_size);
  241. if (ret != 0)
  242. exit_error (id, "munmap");
  243. }
  244. unsigned char *buf = mmap (0, alloc_size, PROT_READ | PROT_WRITE,
  245. MAP_PRIVATE | MAP_ANON, -1, 0);
  246. if (buf == MAP_FAILED)
  247. exit_error (id, "mmap");
  248. if (mprotect (buf + size, page_size, PROT_NONE))
  249. exit_error (id, "mprotect");
  250. *retbuf = buf;
  251. }
  252. static void
  253. alloc_bufs (void)
  254. {
  255. alloc_buf ("buf1", buf1_size, &buf1);
  256. alloc_buf ("buf2", buf2_size, &buf2);
  257. }
  258. static void
  259. test_init (void)
  260. {
  261. # ifdef TEST_NAME
  262. func_count = __libc_ifunc_impl_list (TEST_NAME, func_list,
  263. (sizeof func_list
  264. / sizeof func_list[0]));
  265. # endif
  266. init_sizes ();
  267. alloc_bufs ();
  268. if (do_srandom)
  269. {
  270. printf ("Setting seed to 0x%x\n", seed);
  271. srandom (seed);
  272. }
  273. }
  274. #endif /* TEST_MAIN */