diff --git a/haversine_02/include/repetition_testing/reptester.h b/haversine_02/include/repetition_testing/reptester.h new file mode 100644 index 0000000..796f869 --- /dev/null +++ b/haversine_02/include/repetition_testing/reptester.h @@ -0,0 +1,44 @@ +#ifndef REPTESTER_H +#define REPTESTER_H + +#include "aliases.h" + +struct reptest_params { + const char *filename; + char *buffer; + u64 read_size; + u64 read_count; +}; + +struct reptest_results { + u64 bytes_read; + u64 read_time; +}; + +struct reptester { + reptest_params params; + + const u64 cpu_freq; + + f64 wait_time_secs; + f64 test_time_secs; + u64 test_start_time; + + u64 current_run; + u64 min; + u64 max; + u64 avg; + u64 total; + + reptest_results results; +}; + +struct reptest_func { + const char *name; + void (*func)(reptester *tester); +}; + +void run_func_test(reptester *tester, reptest_func func_obj); +void print_results(reptester *tester, const char *name); + +#endif // !REPTESTER_H diff --git a/haversine_02/src/repetition_testing/main.cpp b/haversine_02/src/repetition_testing/main.cpp new file mode 100644 index 0000000..f11e9d2 --- /dev/null +++ b/haversine_02/src/repetition_testing/main.cpp @@ -0,0 +1,134 @@ +#include "aliases.h" +#include "profiler/timer.h" +#include "repetition_testing/reptester.h" +#include +#include +#include +#include +#include + +#define ARR_LEN(ARR) sizeof(ARR) / sizeof(*ARR) + +void test_fread(reptester *tester); +void test_read(reptester *tester); +u64 get_file_length(FILE *fp); + +int main(int argc, char *argv[]) { + const char *filename = NULL; + u64 waves = 1; + + switch (argc) { + case 3: + waves = atol(argv[2]); + // break left intentionally + case 2: + filename = argv[1]; + break; + default: + printf("Usage: reptest FILENAME [WAVE_COUNT]\n"); + return -1; + break; + } + + // clang-format off + reptester tester = { + {filename, NULL, 0, 0}, // params + get_cpu_freq(500), // cpu_freq + + 10.0, // wait_time_secs + 0.0, // test_time_secs + read_cpu_timer(), // test_start_time + + 1, // current_run + UINT64_MAX, // min + 0, // max + 0, // avg + 0, // total + {}, // results + }; + // clang-format on + + FILE *fp = fopen(tester.params.filename, "rb"); + if (!fp) { + return -1; + } + + reptest_func funcs[] = {{"FREAD", test_fread}, {"READ", test_read}}; + + tester.params.read_size = get_file_length(fp); + tester.params.read_count = 1; + tester.params.buffer = (char *)malloc(tester.params.read_size + 1); + memset(tester.params.buffer, 0, tester.params.read_size + 1); + + for (u64 i = 0; i < waves; ++i) { + for (u64 j = 0; j < ARR_LEN(funcs); ++j) { + run_func_test(&tester, funcs[j]); + } + } + + fclose(fp); + + free(tester.params.buffer); + + return 0; +} + +void test_fread(reptester *tester) { + FILE *fp = fopen(tester->params.filename, "rb"); + if (!fp) { + return; + } + + u64 start = read_cpu_timer(); + u64 obj_count = fread(tester->params.buffer, tester->params.read_size, + tester->params.read_count, fp); + u64 end = read_cpu_timer(); + + u64 bytes_read = obj_count * tester->params.read_size; + + u64 read_time = end - start; + + tester->results = { + bytes_read, + read_time, + }; + + fclose(fp); +} + +void test_read(reptester *tester) { + FILE *fp = fopen(tester->params.filename, "rb"); + if (!fp) { + return; + } + + i32 fd = fileno(fp); + + u64 start = read_cpu_timer(); + u64 bytes_read = read(fd, tester->params.buffer, + tester->params.read_size * tester->params.read_count); + u64 end = read_cpu_timer(); + + u64 read_time = end - start; + + tester->results = { + bytes_read, + read_time, + }; + + fclose(fp); +} + +u64 get_file_length(FILE *fp) { + if (!fp) { + return 0; + } + + fseek(fp, 0, SEEK_END); + + u64 length = ftell(fp); + + fseek(fp, 0, SEEK_SET); + + return length; +} diff --git a/haversine_02/src/repetition_testing/reptester.cpp b/haversine_02/src/repetition_testing/reptester.cpp new file mode 100644 index 0000000..9ccc6c4 --- /dev/null +++ b/haversine_02/src/repetition_testing/reptester.cpp @@ -0,0 +1,62 @@ +#include "repetition_testing/reptester.h" +#include "profiler/timer.h" +#include + +void run_func_test(reptester *tester, reptest_func func_obj) { + tester->test_start_time = read_cpu_timer(); + tester->test_time_secs = 0.0; + tester->current_run = 1; + tester->min = UINT64_MAX; + tester->max = 0; + tester->avg = 0; + tester->total = 0; + tester->results = {}; + + while (tester->test_time_secs <= tester->wait_time_secs) { + func_obj.func(tester); + + if (tester->results.bytes_read < + tester->params.read_size * tester->params.read_count) { + printf("Failed to read the entire file (Total size: %lu, Bytes read: " + "%lu)\n", + tester->params.read_size, tester->results.bytes_read); + + return; + } + + tester->total += tester->results.read_time; + + if (tester->results.read_time > tester->max) { + tester->max = tester->results.read_time; + } else if (tester->results.read_time < tester->min) { + tester->test_start_time = read_cpu_timer(); + tester->min = tester->results.read_time; + } + + tester->test_time_secs = time_in_seconds( + read_cpu_timer() - tester->test_start_time, tester->cpu_freq); + + ++(tester->current_run); + } + + print_results(tester, func_obj.name); +} + +void print_results(reptester *tester, const char *name) { + f64 gb = 1024.0 * 1024.0 * 1024.0; + + f64 size_in_gb = + (f64)(tester->params.read_size * tester->params.read_count) / gb; + + u64 run_count = tester->current_run - 1; + + tester->avg = tester->total / run_count; + + printf("\n%s: %lu runs\n", name, run_count); + printf("MIN: %lu (%fGB/s)\n", tester->min, + size_in_gb / time_in_seconds(tester->min, tester->cpu_freq)); + printf("MAX: %lu (%fGB/s)\n", tester->max, + size_in_gb / time_in_seconds(tester->max, tester->cpu_freq)); + printf("AVG: %lu (%fGB/s)\n", tester->avg, + size_in_gb / time_in_seconds(tester->avg, tester->cpu_freq)); +}