From cb518b00efc8fe29df713e652450e90448340c29 Mon Sep 17 00:00:00 2001 From: Mitya Selivanov Date: Thu, 3 Oct 2024 08:32:25 +0200 Subject: Refactor --- examples/test.c | 989 -------------------------------------------------------- 1 file changed, 989 deletions(-) delete mode 100644 examples/test.c (limited to 'examples/test.c') diff --git a/examples/test.c b/examples/test.c deleted file mode 100644 index c5e17bd..0000000 --- a/examples/test.c +++ /dev/null @@ -1,989 +0,0 @@ -// ================================================================ -// -// test.c -// -// Unit-testing and microbenchmarks modular library for C -// -// ---------------------------------------------------------------- -// -// Optional settings -// -// - MAX_NUM_TESTS -// - MAX_NUM_TEST_ASSECTIONS -// - MAX_NUM_BENCHS -// - MAX_NUM_BENCH_REPEATS -// - MAX_NUM_BENCH_CYCLES -// - NUM_BENCH_REPEATS_DEFAULT_1 -// - NUM_BENCH_REPEATS_DEFAULT_2 -// -// ---------------------------------------------------------------- -// -// Usage -// -// - Define a unique TEST_FILE for each file to avoid name -// collisions. -// -// Example -// -// // foo.test.c -// #define TEST_FILE foo // This is required if you want to -// // use multiple test files. -// #define TEST_HEADER // Do not include the implementation. -// #include "test.c" -// TEST("foo") { -// REQUIRE(1); -// REQUIRE_EQ(2 + 2, 4); -// } -// -// // main.c -// #include "test.c" -// int main(int argc, char **argv) { -// return run_tests(argc, argv); -// } -// -// ---------------------------------------------------------------- -// -// (C) 2024 Mitya Selivanov , MIT License -// -// ================================================================ - -#ifndef TYPES_HEADER_GUARD_ -#define TYPES_HEADER_GUARD_ - -typedef signed char i8; -typedef signed short i16; -typedef signed i32; -typedef signed long long i64; -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned u32; -typedef unsigned long long u64; -typedef char c8; -typedef int c32; -typedef signed char b8; -typedef float f32; -typedef double f64; - -#endif // TYPES_HEADER_GUARD_ - -// ================================================================ - -#ifndef TEST_HEADER_GUARD_ -#define TEST_HEADER_GUARD_ - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#ifdef __GNUC__ -# pragma GCC diagnostic ignored "-Wunused-value" -# pragma GCC diagnostic ignored "-Wunused-parameter" -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include - -#ifndef TEST_FILE -#define TEST_FILE test -#endif - -#ifndef MAX_NUM_TESTS -#define MAX_NUM_TESTS 0x1000 -#endif - -#ifndef MAX_NUM_TEST_ASSECTIONS -#define MAX_NUM_TEST_ASSECTIONS 0x50 -#endif - -#ifndef MAX_NUM_BENCHS -#define MAX_NUM_BENCHS 200 -#endif - -#ifndef MAX_NUM_BENCH_REPEATS -#define MAX_NUM_BENCH_REPEATS 4000 -#endif - -#ifndef MAX_NUM_BENCH_CYCLES -#define MAX_NUM_BENCH_CYCLES 40 -#endif - -#ifndef NUM_BENCH_REPEATS_DEFAULT_1 -#define NUM_BENCH_REPEATS_DEFAULT_1 40 -#endif - -#ifndef NUM_BENCH_REPEATS_DEFAULT_2 -#define NUM_BENCH_REPEATS_DEFAULT_2 400 -#endif - -typedef void (*test_report_fn)(i32 test_index, i32 line, i64 value, i64 expected); -typedef void (*test_run_fn) (i32 test_index_, test_report_fn test_report_fn_); - -typedef struct { - c8 const *test_name; - c8 const *test_file; - test_run_fn test_fn; - i32 assertions; - i32 line [MAX_NUM_TEST_ASSECTIONS]; - i32 status [MAX_NUM_TEST_ASSECTIONS]; - i64 value [MAX_NUM_TEST_ASSECTIONS]; - i64 expected[MAX_NUM_TEST_ASSECTIONS]; - i32 signal; -} Test_Case; - -typedef struct { - i32 size; - Test_Case v[MAX_NUM_TESTS]; -} Tests_List; - -extern Tests_List tests_list; - -#define TEST_CONCAT4_(a, b, c, d) a##b##c##d -#define TEST_CONCAT3_(a, b, c) TEST_CONCAT4_(a, b, _, c) - -#ifdef __cplusplus -# define TEST_ON_START_(f) \ - static void f(void); \ - static i32 TEST_CONCAT3_(_test_init_, __LINE__, f) = (f(), 0); \ - static void f(void) -#else -# ifdef _MSC_VER -# pragma section(".CRT$XCU", read) -# define TEST_ON_START_2_(f, p) \ - static void f(void); \ - __declspec(allocate(".CRT$XCU")) void (*f##_)(void) = f; \ - __pragma(comment(linker, "/include:" p #f "_")) static void f(void) -# ifdef _WIN64 -# define TEST_ON_START_(f) TEST_ON_START_2_(f, "") -# else -# define TEST_ON_START_(f) TEST_ON_START_2_(f, "_") -# endif -# else -# define TEST_ON_START_(f) \ - static void f(void) __attribute__((constructor)); \ - static void f(void) -# endif -#endif - -void test_register(c8 const *name, c8 const *file, test_run_fn fn); - -#define TEST(name) \ - static void TEST_CONCAT3_(test_run_, TEST_FILE, __LINE__)(i32, test_report_fn); \ - TEST_ON_START_(TEST_CONCAT3_(test_case_, TEST_FILE, __LINE__)) { \ - test_register(name, __FILE__, TEST_CONCAT3_(test_run_, TEST_FILE, __LINE__)); \ - } \ - static void TEST_CONCAT3_(test_run_, TEST_FILE, __LINE__) \ - (i32 test_index_, test_report_fn test_report_fn_) - -#define REQUIRE(...) test_report_fn_(test_index_, __LINE__, (__VA_ARGS__), 1) -#define REQUIRE_EQ(...) test_report_fn_(test_index_, __LINE__, __VA_ARGS__) - -i32 run_tests(i32 argc, c8 **argv); - -// ================================================================ - -typedef void (*bench_set_repeats_limit_fn)(i32 bench_index, i32 repeats_limit); -typedef i32 (*bench_loop_fn) (i32 bench_index); -typedef void (*bench_begin_fn) (i32 bench_index); -typedef void (*bench_end_fn) (i32 bench_index); - -typedef void (*bench_run_fn)( - i32 bench_index_, - bench_set_repeats_limit_fn bench_set_repeats_limit_, - bench_loop_fn bench_loop_, - bench_begin_fn bench_begin_, - bench_end_fn bench_end_ -); - -typedef struct { - c8 const *bench_name; - c8 const *bench_file; - bench_run_fn bench_fn; - i64 sec [MAX_NUM_BENCH_REPEATS]; - i32 nsec [MAX_NUM_BENCH_REPEATS]; - i64 duration_nsec [MAX_NUM_BENCH_REPEATS]; - i64 duration_sorted_nsec[MAX_NUM_BENCH_REPEATS]; - i32 repeats; - i32 cycles_size; - i32 cycles[MAX_NUM_BENCH_CYCLES]; - i32 cycle; - i32 signal; - i32 ready; -} Benchmark; - -typedef struct { - i32 size; - Benchmark v[MAX_NUM_BENCHS]; -} Benchs_List; - -extern Benchs_List benchs_list; - -void bench_register(c8 const *name, c8 const *file, bench_run_fn fn); - -#define BENCHMARK(name) \ - static void TEST_CONCAT3_(bench_run_, TEST_FILE, __LINE__) \ - (i32, bench_set_repeats_limit_fn, bench_loop_fn, bench_begin_fn, bench_end_fn); \ - TEST_ON_START_(TEST_CONCAT3_(benchmark_, TEST_FILE, __LINE__)) { \ - bench_register(name, __FILE__, TEST_CONCAT3_(bench_run_, TEST_FILE, __LINE__)); \ - } \ - static void TEST_CONCAT3_(bench_run_, TEST_FILE, __LINE__)( \ - i32 bench_index_, \ - bench_set_repeats_limit_fn bench_set_repeats_limit_, \ - bench_loop_fn bench_loop_, \ - bench_begin_fn bench_begin_, \ - bench_end_fn bench_end_ \ - ) - -#define BENCHMARK_REPEAT(repeats_limit_) \ - bench_set_repeats_limit_(bench_index_, repeats_limit_) - -#define BENCHMARK_BEGIN \ - while (bench_loop_(bench_index_)) { \ - bench_begin_(bench_index_); { - -#define BENCHMARK_END \ - } bench_end_(bench_index_); } - -// FIXME -// Does this work reliably? -// -#define DO_NOT_OPTIMIZE(x) \ - do { \ - volatile void *bench_ptr_ = &(x); \ - (void) bench_ptr_; \ - } while (0) - -i32 run_benchmarks(i32 argc, c8 **argv); - -#ifdef __cplusplus -} -#endif - -#endif // TEST_HEADER_GUARD_ - -// ================================================================ -// -// Implementation -// -// ================================================================ - -#ifndef TEST_HEADER -#ifndef TEST_IMPL_GUARD_ -#define TEST_IMPL_GUARD_ - -#include -#include -#include -#include -#include -#include - -enum { - white_, - blue_, - light_, - yellow_, - red_, - green_ -}; - -static c8 const *color_codes_[] = { - "\x1b[38m", "\x1b[34m", - "\x1b[37m", "\x1b[33m", - "\x1b[31m", "\x1b[32m" -}; - -static i32 print_color_(i32 c) { - return printf("%s", color_codes_[c]); -} - -static i32 signums_[] = { SIGINT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGTERM }; - -static c8 const *signames_[64]; - -static void signames_init_(void) { - memset(signames_, 0, sizeof signames_); - signames_[SIGINT] = "Interactive attention signal"; - signames_[SIGILL] = "Illegal instruction"; - signames_[SIGABRT] = "Abnormal termination"; - signames_[SIGFPE] = "Erroneous arithmetic operation"; - signames_[SIGSEGV] = "Invalid access to storage"; - signames_[SIGTERM] = "Termination request"; -} - -Tests_List tests_list = { 0 }; - -static void report_(i32 i, i32 line, i64 value, i64 expected) { - i32 n = tests_list.v[i].assertions++; - - if (n >= MAX_NUM_TEST_ASSECTIONS) - return; - - tests_list.v[i].line[n] = line; - tests_list.v[i].status[n] = value == expected; - tests_list.v[i].value[n] = value; - tests_list.v[i].expected[n] = expected; -} - -static i64 ns_to_ms(i64 ns) { - return (ns + 500000) / 1000000; -} - -static i64 sec_to_ms(int64_t sec) { - return 1000 * sec; -} - -void test_register(c8 const *name, c8 const *file, test_run_fn fn) { - i32 n = tests_list.size++; - if (n < MAX_NUM_TESTS) { - tests_list.v[n].test_fn = fn; - tests_list.v[n].test_name = name; - tests_list.v[n].test_file = file; - tests_list.v[n].assertions = 0; - } -} - -static jmp_buf test_restore_execution; - -static void test_handle_signal(i32 signum) { - longjmp(test_restore_execution, signum); -} - -static void test_setup_signals() { - for (u32 i = 0; i < sizeof signums_ / sizeof *signums_; i++) - signal(signums_[i], test_handle_signal); -} - -static i32 run_test_(volatile i32 i) { - i32 signum = setjmp(test_restore_execution); - - if (signum != 0) { - tests_list.v[i].signal = signum; - return 0; - } - - tests_list.v[i].test_fn(i, report_); - return 1; -} - -i32 run_tests(i32 argc, c8 **argv) { - signames_init_(); - - i32 success_count = 0; - i32 fail_assertion_count = 0; - i32 total_assertion_count = 0; - i32 status = 0; - i32 quiet = 0; - i32 no_color = 0; - i32 line_width = 20; - i32 carriage_return = 1; - - i32 i, j; - - c8 const *specific_test = NULL; - - test_setup_signals(); - - for (i = 0; i < argc; i++) - if (strcmp("--no-term-color", argv[i]) == 0) - no_color = 1; - else if (strcmp("--no-carriage-return", argv[i]) == 0) - carriage_return = 0; - else if (strcmp("--quiet", argv[i]) == 0) - quiet = 1; - else if (strcmp("--match", argv[i]) == 0) - specific_test = argv[++i]; - - quiet && (no_color = 1); - - if (specific_test != NULL) { - no_color || print_color_(light_); - quiet || printf("Run tests matching "); - no_color || print_color_(white_); - quiet || printf("*%s*", specific_test); - no_color || print_color_(light_); - quiet || printf("\n\n"); - } - - c8 const *file = NULL; - i64 file_root = -1; - i32 tests_total = 0; - - for (i = 0; i < tests_list.size && i < MAX_NUM_TESTS; - i++) { - if (specific_test != NULL && - strstr(tests_list.v[i].test_name, specific_test) == NULL) - continue; - tests_total++; - i32 l = 2 + (int) strlen(tests_list.v[i].test_name); - if (line_width < l) - line_width = l; - } - - if (tests_total > 0) { - c8 const *s = tests_list.v[0].test_file; - - for (j = 1; j < tests_list.size && j < MAX_NUM_TESTS; - j++) { - if (specific_test != NULL && - strstr(tests_list.v[j].test_name, specific_test) == - NULL) - continue; - if (strcmp(s, tests_list.v[j].test_file) == 0) - continue; - i32 k = 0; - for (; - s[k] != '\0' && tests_list.v[j].test_file[k] != '\0' && - s[k] == tests_list.v[j].test_file[k]; - k++) { } - if (file_root == -1 || file_root > k) - file_root = k; - } - - if (file_root == -1) { - for (i = 0; s[i] != '\0'; i++) - if (s[i] == '/' || s[i] == '\\') - file_root = i + 1; - } - } - - for (i = 0; i < tests_list.size && i < MAX_NUM_TESTS; i++) { - if (specific_test != NULL && strstr(tests_list.v[i].test_name, specific_test) == NULL) - continue; - if (file == NULL || strcmp(file, tests_list.v[i].test_file) != 0) { - if (file != NULL) - quiet || printf("\n"); - file = tests_list.v[i].test_file; - no_color || print_color_(blue_); - quiet || printf("* "); - no_color || print_color_(white_); - quiet || printf("%s\n", file + file_root); - } - - !carriage_return || no_color || print_color_(yellow_); - carriage_return || no_color || print_color_(light_); - quiet || printf("` %s ", tests_list.v[i].test_name); - !carriage_return || quiet || printf("\r"); - quiet || fflush(stdout); - - struct timespec begin, end; - timespec_get(&begin, TIME_UTC); - - i32 test_status = run_test_(i); - - timespec_get(&end, TIME_UTC); - i32 duration = (i32) (ns_to_ms(end.tv_nsec - begin.tv_nsec) + sec_to_ms(end.tv_sec - begin.tv_sec)); - - for (j = 0; j < tests_list.v[i].assertions && j < MAX_NUM_TEST_ASSECTIONS; j++) - if (tests_list.v[i].status[j] == 0) { - fail_assertion_count++; - test_status = 0; - } - - if (tests_list.v[i].assertions > MAX_NUM_TEST_ASSECTIONS) - test_status = 0; - - total_assertion_count += tests_list.v[i].assertions; - - !carriage_return || no_color || print_color_(light_); - !carriage_return || quiet || printf("` %s ", tests_list.v[i].test_name); - - i32 l = (i32) strlen(tests_list.v[i].test_name); - quiet || printf("%*c", line_width - l, ' '); - - if (test_status == 0) { - no_color || print_color_(red_); - quiet || printf("FAIL"); - no_color || print_color_(light_); - duration == 0 || quiet || printf(" %d ms", duration); - quiet || printf("\n"); - status = 1; - } else { - no_color || print_color_(green_); - quiet || printf("OK"); - no_color || print_color_(light_); - duration == 0 || quiet || printf(" %d ms", duration); - quiet || printf("\n"); - success_count++; - } - - quiet || fflush(stdout); - } - - no_color || print_color_(white_); - quiet || printf("\n%d of %d tests passed.\n", success_count, tests_total); - quiet || printf("%d of %d assertions passed.\n\n", total_assertion_count - fail_assertion_count, total_assertion_count); - no_color || print_color_(light_); - - if (!quiet && status != 0) { - i32 have_report_s = 0; - - for (i = 0; i < tests_list.size && i < MAX_NUM_TESTS; i++) { - if (specific_test != NULL && strstr(tests_list.v[i].test_name, specific_test) == NULL) - continue; - if (tests_list.v[i].signal != 0) { - i32 signum = tests_list.v[i].signal; - if (signum >= 0 && signum < (int) (sizeof signames_ / sizeof *signames_) && signames_[signum] != NULL) { - no_color || print_color_(light_); - printf("Signal \"%s\" (%d) for \"", signames_[signum], signum); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_name); - no_color || print_color_(light_); - printf("\" in \""); - no_color || print_color_(white_); - - printf("%s", tests_list.v[i].test_file + file_root); - no_color || print_color_(light_); - printf("\"!\n"); - } else { - no_color || print_color_(light_); - printf("Unknown signal (%d) for \"", signum); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_name); - no_color || print_color_(light_); - printf("\" in \""); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_file + file_root); - no_color || print_color_(light_); - printf("\"!\n"); - } - have_report_s = 1; - } - if (tests_list.v[i].assertions > - MAX_NUM_TEST_ASSECTIONS) { - no_color || print_color_(light_); - printf("Too many assertions for \""); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_name); - no_color || print_color_(light_); - printf("\" in \""); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_file + file_root); - no_color || print_color_(light_); - printf("\"!\n"); - have_report_s = 1; - } - } - - have_report_s && printf("\n"); - } - - if (!quiet && status != 0) { - for (i = 0; i < tests_list.size && i < MAX_NUM_TESTS; i++) { - if (specific_test != NULL && strstr(tests_list.v[i].test_name, specific_test) == NULL) - continue; - - if (tests_list.v[i].assertions <= MAX_NUM_TEST_ASSECTIONS) - for (j = 0; j < tests_list.v[i].assertions; j++) - if (!tests_list.v[i].status[j]) { - no_color || print_color_(light_); - printf("Assertion on line "); - no_color || print_color_(white_); - printf("%d", tests_list.v[i].line[j]); - no_color || print_color_(light_); - printf(" in \""); - no_color || print_color_(white_); - printf("%s", tests_list.v[i].test_file + file_root); - no_color || print_color_(light_); - printf("\" failed.\n"); - no_color || print_color_(red_); - printf(" -> "); - no_color || print_color_(light_); - printf("Got wrong value "); - no_color || print_color_(white_); - printf("%10lld", (i64) tests_list.v[i].value[j]); - no_color || print_color_(light_); - printf(" ("); - no_color || print_color_(white_); - printf("0x%08llx", (u64) tests_list.v[i].value[j]); - no_color || print_color_(light_); - printf(")\n"); - no_color || print_color_(green_); - printf(" -> "); - no_color || print_color_(light_); - printf("Expected value "); - no_color || print_color_(white_); - printf("%10lld", (i64) tests_list.v[i].expected[j]); - no_color || print_color_(light_); - printf(" ("); - no_color || print_color_(white_); - printf("0x%08llx", (u64) tests_list.v[i].expected[j]); - no_color || print_color_(light_); - printf(")\n\n"); - } - } - } - - if (tests_list.size > MAX_NUM_TESTS) { - no_color || print_color_(light_); - quiet || printf("Too many tests!\n\n"); - status = 1; - } - - if (status == 0) { - no_color || print_color_(green_); - quiet || printf("OK\n"); - } else { - no_color || print_color_(red_); - quiet || printf("FAILED\n"); - } - - no_color || print_color_(light_); - quiet || printf("\n"); - return status; -} - -// ================================================================ - -Benchs_List benchs_list = { 0 }; - -static void bench_set_repeats_limit(i32 i, i32 repeats_limit) { - if (benchs_list.v[i].ready) - return; - if (benchs_list.v[i].cycles_size >= MAX_NUM_BENCH_CYCLES) - return; - benchs_list.v[i].cycles[benchs_list.v[i].cycles_size] = repeats_limit; - benchs_list.v[i].cycles_size++; -} - -static i32 bench_loop(i32 i) { - if (!benchs_list.v[i].ready) - return 0; - return benchs_list.v[i].repeats < benchs_list.v[i].cycles[benchs_list.v[i].cycle]; -} - -static void bench_begin(i32 i) { - i32 n = benchs_list.v[i].repeats++; - - if (n >= MAX_NUM_BENCH_REPEATS) - return; - - struct timespec tv; - timespec_get(&tv, TIME_UTC); - - benchs_list.v[i].sec[n] = (int64_t) tv.tv_sec; - benchs_list.v[i].nsec[n] = (int64_t) tv.tv_nsec; -} - -static void bench_end(i32 i) { - i32 n = benchs_list.v[i].repeats - 1; - - if (n < 0 || n >= MAX_NUM_BENCH_REPEATS) - return; - - struct timespec tv; - timespec_get(&tv, TIME_UTC); - - i64 sec = ((i64) tv.tv_sec) - benchs_list.v[i].sec[n]; - i64 nsec = ((i64) tv.tv_nsec) - benchs_list.v[i].nsec[n]; - - benchs_list.v[i].duration_nsec[n] = sec * 1000000000 + nsec; -} - -void bench_register(c8 const *name, c8 const *file, bench_run_fn fn) { - i32 n = benchs_list.size++; - if (n < MAX_NUM_BENCHS) { - Benchmark *bench = benchs_list.v + n; - - bench->bench_fn = fn; - bench->bench_name = name; - bench->bench_file = file; - bench->cycles_size = 0; - bench->ready = 0; - } -} - -static void bench_setup_signals() { - for (u32 i = 0; i < sizeof signums_ / sizeof *signums_; i++) - signal(signums_[i], test_handle_signal); -} - -static i32 run_bench_(volatile i32 i) { - i32 signum = setjmp(test_restore_execution); - - if (signum != 0) { - benchs_list.v[i].signal = signum; - return 0; - } - - benchs_list.v[i].bench_fn(i, bench_set_repeats_limit, bench_loop, bench_begin, bench_end); - return 1; -} - -static i32 compare_64_(void const *x_, void const *y_) { - i64 const *x = (i64 const *) x_; - i64 const *y = (i64 const *) y_; - return *x - *y; -} - -static i32 compare_32_(void const *x_, void const *y_) { - i32 const *x = (i32 const *) x_; - i32 const *y = (i32 const *) y_; - return *x - *y; -} - -i32 run_benchmarks(i32 argc, c8 **argv) { - i32 success_count = 0; - i32 status = 0; - i32 no_color = 0; - i32 line_width = 20; - i32 carriage_return = 1; - - c8 const *specific_bench = NULL; - - bench_setup_signals(); - - for (i32 i = 0; i < argc; i++) - if (strcmp("--no-term-color", argv[i]) == 0) - no_color = 1; - else if (strcmp("--no-carriage-return", argv[i]) == 0) - carriage_return = 0; - else if (strcmp("--match", argv[i]) == 0) - specific_bench = argv[++i]; - - if (specific_bench != NULL) { - no_color || print_color_(light_); - printf("Run benchmarks matching "); - no_color || print_color_(white_); - printf("*%s*", specific_bench); - no_color || print_color_(light_); - printf("\n\n"); - } - - c8 const *file = NULL; - i64 file_root = -1; - i32 benchs_total = 0; - - for (i32 i = 0; i < benchs_list.size && i < MAX_NUM_BENCHS; i++) { - if (specific_bench != NULL && strstr(benchs_list.v[i].bench_name, specific_bench) == NULL) - continue; - benchs_total++; - i32 l = 2 + (int) strlen(benchs_list.v[i].bench_name); - if (line_width < l) - line_width = l; - } - - if (benchs_total > 0) { - c8 const *s = benchs_list.v[0].bench_file; - - for (i32 j = 1; j < benchs_list.size && j < MAX_NUM_BENCHS; j++) { - Benchmark *bench = benchs_list.v + j; - - if (specific_bench != NULL && strstr(bench->bench_name, specific_bench) == NULL) - continue; - if (strcmp(s, bench->bench_file) == 0) - continue; - i32 k = 0; - for (; s[k] != '\0' && bench->bench_file[k] != '\0' && s[k] == bench->bench_file[k]; k++) { } - if (file_root == -1 || file_root > k) - file_root = k; - } - - if (file_root == -1) { - for (i32 i = 0; s[i] != '\0'; i++) - if (s[i] == '/' || s[i] == '\\') - file_root = i + 1; - } - } - - no_color || print_color_(blue_); - printf("# "); - no_color || print_color_(light_); - printf("BENCHMARK"); - printf("%*c", line_width - 9, ' '); - no_color || print_color_(green_); - printf(" LOW "); - no_color || print_color_(light_); - printf("|"); - no_color || print_color_(blue_); - printf(" MEDIAN "); - no_color || print_color_(light_); - printf("|"); - no_color || print_color_(yellow_); - printf(" HIGH\n"); - no_color || print_color_(light_); - printf(" (in microseconds)\n\n"); - - // Prepare cycles. - // - - for (i32 i = 0; i < benchs_list.size && i < MAX_NUM_BENCHS; i++) { - Benchmark *bench = benchs_list.v + i; - - if (specific_bench != NULL && strstr(bench->bench_name, specific_bench) == NULL) - continue; - - run_bench_(i); - - if (bench->cycles_size == 0) { - bench->cycles_size = 2; - bench->cycles[0] = NUM_BENCH_REPEATS_DEFAULT_1; - bench->cycles[1] = NUM_BENCH_REPEATS_DEFAULT_2; - } - - qsort(bench->cycles, bench->cycles_size, sizeof *bench->cycles, compare_32_); - - benchs_list.v[i].ready = 1; - } - - // Run cycles. - // - - for (i32 cycle = 0; cycle < MAX_NUM_BENCH_CYCLES; cycle++) { - // Prepare cycle. - // - - i32 cycles_done = 1; - - for (i32 i = 0; i < benchs_list.size && i < MAX_NUM_BENCHS; i++) { - Benchmark *bench = benchs_list.v + i; - - if (specific_bench != NULL && strstr(bench->bench_name, specific_bench) == NULL) - continue; - if (cycle >= bench->cycles_size) - continue; - - bench->repeats = 0; - bench->cycle = cycle; - cycles_done = 0; - } - - if (cycles_done) - break; - - // Run benchmarks. - // - - for (i32 i = 0; i < benchs_list.size && i < MAX_NUM_BENCHS; i++) { - Benchmark *bench = benchs_list.v + i; - - if (specific_bench != NULL && strstr(bench->bench_name, specific_bench) == NULL) - continue; - if (cycle >= bench->cycles_size) - continue; - - if (file == NULL || strcmp(file, bench->bench_file) != 0) { - if (file != NULL) - printf("\n"); - file = bench->bench_file; - no_color || print_color_(blue_); - printf("* "); - no_color || print_color_(white_); - printf("%s\n", file + file_root); - } - - !carriage_return || no_color || print_color_(yellow_); - carriage_return || no_color || print_color_(light_); - printf("` %s ", bench->bench_name); - !carriage_return || printf("\r"); - fflush(stdout); - - i32 bench_status = run_bench_(i); - - if (bench->repeats > MAX_NUM_BENCH_REPEATS) - bench_status = 0; - - !carriage_return || no_color || print_color_(light_); - !carriage_return || printf("` %s ", bench->bench_name); - - i32 l = (i32) strlen(bench->bench_name); - printf("%*c", line_width - l, ' '); - - if (bench->repeats <= 0) { - no_color || print_color_(yellow_); - printf(" 0 runs\n"); - success_count++; - } else if (bench_status == 0) { - no_color || print_color_(red_); - printf(" FAIL\n"); - status = 1; - } else { - i32 repeats = bench->repeats; - - memcpy(bench->duration_sorted_nsec, bench->duration_nsec, repeats * sizeof *bench->duration_sorted_nsec); - qsort(bench->duration_sorted_nsec, repeats, sizeof *bench->duration_sorted_nsec, compare_64_); - - i64 average = bench->duration_sorted_nsec[repeats / 2]; - i64 floor = bench->duration_sorted_nsec[repeats / 20]; - i64 roof = bench->duration_sorted_nsec[repeats - repeats / 20 - 1]; - - no_color || print_color_(white_); - printf("%-9g", (f64) floor * 0.001); - no_color || print_color_(light_); - printf("| "); - no_color || print_color_(white_); - printf("%-9g", (f64) average * 0.001); - no_color || print_color_(light_); - printf("| "); - no_color || print_color_(white_); - printf("%-9g", (f64) roof * 0.001); - no_color || print_color_(light_); - printf(" %d runs\n", repeats); - success_count++; - } - } - } - - printf("\n"); - - if (status != 0) { - for (i32 i = 0; i < benchs_list.size && i < MAX_NUM_BENCHS; i++) { - Benchmark *bench = benchs_list.v + i; - - if (specific_bench != NULL && strstr(bench->bench_name, specific_bench) == NULL) - continue; - if (bench->signal != 0) { - i32 signum = bench->signal; - if (signum >= 0 && signum < (i32) (sizeof signames_ / sizeof *signames_) && signames_[signum] != NULL) { - no_color || print_color_(light_); - printf("Signal \"%s\" (%d) for \"", signames_[signum], signum); - no_color || print_color_(white_); - printf("%s", bench->bench_name); - no_color || print_color_(light_); - printf("\" in \""); - no_color || print_color_(white_); - printf("%s", bench->bench_file + file_root); - no_color || print_color_(light_); - printf("\"!.\n"); - } else { - no_color || print_color_(light_); - printf("Unknown signal (%d) for \"", signum); - no_color || print_color_(white_); - printf("%s", bench->bench_name); - no_color || print_color_(light_); - printf("\" in \""); - no_color || print_color_(white_); - printf("%s", bench->bench_file + file_root); - no_color || print_color_(light_); - printf("\"!.\n"); - } - } - } - - printf("\n"); - } - - if (benchs_list.size > MAX_NUM_BENCHS) { - no_color || print_color_(light_); - printf("Too many benchmarks!\n\n"); - status = 1; - } - - if (status == 0) { - no_color || print_color_(green_); - printf("DONE\n"); - } else { - no_color || print_color_(red_); - printf("DONE WITH ERRORS\n"); - } - - no_color || print_color_(light_); - printf("\n"); - return status; -} - -#endif // TEST_IMPL_GUARD_ -#endif // TEST_HEADER -- cgit v1.2.3