mindex.c

In-memory ordered store and fetch library
git clone git://git.finwo.net/lib/mindex.c
Log | Files | Refs | README | LICENSE

commit d7954e0309fbef21f980e59eafe6aaed19f11a79
parent 2c44704a2f6984dbce2d5f1a0acba08c9b306114
Author: Yersa Nordman <yersa@finwo.nl>
Date:   Wed, 22 Mar 2023 22:32:03 +0100

Added basic benchmarking tool for finding bottlenecks

Diffstat:
M.gitignore | 1+
MMakefile | 13++++++++++---
Abenchmark.c | 170+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 181 insertions(+), 3 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,4 @@ /lib/ *.o /test +/benchmark diff --git a/Makefile b/Makefile @@ -1,6 +1,5 @@ SRC:= include config.mk -SRC+=test.c INCLUDES?= INCLUDES+=-I src @@ -10,13 +9,21 @@ override CFLAGS?=-Wall -std=c99 include lib/.dep/config.mk override CFLAGS+=$(INCLUDES) +override CFLAGS+=-D_DEFAULT_SOURCE OBJ=$(SRC:.c=.o) -test: $(OBJ) - $(CC) $(CFLAGS) $(SRC) -o $@ +BIN=\ + benchmark \ + test + +default: $(BIN) + +$(BIN): $(OBJ) $(BIN:=.o) + $(CC) $(CFLAGS) $(OBJ) $@.o -o $@ .PHONY: clean clean: rm -f $(OBJ) + rm -f $(BIN:=.o) rm -f test diff --git a/benchmark.c b/benchmark.c @@ -0,0 +1,170 @@ +#include <errno.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h> +#include <time.h> +#include <unistd.h> + +/* usleep(): Sleep for the requested number of microseconds. */ +int musleep(long usec) { + struct timespec ts; + int res; + + if (usec < 0) { + return -1; + } + + ts.tv_sec = usec / 1000000; + ts.tv_nsec = (usec % 1000000) * 1000; + + do { + res = nanosleep(&ts, &ts); + } while (res && errno == EINTR); + + return res; +} + +#define BMARK(fn) bmark_enqueue((#fn), (fn)) +#define MIN(a,b) ((a<b)?(a):(b)) +#define MAX(a,b) ((a>b)?(a):(b)) + +struct bmark_queue_t { + void *next; + char *name; + void (*fn)(); +}; +struct bmark_ptile_t { + char n; +}; + +struct bmark_queue_t *bmark_queue = NULL; +char bmark_tiles[] = { + 1, + 10, + 50, + 90, + 99, + 0, +}; + +char *units[] = { + "us", + "ms", + "s", + NULL, +}; + +const char *header_description = "Description"; + +void bmark_enqueue(char *name, void (*fn)()) { + struct bmark_queue_t *q = calloc(1, sizeof(struct bmark_queue_t)); + q->name = name; + q->fn = fn; + q->next = bmark_queue; + bmark_queue = q; +} + +// Example time numbers: 12.23 s +// 900.00 ms +// 123.45 us +int bmark_run(int run_count) { + int header_desclen = strlen(header_description); + int i, r, unit; + struct timeval tv_start; + struct timeval tv_end; + + uint64_t *runs = calloc(run_count, sizeof(uint64_t)); + uint64_t run_tmp = 0; + double run_f = 0; + + // Get max description length + struct bmark_queue_t *q_entry = bmark_queue; + while(q_entry) { + header_desclen = MAX(header_desclen, strlen(q_entry->name)); + q_entry = q_entry->next; + } + + printf("\n"); + + // Separator + printf("+-"); + for(i = 0 ; i < header_desclen ; i++) printf("-"); + for(i = 0 ; bmark_tiles[i] ; i++) printf("-+----------"); + printf("-+\n"); + + // Column names + printf("| %-*s |", header_desclen, header_description); + for(i = 0 ; bmark_tiles[i] ; i++) printf(" %*d %% |", 7, bmark_tiles[i]); + printf("\n"); + + // Separator + printf("+-"); + for(i = 0 ; i < header_desclen ; i++) printf("-"); + for(i = 0 ; bmark_tiles[i] ; i++) printf("-+----------"); + printf("-+\n"); + + // Go over the whole queue + q_entry = bmark_queue; + while(q_entry) { + printf("| %-*s |", header_desclen, q_entry->name); + fflush(stdout); + + // Do the actual runs + for(r = 0; r < run_count ; r++) { + gettimeofday(&tv_start, NULL); + q_entry->fn(); + gettimeofday(&tv_end, NULL); + runs[r] = (tv_end.tv_sec*(uint64_t)1000000+tv_end.tv_usec) - (tv_start.tv_sec*(uint64_t)1000000+tv_start.tv_usec); + } + + // Sort the runs + // Basic bubble sort is fine here, we're not going for a speed record + for(r = 0; r < (run_count-1) ; r++) { + if (r < 0) continue; + if (runs[r] > runs[r+1]) { + run_tmp = runs[r]; + runs[r] = runs[r+1]; + runs[r+1] = run_tmp; + r -= 2; + } + } + + // Print percentiles + for(i = 0 ; bmark_tiles[i] ; i++) { + r = bmark_tiles[i] * run_count / 100; + run_f = (double)runs[r]; + unit = 0; + while((run_f > 1000) && units[unit+1]) { + run_f = run_f / 1000; + unit++; + } + printf(" %*.2lf %2s |", 6, run_f, units[unit]); + } + + printf("\n"); + + q_entry = q_entry->next; + } + + // Separator + printf("+-"); + for(i = 0 ; i < header_desclen ; i++) printf("-"); + for(i = 0 ; bmark_tiles[i] ; i++) printf("-+----------"); + printf("-+\n"); + + printf("\n"); + return 0; +} + + +void mindex_some_bmark_method() { + // Intentionally empty + musleep(100); +} + +int main() { + BMARK(mindex_some_bmark_method); + return bmark_run(10000); +}