summaryrefslogtreecommitdiffstats
path: root/test/bench.c
diff options
context:
space:
mode:
authorEthan Werner <mail@ethanwerner.com>2026-07-01 09:42:39 +0400
committerEthan Werner <mail@ethanwerner.com>2026-07-01 09:42:39 +0400
commit07e18043145f3d91c8ea7ec3ad41b3c905585277 (patch)
tree2bdeae46973f4bdfce263679a4008ac768011f28 /test/bench.c
initial commit: ts time series analysis library v0.1.0
- 354 financial and mathematical time-series indicators - Uniform C11 API with consistent function signatures - 349 passing tests with -Werror - Static and shared library builds - pkg-config integration - Python bindings - Fuzzing and sanitizer support - Security hardening flags
Diffstat (limited to 'test/bench.c')
-rw-r--r--test/bench.c204
1 files changed, 204 insertions, 0 deletions
diff --git a/test/bench.c b/test/bench.c
new file mode 100644
index 0000000..83330aa
--- /dev/null
+++ b/test/bench.c
@@ -0,0 +1,204 @@
+#define TS_IMPLEMENTATION
+#include "ts.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#define BENCH_N 10000
+#define BENCH_ITER 100
+
+typedef struct { uint_t k; fp_t std_mult; } bb_params_t;
+typedef struct { fp_t fast_k; fp_t slow_k; fp_t signal_k; } macd_params_t;
+typedef struct { fp_t Q; fp_t R; } kalman_params_t;
+
+static fp_t bench_input[BENCH_N];
+static fp_t bench_output[BENCH_N];
+static fp_t bench_ohlc[4][BENCH_N];
+static fp_t bench_output_multi[4][BENCH_N];
+
+static double elapsed_ms(struct timespec *start, struct timespec *end)
+{
+ return (end->tv_sec - start->tv_sec) * 1000.0 + (end->tv_nsec - start->tv_nsec) / 1000000.0;
+}
+
+int main(void)
+{
+ ts_fill(bench_input, BENCH_N, 0, BENCH_N);
+
+ for (uint_t c = 0; c < 4; c++) {
+ ts_fill(bench_ohlc[c], BENCH_N, 100 + c, 200 + c);
+ }
+
+ printf("Benchmark: n=%d, iterations=%d\n", BENCH_N, BENCH_ITER);
+ printf("--------------------------------------------------\n");
+
+ struct timespec start, end;
+
+ /* ts_average */
+ {
+ uint_t k = 14;
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_average(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_average", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_rsi */
+ {
+ uint_t k = 14;
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_rsi(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_rsi", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_deviation_standard */
+ {
+ uint_t k = 14;
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_deviation_standard(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_deviation_standard", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_average_exponential */
+ {
+ uint_t k = 14;
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_average_exponential(y, 1, x, 1, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_average_exponential", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_bollinger_bands */
+ {
+ bb_params_t c = { .k = 20, .std_mult = 2.0 };
+ fp_t * const y[3] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2] };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_bollinger_bands(y, 3, x, 1, BENCH_N, (ts_constant_t *)&c);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_bollinger_bands", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_macd */
+ {
+ macd_params_t c = { .fast_k = 12, .slow_k = 26, .signal_k = 9 };
+ fp_t * const y[3] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2] };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_macd(y, 3, x, 1, BENCH_N, (ts_constant_t *)&c);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_macd", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_atr */
+ {
+ uint_t k = 14;
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[4] = { bench_ohlc[0], bench_ohlc[1], bench_ohlc[2], bench_ohlc[3] };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_atr(y, 1, x, 4, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_atr", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_adx */
+ {
+ uint_t k = 14;
+ fp_t * const y[4] = { bench_output_multi[0], bench_output_multi[1], bench_output_multi[2], bench_output_multi[3] };
+ fp_t const * const x[4] = { bench_ohlc[0], bench_ohlc[1], bench_ohlc[2], bench_ohlc[3] };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_adx(y, 4, x, 4, BENCH_N, (ts_constant_t *)&k);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_adx", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_kalman_filter */
+ {
+ kalman_params_t c = { .Q = 0.01, .R = 0.05 };
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_kalman_filter(y, 1, x, 1, BENCH_N, (ts_constant_t *)&c);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_kalman_filter", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_absolute_value */
+ {
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_absolute_value(y, 1, x, 1, BENCH_N, NULL);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_absolute_value", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_sine */
+ {
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[1] = { bench_input };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_sine(y, 1, x, 1, BENCH_N, NULL);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_sine", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ /* ts_addition */
+ {
+ fp_t * const y[1] = { bench_output };
+ fp_t const * const x[2] = { bench_input, bench_ohlc[0] };
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (uint_t i = 0; i < BENCH_ITER; i++) {
+ (void)ts_addition(y, 1, x, 2, BENCH_N, NULL);
+ }
+ clock_gettime(CLOCK_MONOTONIC, &end);
+ double ms = elapsed_ms(&start, &end);
+ printf("%-40s %8.2f ms (%.0f ns/call)\n", "ts_addition", ms, ms * 1000000.0 / BENCH_ITER);
+ }
+
+ return 0;
+}