2020-12-29 17:15:51 +00:00
|
|
|
/***********************************************************************
|
|
|
|
* Copyright (c) 2014 Pieter Wuille *
|
|
|
|
* Distributed under the MIT software license, see the accompanying *
|
|
|
|
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
|
|
|
|
***********************************************************************/
|
2015-10-26 14:54:21 +00:00
|
|
|
|
2018-07-09 11:17:44 +00:00
|
|
|
#ifndef SECP256K1_BENCH_H
|
|
|
|
#define SECP256K1_BENCH_H
|
2015-10-26 14:54:21 +00:00
|
|
|
|
2022-12-20 21:11:14 +00:00
|
|
|
#include <stdlib.h>
|
2020-08-26 17:35:27 +00:00
|
|
|
#include <stdint.h>
|
2015-10-26 14:54:21 +00:00
|
|
|
#include <stdio.h>
|
2018-07-09 11:17:44 +00:00
|
|
|
#include <string.h>
|
2022-12-20 21:11:14 +00:00
|
|
|
|
|
|
|
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
|
|
# include <time.h>
|
|
|
|
#else
|
|
|
|
# include "sys/time.h"
|
|
|
|
#endif
|
2015-10-26 14:54:21 +00:00
|
|
|
|
2020-08-26 17:35:27 +00:00
|
|
|
static int64_t gettime_i64(void) {
|
2022-12-20 21:11:14 +00:00
|
|
|
#if (defined(_MSC_VER) && _MSC_VER >= 1900)
|
|
|
|
/* C11 way to get wallclock time */
|
|
|
|
struct timespec tv;
|
|
|
|
if (!timespec_get(&tv, TIME_UTC)) {
|
|
|
|
fputs("timespec_get failed!", stderr);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
|
|
|
|
#else
|
2015-10-26 14:54:21 +00:00
|
|
|
struct timeval tv;
|
|
|
|
gettimeofday(&tv, NULL);
|
2020-08-26 17:35:27 +00:00
|
|
|
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
|
2022-12-20 21:11:14 +00:00
|
|
|
#endif
|
2015-10-26 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 17:35:27 +00:00
|
|
|
#define FP_EXP (6)
|
|
|
|
#define FP_MULT (1000000LL)
|
|
|
|
|
|
|
|
/* Format fixed point number. */
|
|
|
|
void print_number(const int64_t x) {
|
|
|
|
int64_t x_abs, y;
|
2022-03-08 19:45:41 +00:00
|
|
|
int c, i, rounding, g; /* g = integer part size, c = fractional part size */
|
2020-08-26 17:35:27 +00:00
|
|
|
size_t ptr;
|
|
|
|
char buffer[30];
|
|
|
|
|
|
|
|
if (x == INT64_MIN) {
|
|
|
|
/* Prevent UB. */
|
|
|
|
printf("ERR");
|
|
|
|
return;
|
2015-10-26 14:54:21 +00:00
|
|
|
}
|
2020-08-26 17:35:27 +00:00
|
|
|
x_abs = x < 0 ? -x : x;
|
|
|
|
|
|
|
|
/* Determine how many decimals we want to show (more than FP_EXP makes no
|
|
|
|
* sense). */
|
|
|
|
y = x_abs;
|
|
|
|
c = 0;
|
|
|
|
while (y > 0LL && y < 100LL * FP_MULT && c < FP_EXP) {
|
|
|
|
y *= 10LL;
|
2015-10-26 14:54:21 +00:00
|
|
|
c++;
|
|
|
|
}
|
2020-08-26 17:35:27 +00:00
|
|
|
|
|
|
|
/* Round to 'c' decimals. */
|
|
|
|
y = x_abs;
|
|
|
|
rounding = 0;
|
|
|
|
for (i = c; i < FP_EXP; ++i) {
|
|
|
|
rounding = (y % 10) >= 5;
|
|
|
|
y /= 10;
|
|
|
|
}
|
|
|
|
y += rounding;
|
|
|
|
|
|
|
|
/* Format and print the number. */
|
|
|
|
ptr = sizeof(buffer) - 1;
|
|
|
|
buffer[ptr] = 0;
|
2022-03-08 19:45:41 +00:00
|
|
|
g = 0;
|
|
|
|
if (c != 0) { /* non zero fractional part */
|
2020-08-26 17:35:27 +00:00
|
|
|
for (i = 0; i < c; ++i) {
|
|
|
|
buffer[--ptr] = '0' + (y % 10);
|
|
|
|
y /= 10;
|
|
|
|
}
|
2022-03-08 19:45:41 +00:00
|
|
|
} else if (c == 0) { /* fractional part is 0 */
|
|
|
|
buffer[--ptr] = '0';
|
2020-08-26 17:35:27 +00:00
|
|
|
}
|
2022-03-08 19:45:41 +00:00
|
|
|
buffer[--ptr] = '.';
|
2020-08-26 17:35:27 +00:00
|
|
|
do {
|
|
|
|
buffer[--ptr] = '0' + (y % 10);
|
|
|
|
y /= 10;
|
2022-03-08 19:45:41 +00:00
|
|
|
g++;
|
2020-08-26 17:35:27 +00:00
|
|
|
} while (y != 0);
|
|
|
|
if (x < 0) {
|
|
|
|
buffer[--ptr] = '-';
|
2022-03-08 19:45:41 +00:00
|
|
|
g++;
|
2020-08-26 17:35:27 +00:00
|
|
|
}
|
2022-03-08 19:45:41 +00:00
|
|
|
printf("%5.*s", g, &buffer[ptr]); /* Prints integer part */
|
|
|
|
printf("%-*s", FP_EXP, &buffer[ptr + g]); /* Prints fractional part */
|
2015-10-26 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
2020-08-26 17:35:27 +00:00
|
|
|
void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setup)(void*), void (*teardown)(void*, int), void* data, int count, int iter) {
|
2015-10-26 14:54:21 +00:00
|
|
|
int i;
|
2020-08-26 17:35:27 +00:00
|
|
|
int64_t min = INT64_MAX;
|
|
|
|
int64_t sum = 0;
|
|
|
|
int64_t max = 0;
|
2015-10-26 14:54:21 +00:00
|
|
|
for (i = 0; i < count; i++) {
|
2020-08-26 17:35:27 +00:00
|
|
|
int64_t begin, total;
|
2015-10-26 14:54:21 +00:00
|
|
|
if (setup != NULL) {
|
|
|
|
setup(data);
|
|
|
|
}
|
2020-08-26 17:35:27 +00:00
|
|
|
begin = gettime_i64();
|
|
|
|
benchmark(data, iter);
|
|
|
|
total = gettime_i64() - begin;
|
2015-10-26 14:54:21 +00:00
|
|
|
if (teardown != NULL) {
|
2020-08-26 17:35:27 +00:00
|
|
|
teardown(data, iter);
|
2015-10-26 14:54:21 +00:00
|
|
|
}
|
|
|
|
if (total < min) {
|
|
|
|
min = total;
|
|
|
|
}
|
|
|
|
if (total > max) {
|
|
|
|
max = total;
|
|
|
|
}
|
|
|
|
sum += total;
|
|
|
|
}
|
2022-03-08 19:45:41 +00:00
|
|
|
/* ',' is used as a column delimiter */
|
|
|
|
printf("%-30s, ", name);
|
2020-08-26 17:35:27 +00:00
|
|
|
print_number(min * FP_MULT / iter);
|
2022-03-08 19:45:41 +00:00
|
|
|
printf(" , ");
|
2020-08-26 17:35:27 +00:00
|
|
|
print_number(((sum * FP_MULT) / count) / iter);
|
2022-03-08 19:45:41 +00:00
|
|
|
printf(" , ");
|
2020-08-26 17:35:27 +00:00
|
|
|
print_number(max * FP_MULT / iter);
|
2022-03-08 19:45:41 +00:00
|
|
|
printf("\n");
|
2015-10-26 14:54:21 +00:00
|
|
|
}
|
|
|
|
|
2018-07-09 11:17:44 +00:00
|
|
|
int have_flag(int argc, char** argv, char *flag) {
|
|
|
|
char** argm = argv + argc;
|
|
|
|
argv++;
|
2022-03-08 19:45:41 +00:00
|
|
|
while (argv != argm) {
|
2018-07-09 11:17:44 +00:00
|
|
|
if (strcmp(*argv, flag) == 0) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-03-08 19:45:41 +00:00
|
|
|
/* takes an array containing the arguments that the user is allowed to enter on the command-line
|
|
|
|
returns:
|
|
|
|
- 1 if the user entered an invalid argument
|
|
|
|
- 0 if all the user entered arguments are valid */
|
|
|
|
int have_invalid_args(int argc, char** argv, char** valid_args, size_t n) {
|
|
|
|
size_t i;
|
|
|
|
int found_valid;
|
|
|
|
char** argm = argv + argc;
|
|
|
|
argv++;
|
|
|
|
|
|
|
|
while (argv != argm) {
|
|
|
|
found_valid = 0;
|
|
|
|
for (i = 0; i < n; i++) {
|
|
|
|
if (strcmp(*argv, valid_args[i]) == 0) {
|
|
|
|
found_valid = 1; /* user entered a valid arg from the list */
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found_valid == 0) {
|
|
|
|
return 1; /* invalid arg found */
|
|
|
|
}
|
|
|
|
argv++;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-08-26 17:35:27 +00:00
|
|
|
int get_iters(int default_iters) {
|
|
|
|
char* env = getenv("SECP256K1_BENCH_ITERS");
|
|
|
|
if (env) {
|
|
|
|
return strtol(env, NULL, 0);
|
|
|
|
} else {
|
|
|
|
return default_iters;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-03-08 19:45:41 +00:00
|
|
|
void print_output_table_header_row(void) {
|
|
|
|
char* bench_str = "Benchmark"; /* left justified */
|
|
|
|
char* min_str = " Min(us) "; /* center alignment */
|
|
|
|
char* avg_str = " Avg(us) ";
|
|
|
|
char* max_str = " Max(us) ";
|
|
|
|
printf("%-30s,%-15s,%-15s,%-15s\n", bench_str, min_str, avg_str, max_str);
|
|
|
|
printf("\n");
|
|
|
|
}
|
|
|
|
|
2018-07-09 11:17:44 +00:00
|
|
|
#endif /* SECP256K1_BENCH_H */
|