From 873e8c4cb737a6e54538d077738d2d25ba3b9b01 Mon Sep 17 00:00:00 2001 From: Rokas Puzonas Date: Thu, 16 Jan 2025 22:30:35 +0200 Subject: [PATCH] add math_func_checker.c --- Makefile | 19 ++-- src/harvensine_formula.c | 54 +++++++++++- src/main.c | 19 +++- src/math_func_checker.c | 117 ++++++++++++++++++++++++ src/repetition_tester.c | 186 --------------------------------------- src/tests.c | 170 ----------------------------------- 6 files changed, 197 insertions(+), 368 deletions(-) create mode 100644 src/math_func_checker.c delete mode 100644 src/repetition_tester.c delete mode 100644 src/tests.c diff --git a/Makefile b/Makefile index 844761e..13ee15a 100644 --- a/Makefile +++ b/Makefile @@ -6,24 +6,25 @@ guess_cpu_speed: build/guess_cpu_speed gen_data: build/gen_data main: build/main -build/gen_data: src/gen_data.c +build: mkdir -p build + +build/gen_data: src/gen_data.c build gcc -o build/gen_data src/gen_data.c $(CFLAGS) -build/main: src/main.c src/json_parser.c src/rprof.h - mkdir -p build +build/math_func_checker: src/math_func_checker.c build + gcc -o build/math_func_checker src/math_func_checker.c $(CFLAGS) + +build/main: src/main.c src/json_parser.c src/rprof.h build gcc -o build/main src/main.c $(CFLAGS) -build/test: src/tests.c src/repetition_tester.c - mkdir -p build +build/test: src/tests.c src/repetition_tester.c build gcc -o build/test src/tests.c $(CFLAGS) -build/guess_cpu_speed: src/guess_cpu_speed.c src/timer.c - mkdir -p build +build/guess_cpu_speed: src/guess_cpu_speed.c build gcc -o build/guess_cpu_speed src/guess_cpu_speed.c $(CFLAGS) -build/page_fault_prober: src/page_fault_prober.c - mkdir -p build +build/page_fault_prober: src/page_fault_prober.c build gcc -o build/page_fault_prober src/page_fault_prober.c $(CFLAGS) clean: diff --git a/src/harvensine_formula.c b/src/harvensine_formula.c index c632653..9be1630 100644 --- a/src/harvensine_formula.c +++ b/src/harvensine_formula.c @@ -1,14 +1,64 @@ +#include #include +#include typedef double f64; #define EARTH_RADIUS 6372.8 +struct counters { + f64 min_input; + f64 max_input; + f64 min_output; + f64 max_output; +}; + +#define EMPTY_COUNTERS (struct counters){ .min_input = DBL_MAX, .max_input = -DBL_MAX, .min_output = DBL_MAX, .max_output = -DBL_MAX } + +struct counters cos_counters = EMPTY_COUNTERS; +struct counters sin_counters = EMPTY_COUNTERS; +struct counters asin_counters = EMPTY_COUNTERS; +struct counters sqrt_counters = EMPTY_COUNTERS; + +#define LOG_COUNTERS(counters, func, a) do { \ +countres.min_input = MIN(countres.min_input, a) \ +} while (0) + +static f64 log_counters(struct counters *counters, f64 (*calc)(f64), f64 input) +{ + counters->min_input = MIN(counters->min_input, input); + counters->max_input = MAX(counters->max_input, input); + f64 output = calc(input); + counters->min_output = MIN(counters->min_output, output); + counters->max_output = MAX(counters->max_output, output); + return output; +} + static f64 sqaure_f64(f64 num) { return num*num; } +static f64 my_sin(f64 num) +{ + return log_counters(&sin_counters, sin, num); +} + +static f64 my_cos(f64 num) +{ + return log_counters(&cos_counters, cos, num); +} + +static f64 my_sqrt(f64 num) +{ + return log_counters(&sqrt_counters, sqrt, num); +} + +static f64 my_asin(f64 num) +{ + return log_counters(&asin_counters, asin, num); +} + static f64 radians_to_degrees(f64 degrees) { return 0.01745329251994329577 * degrees; @@ -26,8 +76,8 @@ static f64 get_harvensine_distance(f64 X0, f64 Y0, f64 X1, f64 Y1, f64 earth_rad lat1 = radians_to_degrees(lat1); lat2 = radians_to_degrees(lat2); - f64 a = sqaure_f64(sin(dLat/2.0)) + cos(lat1)*cos(lat2)*sqaure_f64(sin(dLon/2)); - f64 c = 2.0*asin(sqrt(a)); + f64 a = sqaure_f64(my_sin(dLat/2.0)) + my_cos(lat1)*my_cos(lat2)*sqaure_f64(my_sin(dLon/2)); + f64 c = 2.0*my_asin(my_sqrt(a)); return earth_radius * c; } diff --git a/src/main.c b/src/main.c index 7c6cc67..c3816f8 100644 --- a/src/main.c +++ b/src/main.c @@ -5,7 +5,6 @@ #include #include - #include "harvensine_compute.h" #include "json_parser.c" #include "harvensine_formula.c" @@ -207,5 +206,23 @@ int main(int argc, char **argv) rprof_output(rprof_cmp_by_exclusive_duration); + printf("\n------- Counters ------\n"); + + printf("Sin:\n"); + printf("Input: %f - %f\n", sin_counters.min_input, sin_counters.max_input); + printf("Output: %f - %f\n\n", sin_counters.min_output, sin_counters.max_output); + + printf("Cos:\n"); + printf("Input: %f - %f\n", cos_counters.min_input, cos_counters.max_input); + printf("Output: %f - %f\n\n", cos_counters.min_output, cos_counters.max_output); + + printf("Sqrt:\n"); + printf("Input: %f - %f\n", sqrt_counters.min_input, sqrt_counters.max_input); + printf("Output: %f - %f\n\n", sqrt_counters.min_output, sqrt_counters.max_output); + + printf("Asin:\n"); + printf("Input: %f - %f\n", asin_counters.min_input, asin_counters.max_input); + printf("Output: %f - %f\n", asin_counters.min_output, asin_counters.max_output); + return 0; } diff --git a/src/math_func_checker.c b/src/math_func_checker.c new file mode 100644 index 0000000..699ffc4 --- /dev/null +++ b/src/math_func_checker.c @@ -0,0 +1,117 @@ +#include +#include +#include +#include + +typedef double f64; +typedef float f32; +typedef f64 (*math_func)(f64); +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +struct math_spec { + const char *name; + math_func mine; + math_func reference; + f64 from; + f64 to; +}; + +static f64 my_sin(f64 num) +{ + return num; +} + +static f64 my_cos(f64 num) +{ + return num; +} + +static f64 my_sqrt1(f64 num) +{ + __m128d zero = _mm_set_sd(0); + __m128d mm_num = _mm_set_sd(num); + __m128d mm_result = _mm_sqrt_sd(zero, mm_num); + f64 result = _mm_cvtsd_f64(mm_result); + return result; +} + +static f64 my_sqrt2(f64 num) +{ + __m128 mm_num = _mm_set_ss(num); + __m128 mm_inv_result = _mm_rsqrt_ss(mm_num); + __m128 mm_result = _mm_div_ss(_mm_set_ss(1), mm_inv_result); + f32 result = _mm_cvtss_f32(mm_result); + return result; +} + +static f64 my_asin(f64 num) +{ + return num; +} + +int main() +{ + uint64_t samples = 10000; + struct math_spec specs[] = { + { + .name = "sin", + .mine = my_sin, + .reference = sin, + .from = -M_PI, + .to = M_PI + }, + { + .name = "cos", + .mine = my_cos, + .reference = cos, + .from = -M_PI/2, + .to = M_PI/2 + }, + { + .name = "sqrt", + .mine = my_sqrt1, + .reference = sqrt, + .from = 0, + .to = 1, + }, + { + .name = "sqrt (using rsqrt)", + .mine = my_sqrt2, + .reference = sqrt, + .from = 0, + .to = 1, + }, + { + .name = "asin", + .mine = my_asin, + .reference = asin, + .from = 0, + .to = 1, + } + }; + + for (int i = 0; i < ARRAY_LEN(specs); i++) { + struct math_spec spec = specs[i]; + + f64 max_error = 0; + + for (int j = 0; j < samples; j++) { + f64 input = ((f64)j / samples) * (spec.to - spec.from) + spec.from; + f64 reference_output = spec.reference(input); + f64 my_output = spec.mine(input); + + f64 error = reference_output - my_output; + if (error < 0) { + error = -error; + } + + if (error > max_error) { + max_error = error; + } + } + + printf("%s max error %f\n", spec.name, max_error); + } + + return 0; +} diff --git a/src/repetition_tester.c b/src/repetition_tester.c deleted file mode 100644 index 1e5eae4..0000000 --- a/src/repetition_tester.c +++ /dev/null @@ -1,186 +0,0 @@ -#include -#include -#include -#include "rprof.h" - -enum tester_state { - STATE_UNKNOWN, - STATE_RUNNING, - STATE_FINISHED, - STATE_ERROR -}; - -struct repetition_tester { - enum tester_state state; - - uint64_t cpu_freq; - uint32_t testing_timeout; - uint64_t expected_byte_count; - uint64_t last_found_min_time; - bool show_current_min; - - uint32_t closed_blocks; - uint32_t opened_blocks; - - uint64_t test_running_time; - uint64_t test_running_bytes; - uint64_t test_running_page_faults; -}; - -struct repetition_results { - uint64_t test_count; - uint64_t total_time; - uint64_t min_time; - uint64_t max_time; - - uint64_t total_page_faults; - uint64_t min_page_faults; - uint64_t max_page_faults; -}; - -typedef void (*test_cb)(struct repetition_tester*, void *user); - -void repetition_tester_init(struct repetition_tester *tester) { - tester->cpu_freq = rprof_get_cpu_timer_hz(100); - tester->testing_timeout = 10; -} - -void repetition_tester_error(struct repetition_tester *tester, char *message) { - tester->state = STATE_ERROR; - printf("Error during repetition: %s\n", message); -} - -void print_repetition_time(char *label, float cpu_time, uint64_t bytes, uint64_t page_faults, uint64_t cpu_freq) { - printf("%s: %.0f", label, cpu_time); - if (cpu_freq) { - float seconds_time = (float)cpu_time/(float)cpu_freq; - printf(" (%fms)", seconds_time*1000.0); - - if (bytes) { - float gigabyte = 1024 * 1024 * 1024; - float bandwidth = bytes / (gigabyte * seconds_time); - printf(" at %fgb/s", bandwidth); - } - - } - if (page_faults) { - printf(" PF: %lu", page_faults); - if (bytes) { - printf(" (%.3fkb/fault)", ((float)bytes)/(page_faults * 1024)); - } - } -} - -bool repetition_tester_continue(struct repetition_tester *tester, struct repetition_results *results) { - if (tester->state != STATE_RUNNING) { - return false; - } - - if (tester->opened_blocks == 0) { - return true; - } - - if (tester->opened_blocks != tester->closed_blocks) { - repetition_tester_error(tester, "Closed blocks doesn't match opened blocks"); - return false; - } - - if (tester->expected_byte_count != tester->test_running_bytes) { - repetition_tester_error(tester, "Processed byte coutn doesn't match"); - return false; - } - - uint64_t now = rprof_read_cpu_timer(); - - results->test_count += 1; - results->total_time += tester->test_running_time; - results->max_time = MAX(results->max_time, tester->test_running_time); - if (tester->test_running_time < results->min_time) { - results->min_time = tester->test_running_time; - tester->last_found_min_time = now; - - if (tester->show_current_min) { - printf("\r"); - print_repetition_time("Min", tester->test_running_time, tester->test_running_bytes, 0, tester->cpu_freq); - fflush(stdout); - } - } - - results->total_page_faults += tester->test_running_page_faults; - results->min_page_faults = MIN(results->min_page_faults, tester->test_running_page_faults); - results->max_page_faults = MAX(results->max_page_faults, tester->test_running_page_faults); - - tester->opened_blocks = 0; - tester->closed_blocks = 0; - tester->test_running_bytes = 0; - tester->test_running_time = 0; - tester->test_running_page_faults = 0; - - uint64_t time_since_last_find = (now - tester->last_found_min_time); - if ((time_since_last_find / tester->cpu_freq) >= tester->testing_timeout) { - tester->state = STATE_FINISHED; - return false; - } - - return true; -} - -int repetition_test_run(struct repetition_tester *tester, uint64_t expected_byte_count, struct repetition_results *results, test_cb cb, void *user) { - memset(results, 0, sizeof(struct repetition_results)); - tester->state = STATE_RUNNING; - tester->expected_byte_count = expected_byte_count; - tester->last_found_min_time = rprof_read_cpu_timer(); - - results->min_time = UINT64_MAX; - results->max_time = 0; - results->test_count = 0; - results->total_time = 0; - results->max_page_faults = 0; - results->min_page_faults = UINT64_MAX; - results->total_page_faults = 0; - - while (repetition_tester_continue(tester, results)) { - cb(tester, user); - } - - if (tester->show_current_min) { - printf("\n"); - } - - if (tester->state == STATE_ERROR) { - return -1; - } - - return 0; -} - -void print_repetition_results(struct repetition_tester *tester, struct repetition_results *results) { - print_repetition_time("Min", results->min_time, tester->expected_byte_count, results->min_page_faults, tester->cpu_freq); - printf("\n"); - - print_repetition_time("Max", results->max_time, tester->expected_byte_count, results->max_page_faults, tester->cpu_freq); - printf("\n"); - - if (results->test_count) { - uint64_t avg_time = results->total_time/results->test_count; - uint64_t avg_page_faults = results->total_page_faults/results->test_count; - print_repetition_time("Avg", avg_time, tester->expected_byte_count, avg_page_faults, tester->cpu_freq); - printf("\n"); - } -} - -void repetition_time_start(struct repetition_tester *tester) { - tester->opened_blocks++; - tester->test_running_time -= rprof_read_cpu_timer(); - tester->test_running_page_faults -= read_page_faults(); -} - -void repetition_time_end(struct repetition_tester *tester) { - tester->closed_blocks++; - tester->test_running_time += rprof_read_cpu_timer(); - tester->test_running_page_faults += read_page_faults(); -} - -void repetition_count_bytes(struct repetition_tester *tester, int bytes) { - tester->test_running_bytes += bytes; -} diff --git a/src/tests.c b/src/tests.c deleted file mode 100644 index be9a4b1..0000000 --- a/src/tests.c +++ /dev/null @@ -1,170 +0,0 @@ -#include -#include -#include - -#include "repetition_tester.c" - -#define RPROF_IMPLEMENTATION -#include "rprof.h" - -#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) - -size_t get_file_size(char *filename) -{ - FILE *f = fopen(filename, "r"); - if (f == NULL) { return 0; } - - fseek(f, 0, SEEK_END); - size_t size = ftell(f); - - fclose(f); - return size; -} - -struct test_params { - char *filename; - uint8_t *buffer; - uint64_t byte_count; - - bool inner_malloc; -}; - -struct testcase { - char *name; - test_cb cb; - bool inner_malloc; -}; - -void handle_buffer_malloc(struct test_params *params) { - if (params->inner_malloc) { - params->buffer = malloc(sizeof(uint8_t) * params->byte_count); - } -} - -void handle_buffer_free(struct test_params *params) { - if (params->inner_malloc) { - free(params->buffer); - } -} - -void test_write_bytes(struct repetition_tester *tester, void *user) -{ - struct test_params *params = user; - - handle_buffer_malloc(params); - - repetition_time_start(tester); - for (uint64_t i = 0; i < params->byte_count; ++i) { - params->buffer[i] = (uint8_t)i; - } - repetition_time_end(tester); - - repetition_count_bytes(tester, params->byte_count); - - handle_buffer_free(params); -} - -void test_fread(struct repetition_tester *tester, void *user) -{ - struct test_params *params = user; - FILE *f = fopen(params->filename, "r"); - if (f == NULL) { - repetition_tester_error(tester, "Failed to open file"); - return; - } - - handle_buffer_malloc(params); - - repetition_time_start(tester); - int result = fread(params->buffer, params->byte_count, 1, f); - repetition_time_end(tester); - if (result <= 0) { - repetition_tester_error(tester, "Failed to read file"); - goto err; - } - - repetition_count_bytes(tester, params->byte_count); - -err: - handle_buffer_free(params); - fclose(f); -} - -void test_read(struct repetition_tester *tester, void *user) -{ - struct test_params *params = user; - int fd = open(params->filename, O_RDONLY); - if (fd <= 0) { - repetition_tester_error(tester, "Failed to open file"); - return; - } - - handle_buffer_malloc(params); - - repetition_time_start(tester); - int result = read(fd, params->buffer, params->byte_count); - repetition_time_end(tester); - if (result <= 0) { - repetition_tester_error(tester, "Failed to read file"); - goto err; - } - - repetition_count_bytes(tester, result); - -err: - handle_buffer_free(params); - close(fd); -} - -int main() -{ - struct repetition_tester tester = { 0 }; - repetition_tester_init(&tester); - tester.show_current_min = true; - - char *filename = "data_10000000.json"; - uint64_t file_size = get_file_size(filename); - - printf("File size: %lu\n", file_size); - - struct testcase cases[] = { - { .name = "write bytes", .cb = test_write_bytes, .inner_malloc = false }, - { .name = "write bytes + malloc", .cb = test_write_bytes, .inner_malloc = true }, - { .name = "read", .cb = test_read, .inner_malloc = false }, - { .name = "read + malloc", .cb = test_read, .inner_malloc = true }, - { .name = "fread", .cb = test_fread, .inner_malloc = false }, - { .name = "fread + malloc", .cb = test_fread, .inner_malloc = true }, - }; - - struct repetition_results results = { 0 }; - while (true) { - for (int i = 0; i < ARRAY_LEN(cases); i++) { - struct testcase *testcase = &cases[i]; - - uint8_t *buffer = NULL; - if (!testcase->inner_malloc) { - buffer = malloc(sizeof(uint8_t) * file_size); - } - - struct test_params params = { - .filename = filename, - .buffer = buffer, - .byte_count = file_size, - .inner_malloc = testcase->inner_malloc - }; - - if (repetition_test_run(&tester, file_size, &results, testcase->cb, ¶ms)) { - return -1; - } - printf("----- %s -----\n", testcase->name); - print_repetition_results(&tester, &results); - printf("\n"); - - if (!testcase->inner_malloc) { - free(buffer); - } - } - } - - return 0; -}