commit 1b3e1792d499b39195b28f668d011b6148d5889b
parent 2e873d657915a209edf8c0518cea1503adbb106f
Author: finwo <finwo@pm.me>
Date: Sat, 25 Mar 2023 00:06:41 +0100
Import from mindex library
Diffstat:
8 files changed, 244 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,2 @@
+/test
+*.o
diff --git a/Makefile b/Makefile
@@ -0,0 +1,29 @@
+SRC:=
+include config.mk
+
+INCLUDES?=
+INCLUDES+=-I src
+
+# override CFLAGS?=-Wall -std=c99
+override CFLAGS?=-Wall
+
+# include lib/.dep/config.mk
+
+override CFLAGS+=$(INCLUDES)
+# override CFLAGS+=-D_DEFAULT_SOURCE
+
+OBJ=$(SRC:.c=.o)
+
+BIN=\
+ 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/__DIRNAME b/__DIRNAME
@@ -0,0 +1 @@
+.
+\ No newline at end of file
diff --git a/config.mk b/config.mk
@@ -0,0 +1 @@
+SRC+=__DIRNAME/src/benchmark.c
diff --git a/package.ini b/package.ini
@@ -0,0 +1,6 @@
+[export]
+config.mk=config.mk
+include/finwo/benchmark.h=src/benchmark.h
+[package]
+deps=lib
+name=finwo/benchmark
diff --git a/src/benchmark.c b/src/benchmark.c
@@ -0,0 +1,132 @@
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "benchmark.h"
+
+struct bmark_queue_t {
+ void *next;
+ char *name;
+ void (*fn)();
+};
+struct bmark_ptile_t {
+ char n;
+};
+
+struct bmark_queue_t *bmark_queue = NULL;
+
+struct bmark_unit_entry {
+ char *name;
+ int next;
+};
+
+struct bmark_unit_entry units[] = {
+ { "us", 1000 },
+ { "ms", 1000 },
+ { "s" , 60 },
+ { "m" , 0 },
+};
+
+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, char percentiles[]) {
+ 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 ; percentiles[i] ; i++) printf("-+----------");
+ printf("-+\n");
+
+ // Column names
+ printf("| %-*s |", header_desclen, header_description);
+ for(i = 0 ; percentiles[i] ; i++) printf(" %*d %% |", 7, percentiles[i]);
+ printf("\n");
+
+ // Separator
+ printf("+-");
+ for(i = 0 ; i < header_desclen ; i++) printf("-");
+ for(i = 0 ; percentiles[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 ; percentiles[i] ; i++) {
+ r = percentiles[i] * (run_count-1) / 100;
+ run_f = (double)runs[r];
+ unit = 0;
+ while((run_f > units[unit].next) && units[unit].next) {
+ run_f = run_f / units[unit].next;
+ unit++;
+ }
+ printf(" %*.2lf %2s |", 6, run_f, units[unit].name);
+ }
+
+ printf("\n");
+
+ q_entry = q_entry->next;
+ }
+
+ // Separator
+ printf("+-");
+ for(i = 0 ; i < header_desclen ; i++) printf("-");
+ for(i = 0 ; percentiles[i] ; i++) printf("-+----------");
+ printf("-+\n");
+
+ printf("\n");
+ return 0;
+}
diff --git a/src/benchmark.h b/src/benchmark.h
@@ -0,0 +1,17 @@
+#ifndef __FINWO_BENCHMARK_H__
+#define __FINWO_BENCHMARK_H__
+
+#ifndef MIN
+#define MIN(a,b) ((a<b)?(a):(b))
+#endif
+
+#ifndef MAX
+#define MAX(a,b) ((a>b)?(a):(b))
+#endif
+
+#define BMARK(fn) bmark_enqueue((#fn), (fn))
+
+void bmark_enqueue(char *name, void (*fn)());
+int bmark_run(int run_count, char percentiles[]);
+
+#endif // __FINWO_BENCHMARK_H__
diff --git a/test.c b/test.c
@@ -0,0 +1,55 @@
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "benchmark.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;
+}
+
+
+void mindex_some_bmark_method() {
+ // Intentionally empty
+ musleep(100 + (rand() % 100));
+}
+
+int main() {
+
+ // Seed random
+ unsigned int seed;
+ FILE* urandom = fopen("/dev/urandom", "r");
+ fread(&seed, sizeof(int), 1, urandom);
+ fclose(urandom);
+ srand(seed);
+
+ // Enqueue benchmarks
+ BMARK(mindex_some_bmark_method);
+
+ char percentiles[] = {
+ 1 , 5, 20,
+ 50,
+ 80, 95, 99,
+ 0
+ };
+
+ // Run & return
+ return bmark_run(100, percentiles);
+}