Commit 4e1cf696 authored by Florian Fischer's avatar Florian Fischer
Browse files

implement descriptive stats reporting

parent 35bf403c
BENCH_MAIN := bench.c
SYSCALLS := blocking io-uring io-uring-sqpoll io-uring-no-syscall epoll paio-sig paio-thrd
STATS ?=
OBJ := $(addprefix bench-,$(SYSCALLS))
LDFLAGS := -luring -pthread -lrt
LDFLAGS := -luring -pthread -lrt -lm
CFLAGS := -Werror -Wall -g -O3
# CFLAGS := -Werror -Wall -g -O0
......@@ -11,7 +13,7 @@ CFLAGS := -Werror -Wall -g -O3
.PHONY: all clean eval docker-eval check
eval: all
@for syscall in $(SYSCALLS); do echo -n "$$syscall " ; ./bench-$$syscall; done
@for syscall in $(SYSCALLS); do echo -n "$$syscall " ; ./bench-$$syscall $(STATS); done
docker-eval:
./docker.sh make eval
......@@ -19,7 +21,7 @@ docker-eval:
all: $(OBJ)
define generateTargets
bench-$(1): $(1).c bench.c stopwatch.c | Makefile
bench-$(1): $(1).c bench.c stopwatch.c stats.c | Makefile
$(CC) $(CFLAGS) -o $$@ $$^ $(LDFLAGS)
endef
......
#include <err.h>
#include <fcntl.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/eventfd.h>
#include "stats.h"
#include "stopwatch.h"
void init(int fd);
......@@ -23,9 +26,11 @@ static int create_eventfd() {
return fd;
}
int main() {
uint64_t cycles_sum = 0;
uint64_t nanos_sum = 0;
int main(int argc, char *argv[]) {
bool print_stats = false;
if (argc > 2 || (argc == 2 && !(print_stats = (strcmp(argv[1], "--stats") == 0))))
errx(EXIT_SUCCESS, "Usage: %s [--stats]", argv[0]);
uint64_t write_buf = 1;
int fd = create_eventfd();
......@@ -34,24 +39,30 @@ int main() {
const size_t exp_warmup = warmup;
const size_t exp_iterations = iterations;
uint64_t *nanos = malloc(exp_iterations * sizeof(uint64_t));
uint64_t *cycles = malloc(exp_iterations * sizeof(uint64_t));
if (!nanos || !cycles) err(EXIT_FAILURE, "allocating memory for our results failed");
if (exp_iterations == 0) errx(EXIT_FAILURE, "experiment must do at least one iteration");
for (size_t i = 0; i < exp_warmup; ++i) do_write(fd, &write_buf, sizeof(write_buf));
for (int64_t i = 1; i <= exp_iterations; ++i) {
do_write(fd, &write_buf, sizeof(write_buf));
if (__builtin_add_overflow(nanos_sum, clock_diff_nanos(), &nanos_sum))
errx(EXIT_FAILURE, "nanos overflowed at %ld", i);
if (__builtin_add_overflow(cycles_sum, clock_diff_cycles(), &cycles_sum))
errx(EXIT_FAILURE, "cycles overflowed at %ld", i);
nanos[i] = clock_diff_nanos();
cycles[i] = clock_diff_cycles();
}
// Since uint64_t <-> double conversion are not well defined
// and we use really small units (cycles and nanoseconds) I am willing
// to accept that we throw away anything after the decimal point.
uint64_t avg_nanos = nanos_sum / exp_iterations;
uint64_t avg_cycles = cycles_sum / exp_iterations;
if (print_stats) {
print_desc_stats("nanos", nanos, exp_iterations);
print_desc_stats("cycles", cycles, exp_iterations);
} else {
uint64_t avg_nanos = calc_mean(nanos, exp_iterations);
uint64_t avg_cycles = calc_mean(cycles, exp_iterations);
printf("avg-nanos: %lu, avg-cycles: %lu\n", avg_nanos, avg_cycles);
}
printf("%lu ns, %lu cycles\n", avg_nanos, avg_cycles);
free(nanos);
free(cycles);
return 0;
}
#include "stats.h"
#include <err.h>
#include <math.h>
#include <stdint.h>
#include <stdio.h>
uint64_t calc_median(uint64_t* data, size_t size) {
// sample size is odd -> there is a middle value
if (size % 2 == 1) return data[size / 2];
// sample size is even calculate a virtual middle value
const uint64_t before_median = data[size / 2];
const uint64_t after_median = data[(size / 2) + 1];
return before_median + ((after_median - before_median) / 2);
}
uint64_t calc_mean(uint64_t* data, size_t size) {
uint64_t sum = 0;
for (size_t i = 0; i < size; ++i) {
if (__builtin_add_overflow(sum, data[i], &sum)) errx(EXIT_FAILURE, "sum overflowed at %ld", i);
}
return sum / size;
}
uint64_t calc_var(uint64_t* data, size_t size, uint64_t mean) {
uint64_t sum = 0;
for (size_t i = 0; i < size; ++i) {
const int64_t delta = mean - data[i];
const uint64_t delta_pow = (uint64_t)pow((double)delta, 2);
if (__builtin_add_overflow(sum, delta_pow, &sum))
errx(EXIT_FAILURE, "sum overflowed at %ld", i);
}
return sum / size;
}
static int compare_uint64_t(const void* v1, const void* v2) {
const uint64_t x1 = *(uint64_t*)v1;
const uint64_t x2 = *(uint64_t*)v2;
if (x1 < x2) return -1;
if (x1 > x2) return 1;
return 0;
}
void print_desc_stats(const char* name, uint64_t* data, size_t size) {
// sort our data
qsort(data, size, sizeof(uint64_t), compare_uint64_t);
const uint64_t min = data[0];
const uint64_t max = data[size - 1];
const uint64_t median = calc_median(data, size);
const uint64_t mean = calc_mean(data, size);
const uint64_t var = calc_var(data, size, mean);
const uint64_t std = (uint64_t)sqrt((double)var);
printf("%s-min: %lu\n", name, min);
printf("%s-max: %lu\n", name, max);
printf("%s-median: %lu\n", name, median);
printf("%s-mean: %lu\n", name, mean);
printf("%s-var: %lu\n", name, var);
printf("%s-std: %lu\n", name, std);
}
#pragma once
#include "stdint.h"
#include "stdlib.h"
uint64_t calc_mean(uint64_t* data, size_t size);
uint64_t calc_median(uint64_t* data, size_t size);
uint64_t calc_var(uint64_t* data, size_t size, uint64_t mean);
void print_desc_stats(const char* name, uint64_t* data, size_t size);
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment