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 <stdint.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include "sys/time.h"
14 
gettime_i64(void)15 static int64_t gettime_i64(void) {
16     struct timeval tv;
17     gettimeofday(&tv, NULL);
18     return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
19 }
20 
21 #define FP_EXP (6)
22 #define FP_MULT (1000000LL)
23 
24 /* Format fixed point number. */
print_number(const int64_t x)25 void print_number(const int64_t x) {
26     int64_t x_abs, y;
27     int c, i, rounding;
28     size_t ptr;
29     char buffer[30];
30 
31     if (x == INT64_MIN) {
32         /* Prevent UB. */
33         printf("ERR");
34         return;
35     }
36     x_abs = x < 0 ? -x : x;
37 
38     /* Determine how many decimals we want to show (more than FP_EXP makes no
39      * sense). */
40     y = x_abs;
41     c = 0;
42     while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
43         y *= 10LL;
44         c++;
45     }
46 
47     /* Round to 'c' decimals. */
48     y = x_abs;
49     rounding = 0;
50     for (i = c; i < FP_EXP; ++i) {
51         rounding = (y % 10) >= 5;
52         y /= 10;
53     }
54     y += rounding;
55 
56     /* Format and print the number. */
57     ptr = sizeof(buffer) - 1;
58     buffer[ptr] = 0;
59     if (c != 0) {
60         for (i = 0; i < c; ++i) {
61             buffer[--ptr] = '0' + (y % 10);
62             y /= 10;
63         }
64         buffer[--ptr] = '.';
65     }
66     do {
67         buffer[--ptr] = '0' + (y % 10);
68         y /= 10;
69     } while (y != 0);
70     if (x < 0) {
71         buffer[--ptr] = '-';
72     }
73     printf("%s", &buffer[ptr]);
74 }
75 
run_benchmark(char * name,void (* benchmark)(void *,int),void (* setup)(void *),void (* teardown)(void *,int),void * data,int count,int iter)76 void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
77     int i;
78     int64_t min = INT64_MAX;
79     int64_t sum = 0;
80     int64_t max = 0;
81     for (i = 0; i < count; i++) {
82         int64_t begin, total;
83         if (setup != NULL) {
84             setup(data);
85         }
86         begin = gettime_i64();
87         benchmark(data, iter);
88         total = gettime_i64() - begin;
89         if (teardown != NULL) {
90             teardown(data, iter);
91         }
92         if (total < min) {
93             min = total;
94         }
95         if (total > max) {
96             max = total;
97         }
98         sum += total;
99     }
100     printf("%s: min ", name);
101     print_number(min * FP_MULT / iter);
102     printf("us / avg ");
103     print_number(((sum * FP_MULT) / count) / iter);
104     printf("us / max ");
105     print_number(max * FP_MULT / iter);
106     printf("us\n");
107 }
108 
have_flag(int argc,char ** argv,char * flag)109 int have_flag(int argc, char** argv, char *flag) {
110     char** argm = argv + argc;
111     argv++;
112     if (argv == argm) {
113         return 1;
114     }
115     while (argv != NULL && argv != argm) {
116         if (strcmp(*argv, flag) == 0) {
117             return 1;
118         }
119         argv++;
120     }
121     return 0;
122 }
123 
get_iters(int default_iters)124 int get_iters(int default_iters) {
125     char* env = getenv("SECP256K1_BENCH_ITERS");
126     if (env) {
127         return strtol(env, NULL, 0);
128     } else {
129         return default_iters;
130     }
131 }
132 
133 #endif /* SECP256K1_BENCH_H */
134