Skip to content

Commit

Permalink
Convert bench.h to fixed-point math
Browse files Browse the repository at this point in the history
- Use 64-bit integer microsecond timestamps
- Use fixed-point math for formatting numbers

Then, remove "except in benchmarks" exception from `README.md`.
  • Loading branch information
laanwj committed Nov 5, 2019
1 parent 0c774d8 commit 8a7dea1
Show file tree
Hide file tree
Showing 2 changed files with 62 additions and 21 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Implementation details
* Extensive testing infrastructure.
* Structured to facilitate review and analysis.
* Intended to be portable to any system with a C89 compiler and uint64_t support.
* No use of floating types, except in benchmarks.
* No use of floating types.
* Expose only higher level interfaces to minimize the API surface and improve application security. ("Be difficult to use insecurely.")
* Field operations
* Optimized implementation of arithmetic modulo the curve's field size (2^256 - 0x1000003D1).
Expand Down
81 changes: 61 additions & 20 deletions src/bench.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,41 +9,82 @@

#include <stdio.h>
#include <string.h>
#include <math.h>
#include "sys/time.h"

static double gettimedouble(void) {
static int64_t gettime_i64(void) {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_usec * 0.000001 + tv.tv_sec;
return (int64_t)tv.tv_usec + (int64_t)tv.tv_sec * 1000000LL;
}

void print_number(double x) {
double y = x;
int c = 0;
if (y < 0.0) {
y = -y;
#define FP_EXP (6)
#define FP_MULT (1000000LL)

/* Format fixed point number. */
void print_number(const int64_t x) {
int64_t x_abs, y;
int c, i, rounding;
size_t ptr;
char buffer[30];

if (x == INT64_MIN) {
/* Prevent UB. */
printf("ERR");
return;
}
while (y > 0 && y < 100.0) {
y *= 10.0;
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;
c++;
}
printf("%.*f", c, x);

/* 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;
if (c != 0) {
for (i = 0; i < c; ++i) {
buffer[--ptr] = '0' + (y % 10);
y /= 10;
}
buffer[--ptr] = '.';
}
do {
buffer[--ptr] = '0' + (y % 10);
y /= 10;
} while (y != 0);
if (x < 0) {
buffer[--ptr] = '-';
}
printf("%s", &buffer[ptr]);
}

void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), void (*teardown)(void*), void* data, int count, int iter) {
int i;
double min = HUGE_VAL;
double sum = 0.0;
double max = 0.0;
int64_t min = INT64_MAX;
int64_t sum = 0;
int64_t max = 0;
for (i = 0; i < count; i++) {
double begin, total;
int64_t begin, total;
if (setup != NULL) {
setup(data);
}
begin = gettimedouble();
begin = gettime_i64();
benchmark(data);
total = gettimedouble() - begin;
total = gettime_i64() - begin;
if (teardown != NULL) {
teardown(data);
}
Expand All @@ -56,11 +97,11 @@ void run_benchmark(char *name, void (*benchmark)(void*), void (*setup)(void*), v
sum += total;
}
printf("%s: min ", name);
print_number(min * 1000000.0 / iter);
print_number(min * FP_MULT / iter);
printf("us / avg ");
print_number((sum / count) * 1000000.0 / iter);
print_number(((sum * FP_MULT) / count) / iter);
printf("us / max ");
print_number(max * 1000000.0 / iter);
print_number(max * FP_MULT / iter);
printf("us\n");
}

Expand Down

0 comments on commit 8a7dea1

Please sign in to comment.