diff --git a/Makefile.inc b/Makefile.inc index bfdc3dc..62356af 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -16,6 +16,8 @@ includedir = $(prefix)/include libdir = $(prefix)/lib -include $(ROOTDIR)/Makefile.conf +AR=ar +RANLIB=ranlib CFLAGS += -g -std=c99 -pipe -Wall LDFLAGS += -g @@ -30,10 +32,10 @@ LDFLAGS += -nostdlib -Wl,-e,_start,-Bstatic $(libdir)/crti.o $(libdir)/crt1.o $( INC += -isystem $(includedir) endif -all: t +all: t b clean: - rm -f $(OBJS) t main.o main.h + rm -f $(OBJS) t main.o main.h b bench.o tests.a .c.o: $(CC) $(CFLAGS) $(INC) -c -o $@ $< @@ -41,12 +43,25 @@ clean: $(OBJS): $(ROOTDIR)/common/test.h main.h: $(OBJS) - nm -f posix $+ |awk '/^test/ && $$2=="T"{print "T(" $$1 ")"}' >main.h + nm -f posix $+ |awk ' \ + /^test/ && $$2=="T"{print "T(" $$1 ")"} \ + /^bench/ && $$2=="T"{print "B(" $$1 ")"} \ + ' >main.h + +tests.a: $(OBJS) + $(AR) rc $@ $+ + $(RANLIB) $@ main.o: $(ROOTDIR)/common/main.c $(ROOTDIR)/common/test.h main.h $(CC) $(CFLAGS) $(INC) -I. -c -o $@ $< -t: $(OBJS) main.o +t: main.o tests.a $(CC) $+ $(LDFLAGS) -o $@ +bench.o: $(ROOTDIR)/common/bench.c $(ROOTDIR)/common/test.h main.h + $(CC) $(CFLAGS) $(INC) -I. -c -o $@ $< + +b: bench.o tests.a + $(CC) $+ $(LDFLAGS) -lrt -o $@ + .PHONY: all clean diff --git a/common/bench.c b/common/bench.c new file mode 100644 index 0000000..0436f67 --- /dev/null +++ b/common/bench.c @@ -0,0 +1,101 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include "test.h" + +#define T(t) +#define B(t) void t(); +#include "main.h" +#undef B + +//static int verbose; + +void error__(const char *n, int l, const char *s, ...) { + fprintf(stderr, "use error in tests only\n"); +} + +int N; +static unsigned long long start; +static unsigned long long ns; +//static unsigned long long bytes; + +#define SEC 1000000000ULL +#define MAXN 1000000000 + +static unsigned long long nsclock() { + struct timespec ts; + int r; + +#ifdef _POSIX_CPUTIME + r = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); +#else +#ifdef _POSIX_MONOTONIC_CLOCK + r = clock_gettime(CLOCK_MONOTONIC, &ts); +#else + r = clock_gettime(CLOCK_REALTIME, &ts); +#endif +#endif + if (r < 0) { + fprintf(stderr, "bench: clock_gettime failed: %s\n", strerror(errno)); + return 0; + } + return ts.tv_sec*SEC + ts.tv_nsec; +} + +void start_timer() { + if (!start) + start = nsclock(); +} + +void stop_timer() { + if (start) + ns += nsclock() - start; + start = 0; +} + +void reset_timer() { + if (start) + start = nsclock(); + ns = 0; +} + +static int nextN() { + unsigned long long n = 2*SEC/(ns/N + 1); + if (n > N*100ULL) + n = N*100ULL; + else if (n <= N) + n = N+1; + if (n > MAXN) + n = MAXN; + return n; +} + +static void run(const char *name, void (*f)()) { + fprintf(stderr, "%s:", name); + for (N=1; ; N=nextN()) { + reset_timer(); + start_timer(); + f(); + stop_timer(); +// fprintf(stderr, "%10d%12llu\n", N, ns); + if (ns > SEC || N >= MAXN) + break; + if (N <= 0) { + fprintf(stderr, "bench: fatal: N <= 0\n"); + return; + } + } + if (ns/N > 100) + fprintf(stderr, "%10d%10llu ns/op\n", N, ns/N); + else + fprintf(stderr, "%10d%13.2f ns/op\n", N, (double)ns/N); +} + +int main() { +#define B(t) run(#t, t); +#include "main.h" + return 0; +} diff --git a/common/main.c b/common/main.c index 02e5f1f..02d77c7 100644 --- a/common/main.c +++ b/common/main.c @@ -4,12 +4,12 @@ #include #include #include -#include #include #include #include #include "test.h" +#define B(t) #define T(t) void t(); #include "main.h" #undef T @@ -21,6 +21,12 @@ static int verbose; static int count; static int nfailed; +static void errtimer() { error("use *_timer in benchmarks only\n"); } +int N = 0; +void start_timer() { errtimer(); } +void stop_timer() { errtimer(); } +void reset_timer() { errtimer(); } + void error__(const char *n, int l, const char *s, ...) { va_list ap; diff --git a/common/test.h b/common/test.h index b403c05..ed8adda 100644 --- a/common/test.h +++ b/common/test.h @@ -1,2 +1,9 @@ +/* use it in test_ functions */ #define error(...) error__(__FILE__, __LINE__, __VA_ARGS__) void error__(const char *n, int l, const char *s, ...); + +/* use it in bench_ functions */ +extern int N; +void start_timer(void); +void stop_timer(void); +void reset_timer(void); diff --git a/src/foo/Makefile b/src/foo/Makefile new file mode 100644 index 0000000..ee4552b --- /dev/null +++ b/src/foo/Makefile @@ -0,0 +1 @@ +include ../../Makefile.inc diff --git a/src/foo/foo.c b/src/foo/foo.c new file mode 100644 index 0000000..637d7fa --- /dev/null +++ b/src/foo/foo.c @@ -0,0 +1,28 @@ +#include "test.h" + +// dummy test + +static unsigned foo(unsigned n) { + int i; + + for (i = 0; i < 10; i++) { + n = n*n; + n = n+123; + n = n/7; + } + return n; +} + +void bench_foo() { + int i; + + for (i = 0; i < N; i++) + foo(3); +} + +void test_foo() { + unsigned n = foo(3); + + if (n != 123) + error("foo(3):%u expected 123\n", n); +}