diff --git a/Makefile b/Makefile index d36c479..debe64b 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -CFLAGS=-lm -g -Wall -Walloc-size-larger-than=-1 +CFLAGS=-lm -g -Wall .PHONY := gen_data main @@ -7,11 +7,11 @@ main: build/main build/gen_data: src/gen_data.c mkdir -p build - gcc -o build/gen_data src/gen_data.c $(CFLAGS) -O2 + gcc -o build/gen_data src/gen_data.c $(CFLAGS) -O0 build/main: src/main.c src/json_parser.c mkdir -p build - gcc -o build/main src/main.c $(CFLAGS) -O2 + gcc -o build/main src/main.c $(CFLAGS) -O0 clean: rm -r build diff --git a/README.md b/README.md index fe67957..feb636c 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ # Harvensine computing For [Computer, Enhance!](https://www.computerenhance.com/) + +Json spec: https://www.json.org/json-en.html diff --git a/src/gen_data.c b/src/gen_data.c index 2002269..ff83de4 100644 --- a/src/gen_data.c +++ b/src/gen_data.c @@ -139,6 +139,13 @@ static void print_usage(char *program) { fprintf(stderr, "\tcluster [seed]\n"); } +u64 get_current_time_us() +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC_RAW, &time); + return time.tv_sec * 1000000 + time.tv_nsec / 1000; +} + int main(int argc, char **argv) { if (argc < 2) { print_usage(argv[0]); @@ -197,6 +204,7 @@ int main(int argc, char **argv) { return -1; } + u64 start_time = get_current_time_us(); srand(seed); f64 sum = 0; if (method == GEN_UNIFORM) { @@ -246,11 +254,13 @@ int main(int argc, char **argv) { } fwrite(&sum, sizeof(f64), 1, answer_file); + u64 duration = get_current_time_us() - start_time; printf("Used earth radius: %f\n", EARTH_RADIUS); printf("Seed: %d\n", seed); printf("Number of pairs: %d\n", row_count); printf("Expected sum: %lf\n", sum); + printf("Duration: %ldus (%lfus/row)\n", duration, ((f64)duration) / row_count); return 0; -} \ No newline at end of file +} diff --git a/src/json_parser.c b/src/json_parser.c index d8aa853..422dcaf 100644 --- a/src/json_parser.c +++ b/src/json_parser.c @@ -3,6 +3,7 @@ #include #include #include +#include #include "json_parser.h" @@ -339,6 +340,18 @@ int parse_json_bool(bool *result, char *data, size_t data_size) return 0; // TODO: } +struct json_value *get_json_object_value(struct json_object *obj, char *key, size_t key_size) +{ + for (int i = 0; i < obj->count; i++) + { + struct json_string *obj_key = obj->keys[i]; + if (obj_key->size == key_size && !strncmp(obj_key->str, key, key_size)) { + return obj->values[i]; + } + } + return NULL; +} + void printf_json_array(struct json_array *array) { diff --git a/src/json_parser.h b/src/json_parser.h index de2ec70..1d34457 100644 --- a/src/json_parser.h +++ b/src/json_parser.h @@ -56,3 +56,5 @@ void printf_json_value(struct json_value *result); void printf_json_string(struct json_string *string); void printf_json_object(struct json_object *object); void printf_json_array(struct json_array *array); + +struct json_value *get_json_object_value(struct json_object *obj, char *key, size_t key_size); diff --git a/src/main.c b/src/main.c index 72ea432..2947831 100644 --- a/src/main.c +++ b/src/main.c @@ -1,12 +1,33 @@ +#include #include #include -#include +#include +#include +#include +#include #include "json_parser.c" +#define EARTH_RADIUS 6372.8 + +typedef uint32_t u32; +typedef uint64_t u64; + +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 [test-bin-file]\n", program); + printf("Usage: %s [reference-bin-file]\n", program); } size_t get_file_size(FILE *f) @@ -17,9 +38,89 @@ size_t get_file_size(FILE *f) 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 f64 sqaure_f64(f64 num) +{ + return num*num; +} + +static f64 radians_to_degrees(f64 degrees) +{ + return 0.01745329251994329577 * degrees; +} + +static f64 get_harvensine_distance(f64 X0, f64 Y0, f64 X1, f64 Y1, f64 earth_radius) +{ + f64 lat1 = Y0; + f64 lat2 = Y1; + f64 lon1 = X0; + f64 lon2 = X1; + + f64 dLat = radians_to_degrees(lat2 - lat1); + f64 dLon = radians_to_degrees(lon2 - lon1); + 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)); + + return earth_radius * c; +} + +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) { - if (argc < 2) { + if (argc <= 1) { print_usage(argv[0]); return -1; } @@ -41,13 +142,90 @@ int main(int argc, char **argv) } fclose(f); - struct json_value *parsed = malloc(sizeof(struct json_value)); - int bytes_parsed = parse_json_value(parsed, json_data, json_size); + 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); - printf_json_value(parsed); - printf("\n"); + fclose(f); + } + // Step 1. Read json file + + u64 json_parse_duration; + struct json_value *parsed = NULL; + { + parsed = malloc(sizeof(struct json_value)); + u64 start_time = get_current_time_us(); + int bytes_parsed = parse_json_value(parsed, json_data, json_size); + assert(bytes_parsed >= 0); + json_parse_duration = get_current_time_us() - start_time; + } + + u32 row_count = parsed->object->values[0]->array->count; + if (reference_harvensines_count > 0) { + assert(row_count == reference_harvensines_count); + } + + printf("Row count: %d\n", row_count); + printf("Time to parse JSON: %ldus (%.3lfus/row)\n", json_parse_duration, (f64)json_parse_duration / row_count); + + // Step 2. Convert json object to struct + + u64 struct_convert_duration; + struct point_pairs *pairs = NULL; + { + u64 start_time = get_current_time_us(); + pairs = convert_to_struct(parsed); + struct_convert_duration = get_current_time_us() - start_time; + } + + printf("Time to convert to struct: %ldus (%.3lfus/row)\n", struct_convert_duration, (f64)struct_convert_duration / row_count); + + // Step 3. Calculate harvensine distances + + f64 *harvensines = malloc(pairs->count*sizeof(f64)); + u64 harvensine_duration; + { + u64 start_time = get_current_time_us(); + 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); + } + harvensine_duration = get_current_time_us() - start_time; + } + + f64 harvensine_sum = 0; + for (int i = 0; i < pairs->count; i++) { + harvensine_sum += harvensines[i]; + } + + printf("Time to calc harvensine: %ldus (%.3lfus/row)\n", harvensine_duration, (f64)harvensine_duration / row_count); + printf("Sum of all harvensines: %.16f\n", harvensine_sum); + + if (reference_harvensines_count > 0) { + printf("Diff of reference harvensine sum: %.16f\n", harvensine_sum - reference_harvensine_sum); + } + + free(reference_harvensines); + free(harvensines); free_json_value(parsed); + free_point_pairs(pairs); return 0; }