1
0

add repetition tester

This commit is contained in:
Rokas Puzonas 2023-08-30 00:18:00 +03:00
parent 3b8986e008
commit 828de96add
6 changed files with 290 additions and 2 deletions

View File

@ -14,6 +14,10 @@ build/main: src/main.c src/json_parser.c src/rprof.h
mkdir -p build
gcc -o build/main src/main.c $(CFLAGS)
build/test: src/tests.c src/repetition_tester.c
mkdir -p build
gcc -o build/test src/tests.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)

1
compile_flags.txt Normal file
View File

@ -0,0 +1 @@
-DRPROF_IMPLEMENTATION

View File

@ -5,13 +5,14 @@
#include <time.h>
#include <math.h>
#define RPROF_IMPLEMENTATION
#include "harvensine_compute.h"
#include "rprof.h"
#include "json_parser.c"
#include "harvensine_formula.c"
#define RPROF_IMPLEMENTATION
#include "rprof.h"
struct point_pair {
f64 x0;
f64 y0;

162
src/repetition_tester.c Normal file
View File

@ -0,0 +1,162 @@
#include <inttypes.h>
#include <string.h>
#include "rprof.h"
enum tester_state {
STATE_UNKNOWN,
STATE_RUNNING,
STATE_FINISHED,
STATE_ERROR
};
struct repetition_tester {
enum tester_state state;
uint64_t cpu_freq;
uint32_t testing_timeout;
uint64_t expected_byte_count;
uint64_t last_found_min_time;
bool show_current_min;
uint32_t closed_blocks;
uint32_t opened_blocks;
uint64_t test_running_time;
uint64_t test_running_bytes;
};
struct repetition_results {
uint64_t test_count;
uint64_t total_time;
uint64_t min_time;
uint64_t max_time;
};
typedef void (*test_cb)(struct repetition_tester*, void *user);
void repetition_tester_init(struct repetition_tester *tester) {
tester->cpu_freq = rprof_get_cpu_timer_hz(100);
tester->testing_timeout = 10;
}
void repetition_tester_error(struct repetition_tester *tester, char *message) {
tester->state = STATE_ERROR;
printf("Error during repetition: %s\n", message);
}
void print_repetition_time(char *label, float cpu_time, uint64_t bytes, uint64_t cpu_freq) {
printf("%s: %.0f", label, cpu_time);
if (cpu_freq) {
float seconds_time = (float)cpu_time/(float)cpu_freq;
printf(" (%fms)", seconds_time*1000.0);
if (bytes) {
float gigabyte = 1024 * 1024 * 1024;
float bandwidth = bytes / (gigabyte * seconds_time);
printf(" at %fgb/s", bandwidth);
}
}
}
bool repetition_tester_continue(struct repetition_tester *tester, struct repetition_results *results) {
if (tester->state != STATE_RUNNING) {
return false;
}
if (tester->opened_blocks == 0) {
return true;
}
if (tester->opened_blocks != tester->closed_blocks) {
repetition_tester_error(tester, "Closed blocks doesn't match opened blocks");
return false;
}
if (tester->expected_byte_count != tester->test_running_bytes) {
repetition_tester_error(tester, "Processed byte coutn doesn't match");
return false;
}
uint64_t now = rprof_read_cpu_timer();
results->test_count += 1;
results->total_time += tester->test_running_time;
results->max_time = MAX(results->max_time, tester->test_running_time);
if (tester->test_running_time < results->min_time) {
results->min_time = tester->test_running_time;
tester->last_found_min_time = now;
if (tester->show_current_min) {
printf("\r");
print_repetition_time("Min", tester->test_running_time, tester->test_running_bytes, tester->cpu_freq);
fflush(stdout);
}
}
tester->opened_blocks = 0;
tester->closed_blocks = 0;
tester->test_running_bytes = 0;
tester->test_running_time = 0;
uint64_t time_since_last_find = (now - tester->last_found_min_time);
if ((time_since_last_find / tester->cpu_freq) >= tester->testing_timeout) {
tester->state = STATE_FINISHED;
return false;
}
return true;
}
int repetition_test_run(struct repetition_tester *tester, uint64_t expected_byte_count, struct repetition_results *results, test_cb cb, void *user) {
memset(results, 0, sizeof(struct repetition_results));
tester->state = STATE_RUNNING;
tester->expected_byte_count = expected_byte_count;
tester->last_found_min_time = rprof_read_cpu_timer();
results->min_time = UINT64_MAX;
results->max_time = 0;
results->test_count = 0;
results->total_time = 0;
while (repetition_tester_continue(tester, results)) {
cb(tester, user);
}
if (tester->show_current_min) {
printf("\n");
}
if (tester->state == STATE_ERROR) {
return -1;
}
return 0;
}
void print_repetition_results(struct repetition_tester *tester, struct repetition_results *results) {
print_repetition_time("Min", results->min_time, tester->expected_byte_count, tester->cpu_freq);
printf("\n");
print_repetition_time("Max", results->max_time, tester->expected_byte_count, tester->cpu_freq);
printf("\n");
if (results->test_count) {
uint64_t avg_time = results->total_time/results->test_count;
print_repetition_time("Avg", avg_time, tester->expected_byte_count, tester->cpu_freq);
printf("\n");
}
}
void repetition_time_start(struct repetition_tester *tester) {
tester->opened_blocks++;
tester->test_running_time -= rprof_read_cpu_timer();
}
void repetition_time_end(struct repetition_tester *tester) {
tester->closed_blocks++;
tester->test_running_time += rprof_read_cpu_timer();
}
void repetition_count_bytes(struct repetition_tester *tester, int bytes) {
tester->test_running_bytes += bytes;
}

View File

@ -76,6 +76,7 @@ void rprof_output(prof_sort_cmp_cb sort_cb);
#define RPROF_START_BYTES(label, bytes) rprof_start(__COUNTER__, label, bytes)
#define RPROF_STOP() rprof_stop()
#define RPROF_IMPLEMENTATION
#ifdef RPROF_IMPLEMENTATION
// ------------------------ CPU Timing -------------------------

119
src/tests.c Normal file
View File

@ -0,0 +1,119 @@
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "repetition_tester.c"
#define RPROF_IMPLEMENTATION
#include "rprof.h"
#define ARRAY_LEN(x) (sizeof(x)/sizeof(x[0]))
size_t get_file_size(char *filename)
{
FILE *f = fopen(filename, "r");
if (f == NULL) { return 0; }
fseek(f, 0, SEEK_END);
size_t size = ftell(f);
fclose(f);
return size;
}
struct test_params {
char *filename;
uint8_t *buffer;
uint64_t byte_count;
};
struct testcase {
char *name;
test_cb cb;
};
void test_fread(struct repetition_tester *tester, void *user)
{
struct test_params *params = user;
FILE *f = fopen(params->filename, "r");
if (f == NULL) {
repetition_tester_error(tester, "Failed to open file");
return;
}
repetition_time_start(tester);
int result = fread(params->buffer, params->byte_count, 1, f);
repetition_time_end(tester);
if (result <= 0) {
repetition_tester_error(tester, "Failed to read file");
goto err;
}
repetition_count_bytes(tester, params->byte_count);
err:
fclose(f);
}
void test_read(struct repetition_tester *tester, void *user)
{
struct test_params *params = user;
int fd = open(params->filename, O_RDONLY);
if (fd <= 0) {
repetition_tester_error(tester, "Failed to open file");
return;
}
repetition_time_start(tester);
int result = read(fd, params->buffer, params->byte_count);
repetition_time_end(tester);
if (result <= 0) {
repetition_tester_error(tester, "Failed to read file");
goto err;
}
repetition_count_bytes(tester, result);
err:
close(fd);
}
int main()
{
struct repetition_tester tester = { 0 };
repetition_tester_init(&tester);
tester.show_current_min = true;
char *filename = "data_10000000.json";
uint64_t file_size = get_file_size(filename);
uint8_t *buffer = malloc(sizeof(uint8_t) * file_size);
struct test_params params = {
.filename = filename,
.buffer = buffer,
.byte_count = file_size
};
struct testcase cases[] = {
{ .name = "fread", .cb = test_fread },
{ .name = "read", .cb = test_read },
};
struct repetition_results results = { 0 };
while (true) {
for (int i = 0; i < ARRAY_LEN(cases); i++) {
struct testcase *testcase = &cases[i];
if (repetition_test_run(&tester, file_size, &results, testcase->cb, &params)) {
return -1;
}
printf("----- %s -----\n", testcase->name);
print_repetition_results(&tester, &results);
printf("\n");
}
}
free(buffer);
return 0;
}