diff --git a/Makefile b/Makefile index debe64b..930014e 100644 --- a/Makefile +++ b/Makefile @@ -1,17 +1,22 @@ -CFLAGS=-lm -g -Wall +CFLAGS=-lm -g -Wall -O2 .PHONY := gen_data main +guess_cpu_speed: build/guess_cpu_speed gen_data: build/gen_data main: build/main build/gen_data: src/gen_data.c mkdir -p build - gcc -o build/gen_data src/gen_data.c $(CFLAGS) -O0 + gcc -o build/gen_data src/gen_data.c $(CFLAGS) build/main: src/main.c src/json_parser.c mkdir -p build - gcc -o build/main src/main.c $(CFLAGS) -O0 + gcc -o build/main src/main.c $(CFLAGS) + +build/guess_cpu_speed: src/guess_cpu_speed.c src/timer.c + mkdir -p build + gcc -o build/guess_cpu_speed src/guess_cpu_speed.c $(CFLAGS) clean: rm -r build diff --git a/src/guess_cpu_speed.c b/src/guess_cpu_speed.c new file mode 100644 index 0000000..d2454c9 --- /dev/null +++ b/src/guess_cpu_speed.c @@ -0,0 +1,17 @@ +#include + +#include "harvensine_compute.h" +#include "timer.c" + +int main(int argc, char **argv) +{ + u64 measure_time_ms = 1000; + if (argc >= 2) { + measure_time_ms = atol(argv[1]); + } + + u64 cpu_hz = get_cpu_timer_hz(measure_time_ms); + printf("Measured for %lums, CPU is around %luHz\n", measure_time_ms, cpu_hz); + + return 0; +} diff --git a/src/harvensine_compute.h b/src/harvensine_compute.h new file mode 100644 index 0000000..1480376 --- /dev/null +++ b/src/harvensine_compute.h @@ -0,0 +1,8 @@ +#include + +#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) + +typedef double f64; + +typedef uint32_t u32; +typedef uint64_t u64; diff --git a/src/json_parser.c b/src/json_parser.c index 422dcaf..a78c619 100644 --- a/src/json_parser.c +++ b/src/json_parser.c @@ -5,10 +5,9 @@ #include #include +#include "harvensine_compute.h" #include "json_parser.h" -#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0])) - typedef uint8_t u8; void free_json_object(struct json_object *object) diff --git a/src/main.c b/src/main.c index f98c966..95c2dc6 100644 --- a/src/main.c +++ b/src/main.c @@ -1,17 +1,15 @@ #include #include -#include #include #include #include #include +#include "harvensine_compute.h" +#include "timer.c" #include "json_parser.c" #include "harvensine_formula.c" -typedef uint32_t u32; -typedef uint64_t u64; - struct point_pair { f64 x0; f64 y0; @@ -91,6 +89,8 @@ static void free_point_pairs(struct point_pairs *pairs) int main(int argc, char **argv) { + struct timer total_timer = START_TIMER("Total time"); + if (argc <= 1) { print_usage(argv[0]); return -1; @@ -104,6 +104,7 @@ int main(int argc, char **argv) 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); @@ -135,68 +136,84 @@ int main(int argc, char **argv) fclose(f); } + END_TIMER(read_files_timer); // Step 1. Read json file - u64 json_parse_duration; + struct timer json_parse_timer = START_TIMER("Parse JSON"); 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; } + 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); } - 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); + 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)); - 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; + 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); - printf("Time to calc harvensine: %ldus (%.3lfus/row)\n", harvensine_duration, (f64)harvensine_duration / row_count); + + 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); } - free(reference_harvensines); - free(harvensines); - free_json_value(parsed); - free_point_pairs(pairs); + 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; } diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 0000000..549305f --- /dev/null +++ b/src/timer.c @@ -0,0 +1,90 @@ +#include "harvensine_compute.h" + +#ifdef WIN32 + +#include +#include + +static u64 get_os_timer_hz(void) +{ + LARGE_INTEGER Freq; + QueryPerformanceFrequency(&Freq); + return Freq.QuadPart; +} + +static u64 read_os_timer(void) +{ + LARGE_INTEGER Value; + QueryPerformanceCounter(&Value); + return Value.QuadPart; +} + +#else + +#include +#include + +static u64 get_os_timer_hz(void) +{ + return 1000000000; +} + +static u64 read_os_timer(void) +{ + struct timespec time; + clock_gettime(CLOCK_MONOTONIC_RAW, &time); + return get_os_timer_hz()*time.tv_sec + time.tv_nsec; +} + +#endif // WIN32 + + +static u64 read_cpu_timer(void) +{ + return __rdtsc(); +} + +static u64 get_cpu_timer_hz(u64 measure_time_ms) +{ + u64 os_freq = get_os_timer_hz(); + u64 os_start = read_os_timer(); + u64 os_elapsed = 0; + + u64 cpu_start = read_cpu_timer(); + + u64 wait_duration = os_freq * measure_time_ms / 1000; + while (os_elapsed < wait_duration) { + os_elapsed = read_os_timer() - os_start; + } + + u64 cpu_elapsed = read_cpu_timer() - cpu_start; + if (os_elapsed) { + return os_freq * cpu_elapsed / os_elapsed; + } else { + return 0; + } +} + +#define START_TIMER(display) { \ + .start = read_cpu_timer(), \ + .end = 0, \ + .name = display \ + } + +#define END_TIMER(timespan) timespan.end = read_cpu_timer() + +#define TIMER_DURATION(timer) (timer.end - timer.start) + +struct timer { + char *name; + u64 start, end; +}; + +static u64 sum_timer(struct timer *timers, size_t count) +{ + u64 sum = 0; + for (int i = 0; i < count; i++) { + sum += TIMER_DURATION(timers[i]); + } + return sum; +}