(root)/
glibc-2.38/
benchtests/
bench-arc4random.c
       1  /* arc4random benchmarks.
       2     Copyright (C) 2022-2023 Free Software Foundation, Inc.
       3     This file is part of the GNU C Library.
       4  
       5     The GNU C Library is free software; you can redistribute it and/or
       6     modify it under the terms of the GNU Lesser General Public
       7     License as published by the Free Software Foundation; either
       8     version 2.1 of the License, or (at your option) any later version.
       9  
      10     The GNU C Library is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13     Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public
      16     License along with the GNU C Library; if not, see
      17     <https://www.gnu.org/licenses/>.  */
      18  
      19  #include "bench-timing.h"
      20  #include "bench-util.h"
      21  #include "json-lib.h"
      22  #include <array_length.h>
      23  #include <intprops.h>
      24  #include <signal.h>
      25  #include <stdbool.h>
      26  #include <stdio.h>
      27  #include <stdlib.h>
      28  #include <support/support.h>
      29  #include <support/timespec.h>
      30  #include <support/xthread.h>
      31  
      32  static volatile sig_atomic_t timer_finished;
      33  
      34  static void timer_callback (int unused)
      35  {
      36    timer_finished = 1;
      37  }
      38  
      39  static timer_t timer;
      40  
      41  /* Run for approximately DURATION seconds, and it does not matter who
      42     receive the signal (so not need to mask it on main thread).  */
      43  static void
      44  timer_start (void)
      45  {
      46    timer_finished = 0;
      47    timer = support_create_timer (DURATION, 0, false, timer_callback);
      48  }
      49  static void
      50  timer_stop (void)
      51  {
      52    support_delete_timer (timer);
      53  }
      54  
      55  static const uint32_t sizes[] = { 0, 16, 32, 48, 64, 80, 96, 112, 128 };
      56  
      57  static double
      58  bench_throughput (void)
      59  {
      60    uint64_t n = 0;
      61  
      62    struct timespec start, end;
      63    clock_gettime (CLOCK_MONOTONIC, &start);
      64    while (1)
      65      {
      66        DO_NOT_OPTIMIZE_OUT (arc4random ());
      67        n++;
      68  
      69        if (timer_finished == 1)
      70  	break;
      71      }
      72    clock_gettime (CLOCK_MONOTONIC, &end);
      73    struct timespec diff = timespec_sub (end, start);
      74  
      75    double total = (double) n * sizeof (uint32_t);
      76    double duration = (double) diff.tv_sec
      77      + (double) diff.tv_nsec / TIMESPEC_HZ;
      78  
      79    return total / duration;
      80  }
      81  
      82  static double
      83  bench_latency (void)
      84  {
      85    timing_t start, stop, cur;
      86    const size_t iters = 1024;
      87  
      88    TIMING_NOW (start);
      89    for (size_t i = 0; i < iters; i++)
      90      DO_NOT_OPTIMIZE_OUT (arc4random ());
      91    TIMING_NOW (stop);
      92  
      93    TIMING_DIFF (cur, start, stop);
      94  
      95    return (double) (cur) / (double) iters;
      96  }
      97  
      98  static double
      99  bench_buf_throughput (size_t len)
     100  {
     101    uint8_t buf[len];
     102    uint64_t n = 0;
     103  
     104    struct timespec start, end;
     105    clock_gettime (CLOCK_MONOTONIC, &start);
     106    while (1)
     107      {
     108        arc4random_buf (buf, len);
     109        n++;
     110  
     111        if (timer_finished == 1)
     112  	break;
     113      }
     114    clock_gettime (CLOCK_MONOTONIC, &end);
     115    struct timespec diff = timespec_sub (end, start);
     116  
     117    double total = (double) n * len;
     118    double duration = (double) diff.tv_sec
     119      + (double) diff.tv_nsec / TIMESPEC_HZ;
     120  
     121    return total / duration;
     122  }
     123  
     124  static double
     125  bench_buf_latency (size_t len)
     126  {
     127    timing_t start, stop, cur;
     128    const size_t iters = 1024;
     129  
     130    uint8_t buf[len];
     131  
     132    TIMING_NOW (start);
     133    for (size_t i = 0; i < iters; i++)
     134      arc4random_buf (buf, len);
     135    TIMING_NOW (stop);
     136  
     137    TIMING_DIFF (cur, start, stop);
     138  
     139    return (double) (cur) / (double) iters;
     140  }
     141  
     142  static void
     143  bench_singlethread (json_ctx_t *json_ctx)
     144  {
     145    json_element_object_begin (json_ctx);
     146  
     147    json_array_begin (json_ctx, "throughput");
     148    for (int i = 0; i < array_length (sizes); i++)
     149      {
     150        timer_start ();
     151        double r = sizes[i] == 0
     152  	? bench_throughput () : bench_buf_throughput (sizes[i]);
     153        timer_stop ();
     154  
     155        json_element_double (json_ctx, r);
     156      }
     157    json_array_end (json_ctx);
     158  
     159    json_array_begin (json_ctx, "latency");
     160    for (int i = 0; i < array_length (sizes); i++)
     161      {
     162        timer_start ();
     163        double r = sizes[i] == 0
     164  	? bench_latency () : bench_buf_latency (sizes[i]);
     165        timer_stop ();
     166  
     167        json_element_double (json_ctx, r);
     168      }
     169    json_array_end (json_ctx);
     170  
     171    json_element_object_end (json_ctx);
     172  }
     173  
     174  static void
     175  run_bench (json_ctx_t *json_ctx, const char *name,
     176  	   char *const*fnames, size_t fnameslen,
     177  	   void (*bench) (json_ctx_t *ctx))
     178  {
     179    json_attr_object_begin (json_ctx, name);
     180    json_array_begin (json_ctx, "functions");
     181    for (int i = 0; i < fnameslen; i++)
     182      json_element_string (json_ctx, fnames[i]);
     183    json_array_end (json_ctx);
     184  
     185    json_array_begin (json_ctx, "results");
     186    bench (json_ctx);
     187    json_array_end (json_ctx);
     188    json_attr_object_end (json_ctx);
     189  }
     190  
     191  static int
     192  do_test (void)
     193  {
     194    char *fnames[array_length (sizes)];
     195    for (int i = 0; i < array_length (sizes); i++)
     196      if (sizes[i] == 0)
     197        fnames[i] = xasprintf ("arc4random");
     198      else
     199        fnames[i] = xasprintf ("arc4random_buf(%u)", sizes[i]);
     200  
     201    json_ctx_t json_ctx;
     202    json_init (&json_ctx, 0, stdout);
     203  
     204    json_document_begin (&json_ctx);
     205    json_attr_string (&json_ctx, "timing_type", TIMING_TYPE);
     206  
     207    run_bench (&json_ctx, "single-thread", fnames, array_length (fnames),
     208  	     bench_singlethread);
     209  
     210    json_document_end (&json_ctx);
     211  
     212    for (int i = 0; i < array_length (sizes); i++)
     213      free (fnames[i]);
     214  
     215    return 0;
     216  }
     217  
     218  #include <support/test-driver.c>