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 */