commit d0788650ecb3f38f4e20f9a71f449980258d3112
Author: Mattias Andrée <maandree_AT_kth.se>
AuthorDate: Sun Apr 24 00:41:07 2016 +0200
Commit: Mattias Andrée <maandree_AT_kth.se>
CommitDate: Sun Apr 24 00:41:07 2016 +0200
bench/benchmark-func.c
Signed-off-by: Mattias Andrée <maandree_AT_kth.se>
diff --git a/.gitignore b/.gitignore
index 618db63..5a7aa5d 100644
--- a/.gitignore
+++ b/.gitignore
_AT_@ -13,3 +13,4 @@
/test-random.c
/benchmark
/benchmark-zrand
+/benchmark-func
diff --git a/Makefile b/Makefile
index 2636834..9bbd442 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -130,6 +130,9 @@ test: test.c libzahl.a test-random.c
benchmark: bench/benchmark.c $(BENCHMARK_DEP_$(BENCHMARK_LIB))
$(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $_AT_ bench/benchmark.c $(BENCHMARK_LIB_$(BENCHMARK_LIB))
+benchmark-func: bench/benchmark-func.c $(BENCHMARK_DEP_$(BENCHMARK_LIB))
+ $(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $_AT_ bench/benchmark-func.c $(BENCHMARK_LIB_$(BENCHMARK_LIB))
+
benchmark-zrand: bench/benchmark-zrand.c libzahl.a
$(CC) $(LDFLAGS) $(CFLAGS) $(CPPFLAGS) -o $_AT_ $^
_AT_@ -158,5 +161,6 @@ uninstall:
clean:
-rm -- *.o *.su *.a *.so test test-random.c 2>/dev/null
+ -rm -- benchmark benchmark-zrand benchmark-func 2>/dev/null
.PHONY: all check clean install uninstall
diff --git a/bench/benchmark-func.c b/bench/benchmark-func.c
new file mode 100644
index 0000000..c0bc2d8
--- /dev/null
+++ b/bench/benchmark-func.c
_AT_@ -0,0 +1,338 @@
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef BENCHMARK_LIB
+# include BENCHMARK_LIB
+#else
+# include "../zahl.h"
+# define BIGINT_LIBRARY "libzahl"
+#endif
+
+enum {
+ HIGH_ONLY,
+ HIGH_AND_LOW,
+ HALF,
+ FULL
+};
+
+struct function {
+ const char *name;
+ void (*f)(z_t *, z_t *, struct function *);
+ size_t a_start;
+ size_t a_end;
+ size_t a_step;
+ int a_mode;
+ size_t b_start;
+ size_t b_end;
+ size_t b_step;
+ int b_mode;
+ size_t runs;
+ 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
+static int
+measurementpcmp(const void *ap_, const void *bp_)
+{
+ const unsigned long long int *ap = ap_, *bp = bp_;
+ return *ap < *bp ? -1 : *ap > *bp;
+}
+# if 0
+static unsigned long long int
+gettime(size_t m)
+{
+ qsort(measurements, m, sizeof(*measurements), measurementpcmp);
+ if (m & 1)
+ return measurements[m / 2];
+ return (measurements[m / 2] + measurements[m / 2 - 1]) / 2;
+}
+# else
+static unsigned long long int
+gettime(size_t m)
+{
+# define X 2 / 7
+ size_t i = m * X, n = m - m * X;
+ unsigned long long int tot = 0;
+ qsort(measurements, m, sizeof(*measurements), measurementpcmp);
+ for (; i < n; i++)
+ tot += measurements[i];
+ return tot / (n - m * X);
+# undef X
+}
+# endif
+#elif 0
+static unsigned long long int
+gettime(size_t m)
+{
+ unsigned long long int tot = 0;
+ size_t i = m;
+ while (i--)
+ tot += measurements[i];
+ return tot / m;
+}
+#else
+static unsigned long long int
+gettime(size_t m)
+{
+ unsigned long long int best = ULLONG_MAX;
+ size_t i = m;
+ while (i--)
+ if (best > measurements[i])
+ best = measurements[i];
+ return best;
+}
+#endif
+
+#define FUNCTION_2D(NAME, INSTRUCTION, PREINSTRUCTION)\
+ void\
+ NAME(z_t *as, z_t* bs, struct function *f)\
+ {\
+ size_t i, j, k, n = f->a_end - f->a_start + 1;\
+ z_t *a;\
+ zmul(temp, as[n - 1], as[n - 1]);\
+ zadd(temp, temp, temp);\
+ for (i = 0; i < n; i += f->a_step) {\
+ a = as + i;\
+ zset(temp2, *a);\
+ PREINSTRUCTION;\
+ k = f->measurements;\
+ while (k--) {\
+ for (j = f->runs / 10; j--;) {\
+ INSTRUCTION;\
+ }\
+ j = f->runs;\
+ start = rdtsc();\
+ while (j--) {\
+ INSTRUCTION;\
+ }\
+ end = rdtsc();\
+ measurements[k] = (unsigned long long int)(end - start);\
+ }\
+ printf("%llu\n", gettime(f->measurements));\
+ a++;\
+ }\
+ (void) bs;\
+ }
+
+FUNCTION_2D(bench_zset, zset(temp, *a),)
+FUNCTION_2D(bench_zneg, zneg(temp, *a),)
+FUNCTION_2D(bench_zabs, zabs(temp, *a),)
+FUNCTION_2D(bench_self_zneg, zneg(*a, *a),)
+FUNCTION_2D(bench_self_zabs, zabs(*a, *a),)
+FUNCTION_2D(bench_zadd_unsigned, zadd_unsigned(temp, *a, temp2),)
+FUNCTION_2D(bench_zsub_unsigned, zsub_unsigned(temp, *a, temp2),)
+FUNCTION_2D(bench_zadd, zadd(temp, *a, temp2),)
+FUNCTION_2D(bench_zsub, zsub(temp, *a, temp2),)
+FUNCTION_2D(bench_zand, zand(temp, *a, temp2),)
+FUNCTION_2D(bench_zor, zor(temp, *a, temp2),)
+FUNCTION_2D(bench_zxor, zxor(temp, *a, temp2),)
+FUNCTION_2D(bench_znot, znot(temp, *a),)
+FUNCTION_2D(bench_zeven, zeven(*a),)
+FUNCTION_2D(bench_zodd, zodd(*a),)
+FUNCTION_2D(bench_zeven_nonzero, zeven_nonzero(*a),)
+FUNCTION_2D(bench_zodd_nonzero, zodd_nonzero(*a),)
+FUNCTION_2D(bench_zzero, zzero(*a),)
+FUNCTION_2D(bench_zsignum, zsignum(*a),)
+FUNCTION_2D(bench_zbits, zbits(*a),)
+FUNCTION_2D(bench_zlsb, zlsb(*a),)
+FUNCTION_2D(bench_zswap, zswap(temp, *a),)
+FUNCTION_2D(bench_zcmpmag, zcmpmag(temp2, *a),)
+FUNCTION_2D(bench_zcmp, zcmp(temp2, *a),)
+FUNCTION_2D(bench_sqr_zmul, zmul(temp, *a, temp2),)
+FUNCTION_2D(bench_zsqr, zsqr(temp, *a),)
+FUNCTION_2D(bench_zstr_length, zstr_length(*a, 10),)
+FUNCTION_2D(bench_zstr, zstr(*a, buf),)
+FUNCTION_2D(bench_zsave, zsave(*a, buf),)
+FUNCTION_2D(bench_zload, zload(temp, buf), zsave(*a, buf))
+
+/* TODO
+ zlsh
+ zrsh
+ ztrunc
+ self_ztrunc
+ zsplit
+ zbset_set
+ zbset_clear
+ zbset_flip
+ self_zbset_set
+ self_zbset_clear
+ self_zbset_flip
+ zbtest
+ zgcd
+ zsets
+ zpow
+ zpowu
+ zmodpow
+ zmodpowu
+ zrand
+ zptest
+ zdiv
+ zmod
+ zdivmod
+ zmul
+ zmodmul
+ sqr_zmodmul
+ zmodsqr
+ zdiv
+ zmod
+ zdivmod
+*/
+
+#define F(f) #f, bench_##f
+struct function functions[] = {
+ {F(zset), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zneg), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zabs), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(self_zneg), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(self_zabs), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zadd_unsigned), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zsub_unsigned), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zadd), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zsub), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zand), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zor), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zxor), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(znot), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zeven), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zodd), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zeven_nonzero), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zodd_nonzero), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zzero), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zsignum), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zbits), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zlsb), 1, 4097, 64, HIGH_ONLY, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zswap), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zcmpmag), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zcmp), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(sqr_zmul), 1, 4097, 64, FULL, 0, 0, 0, 0, 10, 20},
+ {F(zsqr), 1, 4097, 64, FULL, 0, 0, 0, 0, 10, 20},
+ {F(zstr_length), 1, 4097, 64, FULL, 0, 0, 0, 0, 10, 20},
+ {F(zstr), 1, 4097, 64, FULL, 0, 0, 0, 0, 10, 20},
+ {F(zsave), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+ {F(zload), 1, 4097, 64, FULL, 0, 0, 0, 0, 1000, M_MAX},
+
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
+#undef F
+
+static z_t *
+create_ints(size_t start, size_t end, int mode)
+{
+ z_t *array = malloc((end - start + 1) * sizeof(z_t));
+ z_t *rc = array;
+ ssize_t n;
+ for (; start <= end; start++, array++) {
+ zinit(*array);
+ switch (mode) {
+ case HIGH_ONLY:
+ zsetu(temp, 1);
+ zlsh(*array, temp, start - 1);
+ break;
+ case HIGH_AND_LOW:
+ zsetu(temp, 1);
+ zlsh(*array, temp, start - 1);
+ if (start > 1)
+ zadd(*array, *array, temp);
+ break;
+ case HALF:
+ n = (ssize_t)start;
+ zsetu(temp, 1 << (~start & 1));
+ zsetu(*array, 0);
+ for (; n > 0; n -= 2) {
+ zlsh(*array, *array, 2);
+ zadd(*array, *array, temp);
+ }
+ break;
+ case FULL:
+ zsetu(temp, 1);
+ zlsh(*array, temp, start);
+ zsub(*array, *array, temp);
+ break;
+ default:
+ abort();
+ }
+ }
+ return rc;
+}
+
+static void
+destroy_ints(z_t *array, size_t start, size_t end)
+{
+ z_t *array_ = array;
+ for (; start <= end; start++)
+ zfree(*array++);
+ free(array_);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct function *fs = functions;
+ jmp_buf jmp;
+ z_t *as = 0, *bs = 0;
+
+ if (argc != 2) {
+ fprintf(stderr, "usage: %s function\n", *argv);
+ return 2;
+ }
+
+ if (setjmp(jmp)) {
+ zperror(argv[0]);
+ return 1;
+ }
+ zsetup(jmp);
+ printf("%s\n", BIGINT_LIBRARY);
+ zinit(temp);
+ zinit(temp2);
+
+ for (; fs->name && strcmp(fs->name, argv[1]); fs++);
+ if (!fs->name) {
+ fprintf(stderr, "%s: function not recognised: %s\n", *argv, argv[1]);
+ return 2;
+ }
+
+ if (fs->b_end) {
+ as = create_ints(fs->a_start, fs->a_end, fs->a_mode);
+ bs = create_ints(fs->b_start, fs->b_end, fs->b_mode);
+ printf("3\n%zu %zu %zu\n%zu %zu %zu\n",
+ fs->a_start, fs->a_end, fs->a_step,
+ fs->b_start, fs->b_end, fs->b_step);
+ } else {
+ as = create_ints(fs->a_start, fs->a_end, fs->a_mode);
+ printf("2\n%zu %zu %zu\n", fs->a_start, fs->a_end, fs->a_step);
+ }
+ fs->f(as, bs, fs);
+
+ if (as)
+ destroy_ints(as, fs->a_start, fs->a_end);
+ if (bs)
+ destroy_ints(bs, fs->b_start, fs->b_end);
+
+ zfree(temp);
+ zfree(temp2);
+ zunsetup();
+ return 0;
+}
diff --git a/bench/benchmark-zrand.c b/bench/benchmark-zrand.c
index a7e9fb4..714ba78 100644
--- a/bench/benchmark-zrand.c
+++ b/bench/benchmark-zrand.c
_AT_@ -5,7 +5,7 @@
#ifndef CLOCK_MONOTONIC_RAW
-# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
#endif
diff --git a/bench/benchmark.c b/bench/benchmark.c
index 6649958..27efee1 100644
--- a/bench/benchmark.c
+++ b/bench/benchmark.c
_AT_@ -5,11 +5,12 @@
# include BENCHMARK_LIB
#else
# include "../zahl.h"
+# define BIGINT_LIBRARY "libzahl"
#endif
#ifndef CLOCK_MONOTONIC_RAW
-# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
#endif
diff --git a/bench/libgmp.h b/bench/libgmp.h
index 1ea6dcb..95a518d 100644
--- a/bench/libgmp.h
+++ b/bench/libgmp.h
_AT_@ -6,6 +6,8 @@
#include <stdio.h>
#include <stdlib.h>
+#define BIGINT_LIBRARY "GMP"
+
typedef mpz_t z_t;
static z_t _0, _1, _a, _b;
diff --git a/bench/libhebimath.h b/bench/libhebimath.h
index c16d8f4..e2ef936 100644
--- a/bench/libhebimath.h
+++ b/bench/libhebimath.h
_AT_@ -6,6 +6,8 @@
#include <stdio.h>
#include <stdlib.h>
+#define BIGINT_LIBRARY "hebimath"
+
typedef hebi_int z_t[1];
static z_t _0, _1, _a, _b, _m;
diff --git a/bench/libtfm.h b/bench/libtfm.h
index 3c9f85f..00e175f 100644
--- a/bench/libtfm.h
+++ b/bench/libtfm.h
_AT_@ -5,6 +5,8 @@
#include <stdint.h>
#include <stdio.h>
+#define BIGINT_LIBRARY "TomsFastMath"
+
typedef fp_int z_t[1];
static z_t _0, _1, _a, _b;
diff --git a/bench/libtommath.h b/bench/libtommath.h
index 25da3ff..1867bdb 100644
--- a/bench/libtommath.h
+++ b/bench/libtommath.h
_AT_@ -5,6 +5,8 @@
#include <stdint.h>
#include <stdio.h>
+#define BIGINT_LIBRARY "libtommath"
+
typedef mp_int z_t[1];
static z_t _0, _1, _a, _b;
diff --git a/bench/plot.py b/bench/plot.py
new file mode 100755
index 0000000..3a59490
--- /dev/null
+++ b/bench/plot.py
_AT_@ -0,0 +1,51 @@
+#!/usr/bin/env python3
+
+import sys, os
+import matplotlib.pyplot as plot
+
+xkcdstyle = 'XKCD_STYLE' in os.environ
+if xkcdstyle:
+ plot.xkcd()
+plot.figure()
+
+multiple = 1
+smultiple = ''
+
+for path in sys.argv[1:]:
+ if path.startswith('*'):
+ multiple = float(path[1:])
+ smultiple = ' * ' + path[1:]
+ continue
+ with open(path, 'rb') as file:
+ lines = file.read()
+ lines = lines.decode('utf-8', 'strict').split('\n')
+ label, dim, xpoints, values = lines[0], int(lines[1]), lines[2], lines[3:]
+ label += smultiple
+ xpoints = [int(x) for x in xpoints.split(' ')]
+ xpoints[1] += 1
+ xpoints = list(range(*xpoints))
+ if dim == 3:
+ ypoints, values = values[0], values[1:]
+ ypoints = [int(x) for x in ypoints.split(' ')]
+ ypoints[1] += 1
+ ypoints = list(range(*ypoints))
+ values = [float(v) * multiple for v in values if v != '']
+ if dim == 2:
+ if 'PER_BIT' in os.environ:
+ values = [y / x for y, x in zip(values, xpoints)]
+ plot.plot(xpoints, values, label = label)
+ elif dim == 3:
+ pass
+ multiple = 1
+ smultiple = ''
+
+if dim == 2:
+ plot.legend(loc = 'best')
+ plot.xlabel('bits')
+ plot.ylabel('time')
+elif dim == 3:
+ pass
+
+if not xkcdstyle:
+ plot.grid(True)
+plot.show()
Received on Sun Apr 24 2016 - 00:41:31 CEST
This archive was generated by hypermail 2.3.0
: Sun Apr 24 2016 - 00:48:15 CEST