diff --git a/Makefile.inc b/Makefile.inc index 62356af..10f3e8a 100644 --- a/Makefile.inc +++ b/Makefile.inc @@ -35,12 +35,12 @@ endif all: t b clean: - rm -f $(OBJS) t main.o main.h b bench.o tests.a + rm -f $(OBJS) t t.o main.h b b.o tests.a .c.o: $(CC) $(CFLAGS) $(INC) -c -o $@ $< -$(OBJS): $(ROOTDIR)/common/test.h +$(OBJS): $(ROOTDIR)/common/test.h $(ROOTDIR)/Makefile.conf main.h: $(OBJS) nm -f posix $+ |awk ' \ @@ -52,16 +52,16 @@ tests.a: $(OBJS) $(AR) rc $@ $+ $(RANLIB) $@ -main.o: $(ROOTDIR)/common/main.c $(ROOTDIR)/common/test.h main.h +t.o: $(ROOTDIR)/common/t.c $(ROOTDIR)/common/test.h main.h $(CC) $(CFLAGS) $(INC) -I. -c -o $@ $< -t: main.o tests.a +t: t.o tests.a $(CC) $+ $(LDFLAGS) -o $@ -bench.o: $(ROOTDIR)/common/bench.c $(ROOTDIR)/common/test.h main.h +b.o: $(ROOTDIR)/common/b.c $(ROOTDIR)/common/test.h main.h $(CC) $(CFLAGS) $(INC) -I. -c -o $@ $< -b: bench.o tests.a +b: b.o tests.a $(CC) $+ $(LDFLAGS) -lrt -o $@ .PHONY: all clean diff --git a/common/b.c b/common/b.c new file mode 100644 index 0000000..b82531c --- /dev/null +++ b/common/b.c @@ -0,0 +1,136 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define T(t) +#define B(t) void t(); +#include "main.h" +#undef B + +static int verbose = 1; + +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 dt; +//static unsigned long long bytes; + +#define SEC 1000000000ULL +#define MAXN 500000000 + +static unsigned long long tic() { + struct timespec ts; + + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 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 = tic(); +} + +void stop_timer() { + if (start) + dt += tic() - start; + start = 0; +} + +void reset_timer() { + if (start) + start = tic(); + dt = 0; +} + +static int nextN() { + unsigned long long n = dt/N; + + if (n) + n = SEC/2/n; + else + n = SEC/2; + n += n/2; + if (n > N*100ULL) + n = N*100ULL; + else if (n <= N) + n = N+1; + if (n > MAXN) + n = MAXN; + return n; +} + +void vmstats() { + FILE *f; + char buf[256]; + int maj, min, in_heap=0; + unsigned long l; + size_t vm_size=0, vm_rss=0, vm_priv_dirty=0; + + f = fopen("/proc/self/smaps", "rb"); + if (f) while (fgets(buf, sizeof buf, f)) { + if (sscanf(buf, "%*lx-%*lx %*s %*lx %x:%x %*lu %*s", &maj, &min)==2) + in_heap = (!maj && !min && !strstr(buf, "---p") && (strstr(buf, "[heap]") || !strchr(buf, '['))); + if (in_heap) { + if (sscanf(buf, "Size: %lu", &l)==1) vm_size += l; + else if (sscanf(buf, "Rss: %lu", &l)==1) vm_rss += l; + else if (sscanf(buf, "Private_Dirty: %lu", &l)==1) vm_priv_dirty += l; + } + } + if (f) fclose(f); + fprintf(stderr, " %7zu virt %7zu res %7zu dirty", vm_size, vm_rss, vm_priv_dirty); +} + +void stats() { + if (dt/N > 100) + fprintf(stderr, "%10d N %10llu ns/op ", N, dt/N); + else + fprintf(stderr, "%10d N %13.2f ns/op", N, (double)dt/N); + if (verbose) + vmstats(); + fputc('\n', stderr); +} + +static void run(const char *name, void (*f)()) { + int p = fork(); + if (p) { + int s; + if (p<0 || wait(&s)<0 || !WIFEXITED(s) || WEXITSTATUS(s)) + fprintf(stderr, "benchmark %s failed\n", name); + return; + } + fprintf(stderr, "%-32s", name); + for (N=1; ; N=nextN()) { + reset_timer(); + start_timer(); + f(); + stop_timer(); +// fprintf(stderr, "%10d%12llu next: %d\n", N, dt, nextN()); + if (dt >= SEC/2 || N >= MAXN) { + stats(); + exit(0); + } + if (N <= 0) { + fprintf(stderr, "bench: fatal: N <= 0\n"); + exit(1); + } + } +} + +int main() { +#define B(t) run(#t, t); +#include "main.h" + return 0; +} diff --git a/common/bench.c b/common/bench.c deleted file mode 100644 index ee6daa1..0000000 --- a/common/bench.c +++ /dev/null @@ -1,97 +0,0 @@ -#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 dt; -//static unsigned long long bytes; - -#define SEC 1000000000ULL -#define MAXN 1000000000 - -static unsigned long long tic() { - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) < 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 = tic(); -} - -void stop_timer() { - if (start) - dt += tic() - start; - start = 0; -} - -void reset_timer() { - if (start) - start = tic(); - dt = 0; -} - -static int nextN() { - unsigned long long n = dt/N; - - if (n) - n = SEC/n; - else - n = SEC; - n += n/4; - 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 (dt >= SEC || N >= MAXN) - break; - if (N <= 0) { - fprintf(stderr, "bench: fatal: N <= 0\n"); - return; - } - } - if (dt/N > 100) - fprintf(stderr, "%10d%10llu ns/op\n", N, dt/N); - else - fprintf(stderr, "%10d%13.2f ns/op\n", N, (double)dt/N); -} - -int main() { -#define B(t) run(#t, t); -#include "main.h" - return 0; -} diff --git a/common/main.c b/common/main.c deleted file mode 100644 index 02d77c7..0000000 --- a/common/main.c +++ /dev/null @@ -1,84 +0,0 @@ -#define _POSIX_C_SOURCE 200809L -#include -#include -#include -#include -#include -#include -#include -#include -#include "test.h" - -#define B(t) -#define T(t) void t(); -#include "main.h" -#undef T - -static int failed; -static const char *name; - -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; - - failed = 1; - fprintf(stderr, "- ERROR %s at %s:%d: ", name, n, l); - va_start(ap, s); - vfprintf(stderr, s, ap); - va_end(ap); -} - -static void run(const char *n, void (*f)()) { - pid_t pid; - int s; - - count++; - failed = 0; - name = n; - if (verbose) - fprintf(stderr, "running %s:\n", name); - - pid = fork(); - if (pid == 0) { - /* run test in a child process */ - f(); - exit(failed); - } - - if (pid == -1) - error("fork failed: %s\n", strerror(errno)); - else { - if (waitpid(pid, &s, 0) == -1) - error("waitpid failed: %s\n", strerror(errno)); - else if (!WIFEXITED(s)) - error("abnormal exit: %s\n", WIFSIGNALED(s) ? strsignal(WTERMSIG(s)) : "(unknown)"); - else - failed = !!WEXITSTATUS(s); - } - - if (failed) { - nfailed++; - fprintf(stderr, "FAILED %s\n", name); - } else if (verbose) - fprintf(stderr, "PASSED %s\n", name); -} - -static int summary() { - fprintf(stderr, "PASS:%d FAIL:%d\n", count-nfailed, nfailed); - return !!nfailed; -} - -int main() { -#define T(t) run(#t, t); -#include "main.h" - return summary(); -} diff --git a/common/t.c b/common/t.c new file mode 100644 index 0000000..02d77c7 --- /dev/null +++ b/common/t.c @@ -0,0 +1,84 @@ +#define _POSIX_C_SOURCE 200809L +#include +#include +#include +#include +#include +#include +#include +#include +#include "test.h" + +#define B(t) +#define T(t) void t(); +#include "main.h" +#undef T + +static int failed; +static const char *name; + +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; + + failed = 1; + fprintf(stderr, "- ERROR %s at %s:%d: ", name, n, l); + va_start(ap, s); + vfprintf(stderr, s, ap); + va_end(ap); +} + +static void run(const char *n, void (*f)()) { + pid_t pid; + int s; + + count++; + failed = 0; + name = n; + if (verbose) + fprintf(stderr, "running %s:\n", name); + + pid = fork(); + if (pid == 0) { + /* run test in a child process */ + f(); + exit(failed); + } + + if (pid == -1) + error("fork failed: %s\n", strerror(errno)); + else { + if (waitpid(pid, &s, 0) == -1) + error("waitpid failed: %s\n", strerror(errno)); + else if (!WIFEXITED(s)) + error("abnormal exit: %s\n", WIFSIGNALED(s) ? strsignal(WTERMSIG(s)) : "(unknown)"); + else + failed = !!WEXITSTATUS(s); + } + + if (failed) { + nfailed++; + fprintf(stderr, "FAILED %s\n", name); + } else if (verbose) + fprintf(stderr, "PASSED %s\n", name); +} + +static int summary() { + fprintf(stderr, "PASS:%d FAIL:%d\n", count-nfailed, nfailed); + return !!nfailed; +} + +int main() { +#define T(t) run(#t, t); +#include "main.h" + return summary(); +}