Create benchmarking library

This commit is contained in:
Camden Dixie O'Brien 2024-11-10 13:16:10 +00:00
parent 15a6195bf0
commit e4d3b08bf2
4 changed files with 152 additions and 0 deletions

View File

@ -19,3 +19,4 @@ endfunction()
add_subdirectory(lib)
add_subdirectory(tests)
add_subdirectory(demo)
add_subdirectory(benchmarks)

16
benchmarks/CMakeLists.txt Normal file
View File

@ -0,0 +1,16 @@
add_library(benchmarking benchmarking.c)
set_default_target_options(benchmarking)
target_include_directories(benchmarking PUBLIC include)
function(add_benchmark_suite source)
string(REGEX REPLACE ".c$" "" name ${source})
add_executable(${name} ${source})
set_default_target_options(${name})
target_link_libraries(${name} PRIVATE lib benchmarking m)
endfunction()
function(add_benchmark_suites)
foreach(source ${ARGN})
add_benchmark_suite(${source})
endforeach()
endfunction()

85
benchmarks/benchmarking.c Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (c) Camden Dixie O'Brien
* SPDX-License-Identifier: AGPL-3.0-only
*/
#include "benchmarking.h"
#include <assert.h>
#include <math.h>
#include <stdio.h>
#define SWAP(x, y) \
do { \
const double tmp = x; \
x = y; \
y = tmp; \
} while (0)
clock_t benchmark_start, benchmark_end;
static void sort(double *xs, int n)
{
if (n <= 0)
return;
const double pivot = xs[(n - 1) / 2];
int lt = 0;
int eq = 0;
int gt = n - 1;
while (eq <= gt) {
if (xs[eq] < pivot) {
SWAP(xs[eq], xs[lt]);
++lt;
++eq;
} else if (xs[eq] > pivot) {
SWAP(xs[eq], xs[gt]);
--gt;
} else {
++eq;
}
}
sort(xs, lt);
sort(xs + gt + 1, n - (gt + 1));
}
void benchmark_summarise(double *res, int reps, benchmark_summary_t *out)
{
assert(reps > 0);
sort(res, reps);
const double median = res[reps / 2];
double sum = 0;
for (int i = 0; i < reps; ++i)
sum += res[i];
const double mean = sum / reps;
double diff_sum = 0;
for (int i = 0; i < reps; ++i)
diff_sum += pow(res[i] - mean, 2);
const double variance = diff_sum / (reps - 1);
out->reps = reps;
out->total = sum;
out->median = median;
out->mean = mean;
out->min = res[0];
out->max = res[reps - 1];
out->stddev = sqrt(variance);
}
void benchmark_print_header(void)
{
printf(
"%-12s %13s %13s %13s %13s %12s\n", "benchmark", "median (µs)",
"mean (µs)", "min (µs)", "max (µs)", "stddev");
}
void benchmark_print(const char *name, const benchmark_summary_t *s)
{
printf(
"%-12s %12.2f %12.2f %12.2f %12.2f %12.2f\n", name, s->median,
s->mean, s->min, s->max, s->stddev);
}

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) Camden Dixie O'Brien
* SPDX-License-Identifier: AGPL-3.0-only
*/
#ifndef BENCHMARKING_H
#define BENCHMARKING_H
#include <time.h>
typedef struct {
int reps;
double total, median, mean, min, max, stddev;
} benchmark_summary_t;
#define CLOCK_MICROS(c) (1000000 * (double)c / CLOCKS_PER_SEC)
#define BENCHMARKING_BEGIN() benchmark_print_header()
#define BENCHMARKING_END() 0
#define START_CLOCK() \
do { \
benchmark_start = clock(); \
} while (0)
#define STOP_CLOCK() \
do { \
benchmark_end = clock(); \
} while (0)
#define RUN_BENCHMARK(reps, name, fn, ...) \
do { \
double res[reps]; \
for (int i = 0; i < reps; ++i) { \
fn(__VA_ARGS__); \
res[i] = CLOCK_MICROS(benchmark_end) \
- CLOCK_MICROS(benchmark_start); \
} \
benchmark_summary_t summary; \
benchmark_summarise(res, reps, &summary); \
benchmark_print(name, &summary); \
} while (0)
extern clock_t benchmark_start, benchmark_end;
void benchmark_summarise(double *res, int reps, benchmark_summary_t *out);
void benchmark_print_header(void);
void benchmark_print(const char *name, const benchmark_summary_t *summary);
#endif