From bf0d77d7d448e964e9716d5af67c48f3d014f090 Mon Sep 17 00:00:00 2001 From: Filip Wandzio Date: Sun, 1 Mar 2026 01:03:39 +0100 Subject: Scaffold basic project tree, implement benchmarking logic Implement unit testing guardian --- benchmark/benchmark.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 benchmark/benchmark.c (limited to 'benchmark/benchmark.c') diff --git a/benchmark/benchmark.c b/benchmark/benchmark.c new file mode 100644 index 0000000..2fe3163 --- /dev/null +++ b/benchmark/benchmark.c @@ -0,0 +1,101 @@ +#define _POSIX_C_SOURCE 199309L +#include "benchmark.h" +#include "resource_usage.h" +#include + +#if defined(_WIN32) || defined(_WIN64) +#include +#else +#include +#endif + +/* ANSI color codes */ +const char* COLOR_RED = "\033[31m"; +const char* COLOR_GREEN = "\033[32m"; +const char* COLOR_YELLOW = "\033[33m"; +const char* COLOR_RESET = "\033[0m"; + +/* Maximum allowed average execution time per call in milliseconds */ +const double MAX_ALLOWED_MS = 0.05; + +/* Default benchmark iteration counts */ +const size_t DEFAULT_BENCHMARKS = 100; +const size_t ITERATIONS_FAST = 1000; +const size_t ITERATIONS_SLOW = 10; + +/* Volatile sink to prevent compiler optimizations removing the function call */ +static volatile int sink; + +/** + * @brief Cross-platform monotonic time in milliseconds + */ +static double now_ms(void) +{ +#if defined(_WIN32) || defined(_WIN64) + LARGE_INTEGER freq, counter; + QueryPerformanceFrequency(&freq); + QueryPerformanceCounter(&counter); + return (double)counter.QuadPart * 1000.0 / (double)freq.QuadPart; +#else + struct timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + return ts.tv_sec * 1000.0 + ts.tv_nsec / 1e6; +#endif +} + +double benchmark_func(const function_to_benchmark func, + const char* arg, + size_t benchmarks) +{ + if (!func) + return 0.0; + if (benchmarks == 0) + benchmarks = DEFAULT_BENCHMARKS; + size_t warmup = benchmarks / 10; + if (warmup > 1000) + warmup = 1000; + for (size_t i = 0; i < warmup; ++i) + sink = func(arg); + const double start = now_ms(); + for (size_t i = 0; i < benchmarks; ++i) + sink = func(arg); + const double end = now_ms(); + return (end - start) / benchmarks; +} + +void report_result(const char* test_name, + const int passed, + const double avg_ms, + const double max_allowed_ms) +{ + const int is_pass = passed && (avg_ms <= max_allowed_ms); + const char* status_color = is_pass ? COLOR_GREEN : COLOR_RED; + const char* status_text = is_pass ? "PASS" : "FAIL"; + + if (!is_pass && avg_ms > max_allowed_ms) + status_text = "SLOW"; + + printf("[avg %.6f ms] %s%s: %s%s\n", + avg_ms, + status_color, + status_text, + test_name, + COLOR_RESET); + + if (!is_pass && avg_ms > max_allowed_ms) { + printf(" %sReason:%s exceeded %.3f ms limit\n", + COLOR_YELLOW, + COLOR_RESET, + max_allowed_ms); + } +} + +void benchmark_func_with_resources(const function_to_benchmark func, + const char* arg, + const size_t benchmarks, + const char* label) +{ + const double avg_ms = benchmark_func(func, arg, benchmarks); + printf("[Benchmark] %s avg %.6f ms\n", label, avg_ms); + print_resource_usage(label); +} -- cgit v1.2.3