use better performance timers
This commit is contained in:
parent
3726cb5ad0
commit
fc35e0d268
11
Makefile
11
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
|
||||
|
17
src/guess_cpu_speed.c
Normal file
17
src/guess_cpu_speed.c
Normal file
@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
|
||||
#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;
|
||||
}
|
8
src/harvensine_compute.h
Normal file
8
src/harvensine_compute.h
Normal file
@ -0,0 +1,8 @@
|
||||
#include <inttypes.h>
|
||||
|
||||
#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
|
||||
|
||||
typedef double f64;
|
||||
|
||||
typedef uint32_t u32;
|
||||
typedef uint64_t u64;
|
@ -5,10 +5,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#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)
|
||||
|
81
src/main.c
81
src/main.c
@ -1,17 +1,15 @@
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <inttypes.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"
|
||||
|
||||
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;
|
||||
}
|
||||
|
90
src/timer.c
Normal file
90
src/timer.c
Normal file
@ -0,0 +1,90 @@
|
||||
#include "harvensine_compute.h"
|
||||
|
||||
#ifdef WIN32
|
||||
|
||||
#include <intrin.h>
|
||||
#include <windows.h>
|
||||
|
||||
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 <x86intrin.h>
|
||||
#include <time.h>
|
||||
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue
Block a user