1
0

use better performance timers

This commit is contained in:
Rokas Puzonas 2023-06-14 21:51:33 +03:00
parent 3726cb5ad0
commit fc35e0d268
6 changed files with 173 additions and 37 deletions

View File

@ -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
View 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
View 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;

View File

@ -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)

View File

@ -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
View 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;
}