commit 95cec6a5ecfdc2a75ba041a6e9f9cd568d53a6fc
Author:     Mattias Andrée <[email protected]>
AuthorDate: Wed Apr 27 21:39:19 2016 +0200
Commit:     Mattias Andrée <[email protected]>
CommitDate: Wed Apr 27 21:39:19 2016 +0200

    More accurate benchmarking
    
    Signed-off-by: Mattias Andrée <[email protected]>

diff --git a/Makefile b/Makefile
index 0c693d3..a7c2b0a 100644
--- a/Makefile
+++ b/Makefile
@@ -130,15 +130,15 @@ test-random.c: test-generate.py
 test: test.c libzahl.a test-random.c
        $(CC) $(LDFLAGS) $(CFLAGS_WITHOUT_O) -O0 $(CPPFLAGS) -o $@ test.c 
libzahl.a
 
-benchmark: bench/benchmark.c $(BENCHMARK_DEP_$(BENCHMARK_LIB))
+benchmark: bench/benchmark.c bench/benchmark.h 
$(BENCHMARK_DEP_$(BENCHMARK_LIB))
        $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ bench/benchmark.c \
                $(BENCHMARK_LIB_$(BENCHMARK_LIB)) 
$(BENCHMARK_C_$(BENCHMARK_LIB))
 
-benchmark-func: bench/benchmark-func.c $(BENCHMARK_DEP_$(BENCHMARK_LIB))
+benchmark-func: bench/benchmark-func.c bench/benchmark.h 
$(BENCHMARK_DEP_$(BENCHMARK_LIB))
        $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ bench/benchmark-func.c \
                $(BENCHMARK_LIB_$(BENCHMARK_LIB)) 
$(BENCHMARK_C_$(BENCHMARK_LIB))
 
-benchmark-zrand: bench/benchmark-zrand.c libzahl.a
+benchmark-zrand: bench/benchmark-zrand.c bench/benchmark.h libzahl.a
        $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $@ $^
 
 check: test
diff --git a/bench/benchmark-func.c b/bench/benchmark-func.c
index 82368a7..fe7e160 100644
--- a/bench/benchmark-func.c
+++ b/bench/benchmark-func.c
@@ -1,16 +1,7 @@
+#include "benchmark.h"
+
 #include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <unistd.h>
 
-#ifdef BENCHMARK_LIB
-# include BENCHMARK_LIB
-#else
-# include "../zahl.h"
-# define BIGINT_LIBRARY "libzahl"
-#endif
 
 enum {
        HIGH_ONLY,
@@ -34,24 +25,10 @@ struct function {
        size_t measurements;
 };
 
-#if defined(__x86_64__)
-# undef clock_t
-# define clock_t unsigned long long int
-static inline clock_t rdtsc(void)
-{
-  unsigned int low, high;
-  __asm__ __volatile__ ("rdtsc" : "=a"(low), "=d"(high));
-  return (clock_t)low | (((clock_t)high) << 32);
-}
-#else
-# define rdtsc clock
-#endif
-
 #define M_MAX 200
 
 static char buf[1000];
 static z_t temp, temp2;
-static clock_t start, end;
 static unsigned long long int measurements[M_MAX];
 
 #if 1
@@ -124,12 +101,12 @@ gettime(size_t m)
                                INSTRUCTION;\
                                INSTRUCTION;\
                                j = f->runs;\
-                               start = rdtsc();\
+                               TIC;\
                                while (j--) {\
                                        INSTRUCTION;\
                                }\
-                               end = rdtsc();\
-                               measurements[k] = (unsigned long long int)(end 
- start);\
+                               TOC;\
+                               measurements[k] = TICKS;\
                        }\
                        printf("%llu\n", gettime(f->measurements));\
                        a++;\
@@ -301,6 +278,8 @@ main(int argc, char *argv[])
                return 2;
        }
 
+       benchmark_init();
+
        if (setjmp(jmp)) {
                zperror(argv[0]);
                return 1;
diff --git a/bench/benchmark-zrand.c b/bench/benchmark-zrand.c
index 714ba78..2672f0e 100644
--- a/bench/benchmark-zrand.c
+++ b/bench/benchmark-zrand.c
@@ -1,43 +1,28 @@
-#include <time.h>
-#include <stdio.h>
-
-#include "../zahl.h"
-
-
-#ifndef CLOCK_MONOTONIC_RAW
-# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
-#endif
+#include "benchmark.h"
 
 
 #define BENCHMARK(INSTRUCTION, FAST)\
        do {\
                i = FAST ? 1000000L : 1000L;\
-               clock_gettime(CLOCK_MONOTONIC_RAW, &start);\
+               TIC;\
                while (i--) {\
                        INSTRUCTION;\
                }\
-               clock_gettime(CLOCK_MONOTONIC_RAW, &end);\
-               end.tv_sec -= start.tv_sec;\
-               end.tv_nsec -= start.tv_nsec;\
-               if (end.tv_nsec < 0) {\
-                       end.tv_nsec += 1000000000L;\
-                       end.tv_sec -= 1;\
-               }\
-               printf("%s: %lli.%09li %s\n",\
-                      #INSTRUCTION,\
-                      (long long int)(end.tv_sec), end.tv_nsec,\
-                      FAST ? "µs" : "ms");\
+               TOC;\
+               printf("%s: %s %s\n",\
+                      #INSTRUCTION, STIME, FAST ? "µs" : "ms");\
        } while (0)
 
 
 int
 main(int argc, char *argv[])
 {
-       struct timespec start, end;
        z_t r, n;
        jmp_buf jmp;
        size_t i;
 
+       benchmark_init();
+
        if (setjmp(jmp)) {
                zperror(argv[0]);
                return 1;
diff --git a/bench/benchmark.c b/bench/benchmark.c
index 87e15ca..485e2c4 100644
--- a/bench/benchmark.c
+++ b/bench/benchmark.c
@@ -1,49 +1,29 @@
-#include <time.h>
-#include <stdio.h>
-
-#ifdef BENCHMARK_LIB
-# include BENCHMARK_LIB
-#else
-# include "../zahl.h"
-# define BIGINT_LIBRARY "libzahl"
-#endif
-
-
-#ifndef CLOCK_MONOTONIC_RAW
-# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
-#endif
+#include "benchmark.h"
 
 
 #define BENCHMARK(INSTRUCTION, FAST)\
        do {\
                i = FAST ? 1000000L : 1000L;\
-               clock_gettime(CLOCK_MONOTONIC_RAW, &start);\
+               TIC;\
                while (i--) {\
                        (void)INSTRUCTION;\
                }\
-               clock_gettime(CLOCK_MONOTONIC_RAW, &end);\
-               end.tv_sec -= start.tv_sec;\
-               end.tv_nsec -= start.tv_nsec;\
-               if (end.tv_nsec < 0) {\
-                       end.tv_nsec += 1000000000L;\
-                       end.tv_sec -= 1;\
-               }\
-               printf("%s: %lli.%09li %s (152 bits)\n",\
-                      #INSTRUCTION,\
-                      (long long int)(end.tv_sec), end.tv_nsec,\
-                      FAST ? "µs" : "ms");\
+               TOC;\
+               printf("%s: %s %s (152 bits)\n",\
+                      #INSTRUCTION, STIME, FAST ? "µs" : "ms");\
        } while (0)
 
 
 int
 main(int argc, char *argv[])
 {
-       struct timespec start, end;
        char buf[1000];
        z_t a, b, c, d, tiny;
        jmp_buf jmp;
        size_t i;
 
+       benchmark_init();
+
        if (setjmp(jmp)) {
                zperror(argv[0]);
                return 1;
diff --git a/bench/benchmark.h b/bench/benchmark.h
new file mode 100644
index 0000000..6d6aa87
--- /dev/null
+++ b/bench/benchmark.h
@@ -0,0 +1,134 @@
+#if defined(__linux__)
+# define _GNU_SOURCE
+# include <sched.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <unistd.h>
+
+
+#ifdef BENCHMARK_LIB
+# include BENCHMARK_LIB
+#else
+# include "../zahl.h"
+# define BIGINT_LIBRARY "libzahl"
+#endif
+
+
+#ifndef CLOCK_MONOTONIC_RAW
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+
+
+#ifdef __x86_64__
+# define RDTSC_MAYBE_SUPPORTED
+#endif
+
+
+#if !defined(USE_RDTSC) && !defined(USE_CLOCK) && !defined(USE_GETTIME)
+# if 1 && defined(RDTSC_MAYBE_SUPPORTED) && defined(__linux__)
+#  define USE_RDTSC
+# elif 1
+#  define USE_CLOCK
+# else
+#  define USE_GETTIME
+# endif
+#endif
+
+
+static struct timespec dur;
+static char timebuf[512];
+#if defined(USE_RDTSC)
+typedef unsigned long long int rdtsc_t;
+static unsigned int start_high, start_low, end_high, end_low;
+static unsigned long long int freq;
+#elif defined(USE_CLOCK)
+static clock_t start, end;
+#else
+static struct timespec start;
+#endif
+
+
+static void
+benchmark_init(void)
+{
+#if defined(__linux__)
+       cpu_set_t cpuset;
+# if defined(USE_RDTSC)
+       FILE *f;
+       char *line = 0;
+       size_t size = 0;
+# endif
+       CPU_ZERO(&cpuset);
+       CPU_SET(0, &cpuset);
+       sched_setaffinity(getpid(), sizeof(cpuset), &cpuset);
+# if defined(USE_RDTSC)
+       f = fopen("/sys/devices/system/cpu/cpu0/cpufreq/cpuinfo_max_freq", "r");
+       if (getline(&line, &size, f) < 0)
+               abort();
+       fclose(f);
+       freq = strtoull(line, 0, 10);
+       free(line);
+# endif
+#endif
+       (void) timebuf;
+}
+
+
+#if defined(USE_RDTSC) && defined(__x86_64__)
+static inline void
+rdtsc(unsigned int *low, unsigned int *high)
+{
+       __asm__ __volatile__ ("rdtsc" : "=a"(*low), "=d"(*high));
+}
+static inline rdtsc_t
+rdtsc_join(unsigned int low, unsigned int high)
+{
+       return (rdtsc_t)low | (((rdtsc_t)high) << 32);
+}
+#endif
+
+
+#if defined(USE_RDTSC)
+# define TIC  (rdtsc(&start_low, &start_high))
+# define TOC\
+       do {\
+               rdtsc_t dur_cycles;\
+               double dur_seconds;\
+               rdtsc(&end_low, &end_high);\
+               dur_cycles = rdtsc_join(end_low, end_high);\
+               dur_cycles -= rdtsc_join(start_low, start_high);\
+               dur_seconds = dur_cycles;\
+               dur_seconds /= freq;\
+               dur_seconds /= 1000;\
+               dur_seconds -= dur.tv_sec = (int)dur_seconds;\
+               dur.tv_nsec = dur_seconds * 1000000000L;\
+       } while (0)
+#elif defined(USE_CLOCK)
+# define TIC  (start = clock())
+# define TOC\
+       do {\
+               end = clock();\
+               dur.tv_sec = (end - start) / 1000000ULL;\
+               dur.tv_nsec = ((end - start) % 1000000ULL) * 1000;\
+       } while (0)
+#elif defined(USE_GETTIME)
+# define TIC  clock_gettime(CLOCK_MONOTONIC_RAW, &start)
+# define TOC\
+       do {\
+               clock_gettime(CLOCK_MONOTONIC_RAW, &dur);\
+               dur.tv_sec -= start.tv_sec;\
+               dur.tv_nsec -= start.tv_nsec;\
+               if (dur.tv_nsec < 0) {\
+                       dur.tv_nsec += 1000000000L;\
+                       dur.tv_sec -= 1;\
+               }\
+       } while (0)
+#endif
+
+
+#define TICKS  (dur.tv_sec * 1000000000ULL + dur.tv_nsec)
+#define STIME  (sprintf(timebuf, "%lli.%09li", (long long)(dur.tv_sec), 
dur.tv_nsec), timebuf)

Reply via email to