bench.h (5077B)
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 #if (defined(_MSC_VER) && _MSC_VER >= 1900) 16 # include <time.h> 17 #else 18 # include <sys/time.h> 19 #endif 20 21 static int64_t gettime_i64(void) { 22 #if (defined(_MSC_VER) && _MSC_VER >= 1900) 23 /* C11 way to get wallclock time */ 24 struct timespec tv; 25 if (!timespec_get(&tv, TIME_UTC)) { 26 fputs("timespec_get failed!", stderr); 27 exit(1); 28 } 29 return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL; 30 #else 31 struct timeval tv; 32 gettimeofday(&tv, NULL); 33 return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL; 34 #endif 35 } 36 37 #define FP_EXP (6) 38 #define FP_MULT (1000000LL) 39 40 /* Format fixed point number. */ 41 static void print_number(const int64_t x) { 42 int64_t x_abs, y; 43 int c, i, rounding, g; /* g = integer part size, c = fractional part size */ 44 size_t ptr; 45 char buffer[30]; 46 47 if (x == INT64_MIN) { 48 /* Prevent UB. */ 49 printf("ERR"); 50 return; 51 } 52 x_abs = x < 0 ? -x : x; 53 54 /* Determine how many decimals we want to show (more than FP_EXP makes no 55 * sense). */ 56 y = x_abs; 57 c = 0; 58 while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) { 59 y *= 10LL; 60 c++; 61 } 62 63 /* Round to 'c' decimals. */ 64 y = x_abs; 65 rounding = 0; 66 for (i = c; i < FP_EXP; ++i) { 67 rounding = (y % 10) >= 5; 68 y /= 10; 69 } 70 y += rounding; 71 72 /* Format and print the number. */ 73 ptr = sizeof(buffer) - 1; 74 buffer[ptr] = 0; 75 g = 0; 76 if (c != 0) { /* non zero fractional part */ 77 for (i = 0; i < c; ++i) { 78 buffer[--ptr] = '0' + (y % 10); 79 y /= 10; 80 } 81 } else if (c == 0) { /* fractional part is 0 */ 82 buffer[--ptr] = '0'; 83 } 84 buffer[--ptr] = '.'; 85 do { 86 buffer[--ptr] = '0' + (y % 10); 87 y /= 10; 88 g++; 89 } while (y != 0); 90 if (x < 0) { 91 buffer[--ptr] = '-'; 92 g++; 93 } 94 printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */ 95 printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */ 96 } 97 98 static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) { 99 int i; 100 int64_t min = INT64_MAX; 101 int64_t sum = 0; 102 int64_t max = 0; 103 for (i = 0; i < count; i++) { 104 int64_t begin, total; 105 if (setup != NULL) { 106 setup(data); 107 } 108 begin = gettime_i64(); 109 benchmark(data, iter); 110 total = gettime_i64() - begin; 111 if (teardown != NULL) { 112 teardown(data, iter); 113 } 114 if (total < min) { 115 min = total; 116 } 117 if (total > max) { 118 max = total; 119 } 120 sum += total; 121 } 122 /* ',' is used as a column delimiter */ 123 printf("%-30s, ", name); 124 print_number(min * FP_MULT / iter); 125 printf(" , "); 126 print_number(((sum * FP_MULT) / count) / iter); 127 printf(" , "); 128 print_number(max * FP_MULT / iter); 129 printf("\n"); 130 } 131 132 static int have_flag(int argc, char** argv, char *flag) { 133 char** argm = argv + argc; 134 argv++; 135 while (argv != argm) { 136 if (strcmp(*argv, flag) == 0) { 137 return 1; 138 } 139 argv++; 140 } 141 return 0; 142 } 143 144 /* takes an array containing the arguments that the user is allowed to enter on the command-line 145 returns: 146 - 1 if the user entered an invalid argument 147 - 0 if all the user entered arguments are valid */ 148 static int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) { 149 size_t i; 150 int found_valid; 151 char** argm = argv + argc; 152 argv++; 153 154 while (argv != argm) { 155 found_valid = 0; 156 for (i = 0; i < n; i++) { 157 if (strcmp(*argv, valid_args[i]) == 0) { 158 found_valid = 1; /* user entered a valid arg from the list */ 159 break; 160 } 161 } 162 if (found_valid == 0) { 163 return 1; /* invalid arg found */ 164 } 165 argv++; 166 } 167 return 0; 168 } 169 170 static int get_iters(int default_iters) { 171 char* env = getenv("SECP256K1_BENCH_ITERS"); 172 if (env) { 173 return strtol(env, NULL, 0); 174 } else { 175 return default_iters; 176 } 177 } 178 179 static void print_output_table_header_row(void) { 180 char* bench_str = "Benchmark"; /* left justified */ 181 char* min_str = " Min(us) "; /* center alignment */ 182 char* avg_str = " Avg(us) "; 183 char* max_str = " Max(us) "; 184 printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str); 185 printf("\n"); 186 } 187 188 #endif /* SECP256K1_BENCH_H */