Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,8 @@ Benchmark
------------
If configured with `--enable-benchmark` (which is the default), binaries for benchmarking the libsecp256k1 functions will be present in the root directory after the build.

For reliable benchmarks, it is strongly recommended to pin the process to a dedicated CPU core and to disable CPU frequency scaling.

To print the benchmark result to the command line:

$ ./bench_name
Expand Down
3 changes: 3 additions & 0 deletions src/bench.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/

#define _POSIX_C_SOURCE 200112L /* for clock_gettime() */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -252,6 +254,7 @@ int main(int argc, char** argv) {
data.pubkeylen = 33;
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, SECP256K1_EC_COMPRESSED) == 1);

print_clock_info();
print_output_table_header_row();
if (d || have_flag(argc, argv, "ecdsa") || have_flag(argc, argv, "verify") || have_flag(argc, argv, "ecdsa_verify")) run_benchmark("ecdsa_verify", bench_verify, NULL, NULL, &data, 10, iters);

Expand Down
62 changes: 42 additions & 20 deletions src/bench.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,30 +7,44 @@
#ifndef SECP256K1_BENCH_H
#define SECP256K1_BENCH_H

#if defined(_WIN32)
# include <windows.h>
#else /* POSIX */
# include <time.h>
#endif

#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>

#if (defined(_MSC_VER) && _MSC_VER >= 1900)
# include <time.h>
#else
# include <sys/time.h>
#endif
static int64_t gettime_us(void) {
#if defined(_WIN32)

LARGE_INTEGER freq, counter;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&counter);
return (int64_t)(counter.QuadPart * 1000000 / freq.QuadPart);

#else /* POSIX */

# if defined(CLOCK_PROCESS_CPUTIME_ID)
/* In theory, CLOCK_PROCESS_CPUTIME_ID is only useful if the process is locked to a core,
* see `man clock_gettime` on Linux. In practice, modern CPUs have synchronized TSCs which
* address this issue, see https://docs.amd.com/r/en-US/ug1586-onload-user/Timer-TSC-Stability . */
const clockid_t clock_type = CLOCK_PROCESS_CPUTIME_ID;
# elif defined(CLOCK_MONOTONIC)
/* fallback to wall-clock timer */
const clockid_t clock_type = CLOCK_MONOTONIC;
# else
/* fallback to less precise wall-clock timer */
const clockid_t clock_type = CLOCK_REALTIME;
# endif

struct timespec ts;
clock_gettime(clock_type, &ts);
return (int64_t)ts.tv_sec * 1000000 + ts.tv_nsec / 1000;

static int64_t gettime_i64(void) {
#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(EXIT_FAILURE);
}
return (int64_t)tv.tv_nsec / 1000 + (int64_t)tv.tv_sec * 1000000LL;
#else
struct timeval tv;
gettimeofday(&tv, NULL);
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
#endif
}

Expand Down Expand Up @@ -105,9 +119,9 @@ static void run_benchmark(char *name, void (*benchmark)(void*, int), void (*setu
if (setup != NULL) {
setup(data);
}
begin = gettime_i64();
begin = gettime_us();
benchmark(data, iter);
total = gettime_i64() - begin;
total = gettime_us() - begin;
if (teardown != NULL) {
teardown(data, iter);
}
Expand Down Expand Up @@ -176,6 +190,14 @@ static int get_iters(int default_iters) {
}
}

static void print_clock_info(void) {
#if defined(CLOCK_PROCESS_CPUTIME_ID)
printf("INFO: Using per-process CPU timer\n\n");
#else
printf("WARN: using Wall-Clock timer, results are highly influenced by other running processes\n\n");
#endif
}

static void print_output_table_header_row(void) {
char* bench_str = "Benchmark"; /* left justified */
char* min_str = " Min(us) "; /* center alignment */
Expand Down
5 changes: 4 additions & 1 deletion src/bench_ecmult.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/

#define _POSIX_C_SOURCE 200112L /* for clock_gettime() */

#include <stdio.h>
#include <stdlib.h>

Expand Down Expand Up @@ -362,7 +365,7 @@ int main(int argc, char **argv) {
}
secp256k1_ge_set_all_gej_var(data.pubkeys, data.pubkeys_gej, POINTS);


print_clock_info();
print_output_table_header_row();
/* Initialize offset1 and offset2 */
hash_into_offset(&data, 0);
Expand Down
4 changes: 4 additions & 0 deletions src/bench_internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@
* Distributed under the MIT software license, see the accompanying *
* file COPYING or https://www.opensource.org/licenses/mit-license.php.*
***********************************************************************/

#define _POSIX_C_SOURCE 200112L /* for clock_gettime() */

#include <stdio.h>
#include <stdlib.h>

Expand Down Expand Up @@ -398,6 +401,7 @@ int main(int argc, char **argv) {
}
}

print_clock_info();
print_output_table_header_row();

if (d || have_flag(argc, argv, "scalar") || have_flag(argc, argv, "half")) run_benchmark("scalar_half", bench_scalar_half, bench_setup, NULL, &data, 10, iters*100);
Expand Down