/ src / secp256k1 / src / bench.h
bench.h
  1  /***********************************************************************
  2   * Copyright (c) 2014 Pieter Wuille                                    *
  3   * Distributed under the MIT software license, see the accompanying    *
  4   * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
  5   ***********************************************************************/
  6  
  7  #ifndef SECP256K1_BENCH_H
  8  #define SECP256K1_BENCH_H
  9  
 10  #include <stdlib.h>
 11  #include <stdint.h>
 12  #include <stdio.h>
 13  #include <string.h>
 14  
 15  #include "tests_common.h"
 16  
 17  #define FP_EXP (6)
 18  #define FP_MULT (1000000LL)
 19  
 20  /* Format fixed point number. */
 21  static void print_number(const int64_t x) {
 22      int64_t x_abs, y;
 23      int c, i, rounding, g; /* g = integer part size, c = fractional part size */
 24      size_t ptr;
 25      char buffer[30];
 26  
 27      if (x == INT64_MIN) {
 28          /* Prevent UB. */
 29          printf("ERR");
 30          return;
 31      }
 32      x_abs = x < 0 ? -x : x;
 33  
 34      /* Determine how many decimals we want to show (more than FP_EXP makes no
 35       * sense). */
 36      y = x_abs;
 37      c = 0;
 38      while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
 39          y *= 10LL;
 40          c++;
 41      }
 42  
 43      /* Round to 'c' decimals. */
 44      y = x_abs;
 45      rounding = 0;
 46      for (i = c; i < FP_EXP; ++i) {
 47          rounding = (y % 10) >= 5;
 48          y /= 10;
 49      }
 50      y += rounding;
 51  
 52      /* Format and print the number. */
 53      ptr = sizeof(buffer) - 1;
 54      buffer[ptr] = 0;
 55      g = 0;
 56      if (c != 0) { /* non zero fractional part */
 57          for (i = 0; i < c; ++i) {
 58              buffer[--ptr] = '0' + (y % 10);
 59              y /= 10;
 60          }
 61      } else if (c == 0) { /* fractional part is 0 */
 62          buffer[--ptr] = '0';
 63      }
 64      buffer[--ptr] = '.';
 65      do {
 66          buffer[--ptr] = '0' + (y % 10);
 67          y /= 10;
 68          g++;
 69      } while (y != 0);
 70      if (x < 0) {
 71          buffer[--ptr] = '-';
 72          g++;
 73      }
 74      printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */
 75      printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
 76  }
 77  
 78  static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
 79      int i;
 80      int64_t min = INT64_MAX;
 81      int64_t sum = 0;
 82      int64_t max = 0;
 83      for (i = 0; i < count; i++) {
 84          int64_t begin, total;
 85          if (setup != NULL) {
 86              setup(data);
 87          }
 88          begin = gettime_i64();
 89          benchmark(data, iter);
 90          total = gettime_i64() - begin;
 91          if (teardown != NULL) {
 92              teardown(data, iter);
 93          }
 94          if (total < min) {
 95              min = total;
 96          }
 97          if (total > max) {
 98              max = total;
 99          }
100          sum += total;
101      }
102      /* ',' is used as a column delimiter */
103      printf("%-30s, ", name);
104      print_number(min * FP_MULT / iter);
105      printf("   , ");
106      print_number(((sum * FP_MULT) / count) / iter);
107      printf("   , ");
108      print_number(max * FP_MULT / iter);
109      printf("\n");
110  }
111  
112  static int have_flag(int argc, char** argv, char *flag) {
113      char** argm = argv + argc;
114      argv++;
115      while (argv != argm) {
116          if (strcmp(*argv, flag) == 0) {
117              return 1;
118          }
119          argv++;
120      }
121      return 0;
122  }
123  
124  /* takes an array containing the arguments that the user is allowed to enter on the command-line
125     returns:
126        - 1 if the user entered an invalid argument
127        - 0 if all the user entered arguments are valid */
128  static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
129      size_t i;
130      int found_valid;
131      char** argm = argv + argc;
132      argv++;
133  
134      while (argv != argm) {
135          found_valid = 0;
136          for (i = 0; i < n; i++) {
137              if (strcmp(*argv, valid_args[i]) == 0) {
138                  found_valid = 1; /* user entered a valid arg from the list */
139                  break;
140              }
141          }
142          if (found_valid == 0) {
143              return 1; /* invalid arg found */
144          }
145          argv++;
146      }
147      return 0;
148  }
149  
150  static int get_iters(int default_iters) {
151      char* env = getenv("SECP256K1_BENCH_ITERS");
152      if (env) {
153          char* endptr;
154          long int iters = strtol(env, &endptr, 0);
155          if (*endptr != '\0' || iters <= 0) {
156              printf("Error: Value of SECP256K1_BENCH_ITERS is not a positive integer: %s\n\n", env);
157              return 0;
158          }
159          return iters;
160      } else {
161          return default_iters;
162      }
163  }
164  
165  static void print_output_table_header_row(void) {
166      char* bench_str = "Benchmark";     /* left justified */
167      char* min_str = "    Min(us)    "; /* center alignment */
168      char* avg_str = "    Avg(us)    ";
169      char* max_str = "    Max(us)    ";
170      printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str);
171      printf("\n");
172  }
173  
174  #endif /* SECP256K1_BENCH_H */