220 lines
5.9 KiB
C
220 lines
5.9 KiB
C
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <math.h>
|
|
|
|
#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 <json-file> [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;
|
|
}
|