bench-arc4random.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /* arc4random benchmarks.
  2. Copyright (C) 2022-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 "bench-timing.h"
  16. #include "bench-util.h"
  17. #include "json-lib.h"
  18. #include <array_length.h>
  19. #include <intprops.h>
  20. #include <signal.h>
  21. #include <stdbool.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <support/support.h>
  25. #include <support/timespec.h>
  26. #include <support/xthread.h>
  27. static volatile sig_atomic_t timer_finished;
  28. static void timer_callback (int unused)
  29. {
  30. timer_finished = 1;
  31. }
  32. static timer_t timer;
  33. /* Run for approximately DURATION seconds, and it does not matter who
  34. receive the signal (so not need to mask it on main thread). */
  35. static void
  36. timer_start (void)
  37. {
  38. timer_finished = 0;
  39. timer = support_create_timer (DURATION, 0, false, timer_callback);
  40. }
  41. static void
  42. timer_stop (void)
  43. {
  44. support_delete_timer (timer);
  45. }
  46. static const uint32_t sizes[] = { 0, 16, 32, 48, 64, 80, 96, 112, 128 };
  47. static double
  48. bench_throughput (void)
  49. {
  50. uint64_t n = 0;
  51. struct timespec start, end;
  52. clock_gettime (CLOCK_MONOTONIC, &start);
  53. while (1)
  54. {
  55. DO_NOT_OPTIMIZE_OUT (arc4random ());
  56. n++;
  57. if (timer_finished == 1)
  58. break;
  59. }
  60. clock_gettime (CLOCK_MONOTONIC, &end);
  61. struct timespec diff = timespec_sub (end, start);
  62. double total = (double) n * sizeof (uint32_t);
  63. double duration = (double) diff.tv_sec
  64. + (double) diff.tv_nsec / TIMESPEC_HZ;
  65. return total / duration;
  66. }
  67. static double
  68. bench_latency (void)
  69. {
  70. timing_t start, stop, cur;
  71. const size_t iters = 1024;
  72. TIMING_NOW (start);
  73. for (size_t i = 0; i < iters; i++)
  74. DO_NOT_OPTIMIZE_OUT (arc4random ());
  75. TIMING_NOW (stop);
  76. TIMING_DIFF (cur, start, stop);
  77. return (double) (cur) / (double) iters;
  78. }
  79. static double
  80. bench_buf_throughput (size_t len)
  81. {
  82. uint8_t buf[len];
  83. uint64_t n = 0;
  84. struct timespec start, end;
  85. clock_gettime (CLOCK_MONOTONIC, &start);
  86. while (1)
  87. {
  88. arc4random_buf (buf, len);
  89. n++;
  90. if (timer_finished == 1)
  91. break;
  92. }
  93. clock_gettime (CLOCK_MONOTONIC, &end);
  94. struct timespec diff = timespec_sub (end, start);
  95. double total = (double) n * len;
  96. double duration = (double) diff.tv_sec
  97. + (double) diff.tv_nsec / TIMESPEC_HZ;
  98. return total / duration;
  99. }
  100. static double
  101. bench_buf_latency (size_t len)
  102. {
  103. timing_t start, stop, cur;
  104. const size_t iters = 1024;
  105. uint8_t buf[len];
  106. TIMING_NOW (start);
  107. for (size_t i = 0; i < iters; i++)
  108. arc4random_buf (buf, len);
  109. TIMING_NOW (stop);
  110. TIMING_DIFF (cur, start, stop);
  111. return (double) (cur) / (double) iters;
  112. }
  113. static void
  114. bench_singlethread (json_ctx_t *json_ctx)
  115. {
  116. json_element_object_begin (json_ctx);
  117. json_array_begin (json_ctx, "throughput");
  118. for (int i = 0; i < array_length (sizes); i++)
  119. {
  120. timer_start ();
  121. double r = sizes[i] == 0
  122. ? bench_throughput () : bench_buf_throughput (sizes[i]);
  123. timer_stop ();
  124. json_element_double (json_ctx, r);
  125. }
  126. json_array_end (json_ctx);
  127. json_array_begin (json_ctx, "latency");
  128. for (int i = 0; i < array_length (sizes); i++)
  129. {
  130. timer_start ();
  131. double r = sizes[i] == 0
  132. ? bench_latency () : bench_buf_latency (sizes[i]);
  133. timer_stop ();
  134. json_element_double (json_ctx, r);
  135. }
  136. json_array_end (json_ctx);
  137. json_element_object_end (json_ctx);
  138. }
  139. static void
  140. run_bench (json_ctx_t *json_ctx, const char *name,
  141. char *const*fnames, size_t fnameslen,
  142. void (*bench) (json_ctx_t *ctx))
  143. {
  144. json_attr_object_begin (json_ctx, name);
  145. json_array_begin (json_ctx, "functions");
  146. for (int i = 0; i < fnameslen; i++)
  147. json_element_string (json_ctx, fnames[i]);
  148. json_array_end (json_ctx);
  149. json_array_begin (json_ctx, "results");
  150. bench (json_ctx);
  151. json_array_end (json_ctx);
  152. json_attr_object_end (json_ctx);
  153. }
  154. static int
  155. do_test (void)
  156. {
  157. char *fnames[array_length (sizes)];
  158. for (int i = 0; i < array_length (sizes); i++)
  159. if (sizes[i] == 0)
  160. fnames[i] = xasprintf ("arc4random");
  161. else
  162. fnames[i] = xasprintf ("arc4random_buf(%u)", sizes[i]);
  163. json_ctx_t json_ctx;
  164. json_init (&json_ctx, 0, stdout);
  165. json_document_begin (&json_ctx);
  166. json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
  167. run_bench (&json_ctx, "single-thread", fnames, array_length (fnames),
  168. bench_singlethread);
  169. json_document_end (&json_ctx);
  170. for (int i = 0; i < array_length (sizes); i++)
  171. free (fnames[i]);
  172. return 0;
  173. }
  174. #include <support/test-driver.c>