libzahl

big integer library
git clone git://git.suckless.org/libzahl
Log | Files | Refs | README | LICENSE

commit 95cec6a5ecfdc2a75ba041a6e9f9cd568d53a6fc
parent 37740e679273dbf76593a8da5d44772b94f07b28
Author: Mattias Andrée <maandree@kth.se>
Date:   Wed, 27 Apr 2016 21:39:19 +0200

More accurate benchmarking

Signed-off-by: Mattias Andrée <maandree@kth.se>

Diffstat:
MMakefile | 6+++---
Mbench/benchmark-func.c | 35+++++++----------------------------
Mbench/benchmark-zrand.c | 29+++++++----------------------
Mbench/benchmark.c | 34+++++++---------------------------
Abench/benchmark.h | 134+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 158 insertions(+), 80 deletions(-)

diff --git 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 @@ -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 @@ -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 @@ -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 @@ -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)