#include #include #include #include #include #include #include "harvensine_compute.h" #include "timer.c" #include "json_parser.c" #include "harvensine_formula.c" struct point_pair { f64 x0; f64 y0; f64 x1; f64 y1; }; struct point_pairs { struct point_pair *pairs; size_t count; }; void print_usage(char *program) { printf("Usage: %s [reference-bin-file]\n", program); } size_t get_file_size(FILE *f) { fseek(f, 0, SEEK_END); size_t size = ftell(f); fseek(f, 0, SEEK_SET); return size; } u64 get_current_time_us() { struct timespec time; clock_gettime(CLOCK_MONOTONIC_RAW, &time); return time.tv_sec * 1000000 + time.tv_nsec / 1000; } static struct point_pairs *convert_to_struct(struct json_value *json) { assert(json->type == JSON_TYPE_OBJECT); assert(json->object->count == 1); assert(!strncmp(json->object->keys[0]->str, "pairs", sizeof("pairs")-1)); assert(json->object->values[0]->type == JSON_TYPE_ARRAY); struct json_array *pairs_array = json->object->values[0]->array; struct point_pairs *result = malloc(sizeof(struct point_pairs)); result->pairs = malloc(pairs_array->count * sizeof(struct point_pair)); result->count = pairs_array->count; for (int i = 0; i < result->count; i++) { assert(pairs_array->values[i]->type == JSON_TYPE_OBJECT); assert(pairs_array->values[i]->object->count == 4); struct json_object *json_pair = pairs_array->values[i]->object; struct json_value *x0 = get_json_object_value(json_pair, "x0", sizeof("x0")-1); assert(x0 != NULL && x0->type == JSON_TYPE_NUMBER); struct json_value *y0 = get_json_object_value(json_pair, "y0", sizeof("y0")-1); assert(y0 != NULL && y0->type == JSON_TYPE_NUMBER); struct json_value *x1 = get_json_object_value(json_pair, "x1", sizeof("x1")-1); assert(x1 != NULL && x1->type == JSON_TYPE_NUMBER); struct json_value *y1 = get_json_object_value(json_pair, "y1", sizeof("y1")-1); assert(y1 != NULL && y1->type == JSON_TYPE_NUMBER); struct point_pair *pair = &result->pairs[i]; pair->x0 = x0->number; pair->y0 = y0->number; pair->x1 = x1->number; pair->y1 = y1->number; } return result; } static void free_point_pairs(struct point_pairs *pairs) { if (pairs == NULL) return; free(pairs->pairs); free(pairs); } int main(int argc, char **argv) { struct timer total_timer = START_TIMER("Total time"); if (argc <= 1) { print_usage(argv[0]); return -1; } char *json_filename = argv[1]; FILE *f = fopen(json_filename, "r"); if (f == NULL) { printf("Failed to open: %s\n", json_filename); return -1; } struct timer read_files_timer = START_TIMER("Read files"); size_t json_size = get_file_size(f); char json_data[json_size]; size_t bytes_read = fread(json_data, 1, json_size, f); if (bytes_read != json_size) { printf("Failed to read all contents of file\n"); return -1; } fclose(f); f64 *reference_harvensines = NULL; size_t reference_harvensines_count = 0; f64 reference_harvensine_sum = 0; if (argc >= 3) { char *answers_filename = argv[2]; FILE *f = fopen(answers_filename, "r"); if (f == NULL) { printf("Failed to open: %s\n", json_filename); return -1; } size_t file_size = get_file_size(f); assert(file_size % sizeof(f64) == 0); reference_harvensines_count = file_size / sizeof(f64) - 1; reference_harvensines = malloc(reference_harvensines_count * sizeof(f64)); for (int i = 0; i < reference_harvensines_count; i++) { fread(&reference_harvensines[i], sizeof(f64), 1, f); } fread(&reference_harvensine_sum, sizeof(f64), 1, f); fclose(f); } END_TIMER(read_files_timer); // Step 1. Read json file struct timer json_parse_timer = START_TIMER("Parse JSON"); struct json_value *parsed = NULL; { parsed = malloc(sizeof(struct json_value)); int bytes_parsed = parse_json_value(parsed, json_data, json_size); assert(bytes_parsed >= 0); } END_TIMER(json_parse_timer); u32 row_count = parsed->object->values[0]->array->count; if (reference_harvensines_count > 0) { assert(row_count == reference_harvensines_count); } // Step 2. Convert json object to struct struct timer struct_convert_timer = START_TIMER("Conver to struct"); struct point_pairs *pairs = convert_to_struct(parsed); END_TIMER(struct_convert_timer); // Step 3. Calculate harvensine distances struct timer harvensines_timer = START_TIMER("Compute harvensines"); f64 *harvensines = malloc(pairs->count*sizeof(f64)); for (int i = 0; i < pairs->count; i++) { struct point_pair *p = &pairs->pairs[i]; harvensines[i] = get_harvensine_distance(p->x0, p->y0, p->x1, p->y1, EARTH_RADIUS); } END_TIMER(harvensines_timer); struct timer sum_harvensines_timer = START_TIMER("Sum harvensines"); f64 harvensine_sum = 0; for (int i = 0; i < pairs->count; i++) { harvensine_sum += harvensines[i]; } END_TIMER(sum_harvensines_timer); struct timer freeing_timer = START_TIMER("Free memory"); free(reference_harvensines); free(harvensines); free_json_value(parsed); free_point_pairs(pairs); END_TIMER(freeing_timer); END_TIMER(total_timer); // Output results printf("Row count: %d\n", row_count); printf("Sum of all harvensines: %f\n", harvensine_sum); if (reference_harvensines_count > 0) { printf("Diff of reference harvensine sum: %.16f\n", harvensine_sum - reference_harvensine_sum); } u64 cpu_hz = get_cpu_timer_hz(100); u64 total_time = TIMER_DURATION(total_timer); printf("\nTotal time taken: %.3fms\n", (float)total_time*1000/cpu_hz); struct timer timers[] = { read_files_timer, json_parse_timer, struct_convert_timer, harvensines_timer, sum_harvensines_timer, freeing_timer }; for (size_t i = 0; i < ARRAY_LEN(timers); i++) { u64 duration = TIMER_DURATION(timers[i]); printf("\t%20s - %9lu (%.03f%%)\n", timers[i].name, duration, (float)duration*100/total_time); } u64 other_duration = total_time - sum_timer(timers, ARRAY_LEN(timers)); printf("\t%20s - %9lu (%.03f%%)\n", "Other", other_duration, (float)other_duration*100/total_time); return 0; }