summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgastineau <gastineau@211d60ee-9f03-0410-a15a-8952a2c7a4e4>2014-01-22 10:48:33 +0000
committergastineau <gastineau@211d60ee-9f03-0410-a15a-8952a2c7a4e4>2014-01-22 10:48:33 +0000
commite4251c01b782221d11b33688c54e3d5b75d672dd (patch)
tree2ec64635636cc12193a0d855eb0fc37fc9aa55e2
parenta3e3e143d1b0afce1b712bb7c96f022222925a78 (diff)
downloadmpc-e4251c01b782221d11b33688c54e3d5b75d672dd.tar.gz
add the benchmark
git-svn-id: svn://scm.gforge.inria.fr/svn/mpc/trunk@1426 211d60ee-9f03-0410-a15a-8952a2c7a4e4
-rw-r--r--Makefile.am4
-rw-r--r--configure.ac6
-rw-r--r--tools/Makefile.am21
-rw-r--r--tools/bench/Makefile.am29
-rw-r--r--tools/bench/benchtime.h66
-rw-r--r--tools/bench/mpcbench.c321
6 files changed, 442 insertions, 5 deletions
diff --git a/Makefile.am b/Makefile.am
index 940bd64..b72cca7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,6 +1,6 @@
## Makefile.am -- Process this file with automake to produce Makefile.in
##
-## Copyright (C) 2008, 2010, 2011 INRIA
+## Copyright (C) 2008, 2010, 2011, 2012, 2013, 2014 INRIA
##
## This file is part of GNU MPC.
##
@@ -22,7 +22,7 @@ ACLOCAL_AMFLAGS = -I m4
# version number for distribution tarball
VERSION = @VERSION@@SVNVERSION@
-SUBDIRS = src tests doc
+SUBDIRS = src tests doc tools
EXTRA_HEADERS = src/mpc-log.h
include_HEADERS = src/mpc.h @MPC_LOG_H@
diff --git a/configure.ac b/configure.ac
index 39f8891..207d394 100644
--- a/configure.ac
+++ b/configure.ac
@@ -135,7 +135,7 @@ fi
# Checks for header files.
AC_HEADER_STDC
-AC_CHECK_HEADERS([locale.h inttypes.h stdint.h limits.h unistd.h sys/time.h])
+AC_CHECK_HEADERS([locale.h inttypes.h stdint.h limits.h unistd.h sys/time.h sys/resource.h])
AC_HEADER_TIME
MPC_COMPLEX_H
@@ -144,7 +144,7 @@ AC_C_CONST
AC_TYPE_SIZE_T
# Checks for libraries.
-AC_CHECK_FUNCS([gettimeofday localeconv setlocale])
+AC_CHECK_FUNCS([gettimeofday localeconv setlocale getrusage])
AC_CHECK_FUNCS([dup dup2],,
[AC_DEFINE([MPC_NO_STREAM_REDIRECTION],1,[Do not check mpc_out_str on stdout])])
@@ -237,5 +237,5 @@ AC_DEFINE_UNQUOTED([MPC_GCC_VERSION], ["$GCC_VERSION"], [Version of gcc])
# Looks for svn version if the version string contains "dev"
MPC_SVNVERSION
-AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile doc/Makefile])
+AC_CONFIG_FILES([Makefile src/Makefile tests/Makefile doc/Makefile tools/Makefile tools/bench/Makefile])
AC_OUTPUT
diff --git a/tools/Makefile.am b/tools/Makefile.am
new file mode 100644
index 0000000..b91ddf6
--- /dev/null
+++ b/tools/Makefile.am
@@ -0,0 +1,21 @@
+## tools/Makefile.am -- Process this file with automake to produce Makefile.in
+##
+## Copyright (C) 2014 INRIA
+##
+## This file is part of GNU MPC.
+##
+## GNU MPC is free software; you can redistribute it and/or modify it under
+## the terms of the GNU Lesser General Public License as published by the
+## Free Software Foundation; either version 3 of the License, or (at your
+## option) any later version.
+##
+## GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+## more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program. If not, see http://www.gnu.org/licenses/ .
+
+SUBDIRS = bench
+
diff --git a/tools/bench/Makefile.am b/tools/bench/Makefile.am
new file mode 100644
index 0000000..7a554ec
--- /dev/null
+++ b/tools/bench/Makefile.am
@@ -0,0 +1,29 @@
+## tools/bench/Makefile.am -- Process this file with automake to produce Makefile.in
+##
+## Copyright (C) 2014 INRIA
+##
+## This file is part of GNU MPC.
+##
+## GNU MPC is free software; you can redistribute it and/or modify it under
+## the terms of the GNU Lesser General Public License as published by the
+## Free Software Foundation; either version 3 of the License, or (at your
+## option) any later version.
+##
+## GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
+## WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+## FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+## more details.
+##
+## You should have received a copy of the GNU Lesser General Public License
+## along with this program. If not, see http://www.gnu.org/licenses/ .
+
+AM_CPPFLAGS = -I$(top_srcdir)/src
+AM_DEFAULT_SOURCE_EXT = .c
+
+LDADD = $(top_builddir)/src/libmpc.la
+
+noinst_PROGRAMS = mpcbench
+
+
+noinst_HEADERS = benchtime.h
+
diff --git a/tools/bench/benchtime.h b/tools/bench/benchtime.h
new file mode 100644
index 0000000..42a9dae
--- /dev/null
+++ b/tools/bench/benchtime.h
@@ -0,0 +1,66 @@
+/* benchtime.h -- compute the timings for the benchmark.
+
+Copyright (C) 2014, INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+
+/* compute the time to run accurately niter calls of the function for any number of inputs */
+#define DECLARE_ACCURATE_TIME_NOP(func, funccall) \
+unsigned long int ACCURATE_TIME_NOP##func( unsigned long int niter, int n, mpc_t* z, mpc_t* x, mpc_t* y, int nop);\
+unsigned long int ACCURATE_TIME_NOP##func( unsigned long int niter, int n, mpc_t* z, mpc_t* x, mpc_t* y, int nop)\
+{ \
+ unsigned long int ti, i; int kn; \
+ unsigned long int t0 = get_cputime (); \
+ for (i = niter, kn=0; i > 0; i--) \
+ { \
+ funccall; \
+ kn++; if (kn==n) kn = 0; \
+ } \
+ ti = get_cputime () - t0; \
+ /* following lines are append to avoid warnings but minimize the number of macros*/\
+ if (nop==2) y = NULL; \
+ return ti; \
+}
+
+/* address of the function to time accurately niter calls of func */
+#define ADDR_ACCURATE_TIME_NOP(func) ACCURATE_TIME_NOP##func
+
+/* address of the function to time one call of func */
+#define ADDR_TIME_NOP(func) TIME_NOP##func
+
+
+/* compute the time to run one only call of the function with two inputs */
+#define DECLARE_TIME_NOP(func, funcall, nop) \
+ DECLARE_ACCURATE_TIME_NOP(func, funcall) \
+ double TIME_NOP##func(int n, mpc_t* z, mpc_t* x, mpc_t* y); \
+ double TIME_NOP##func(int n, mpc_t* z, mpc_t* x, mpc_t* y) \
+ { \
+ double t; unsigned long int nbcall, mytime; \
+ for (nbcall = 1, mytime=0; mytime<250000; nbcall<<=1) \
+ { \
+ mytime = ACCURATE_TIME_NOP##func(nbcall, n, z, x, y, nop); \
+ } \
+ t = (double) mytime/ nbcall ; \
+ return t; \
+ }
+
+/* compute the time to run accurately niter calls of the function */
+/* functions with 2 operands */
+#define DECLARE_TIME_2OP(func) DECLARE_TIME_NOP(func, func(z[kn],x[kn],y[kn], MPC_RNDNN), 2 )
+/* functions with 1 operand */
+#define DECLARE_TIME_1OP(func) DECLARE_TIME_NOP(func, func(z[kn],x[kn], MPC_RNDNN), 1 )
diff --git a/tools/bench/mpcbench.c b/tools/bench/mpcbench.c
new file mode 100644
index 0000000..f00a182
--- /dev/null
+++ b/tools/bench/mpcbench.c
@@ -0,0 +1,321 @@
+/* mpcbench.c -- perform the benchmark on the complex numbers.
+
+Copyright (C) 2014, INRIA
+
+This file is part of GNU MPC.
+
+GNU MPC is free software; you can redistribute it and/or modify it under
+the terms of the GNU Lesser General Public License as published by the
+Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
+more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with this program. If not, see http://www.gnu.org/licenses/ .
+*/
+
+#include "config.h"
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#endif
+#ifdef HAVE_SYS_RESOURCE_H
+#include <sys/resource.h>
+#endif
+#include "mpc.h"
+#include "benchtime.h"
+
+static unsigned long get_cputime (void);
+
+/* enumeration of the group of functions */
+enum egroupfunc
+{
+ egroup_arith = 0, /* e.g., arith ... */
+ egroup_special, /* e.g., cos, ... */
+ egroup_last /* to get the number of enum */
+};
+
+/* name of the group of functions */
+const char *groupname [] = {
+"Arith ",
+"Special"
+};
+
+
+
+struct benchfunc
+{
+ const char *name; /* name of the function */
+ double (*func_init) (int n, mpc_t * z, mpc_t * x, mpc_t * y); /* compute the time for one call (not accurate) */
+ unsigned long int (*func_accurate) (unsigned long int niter, int n, mpc_t * z, mpc_t * x, mpc_t * y, int nop); /* compute the time for "niter" calls (accurate) */
+ enum egroupfunc group; /* group of the function */
+ int noperands; /* number of operands */
+};
+
+
+/* declare the function to compute the cost for one call of the mpc function */
+DECLARE_TIME_2OP (mpc_mul)
+DECLARE_TIME_2OP (mpc_add)
+DECLARE_TIME_2OP (mpc_sub)
+DECLARE_TIME_2OP (mpc_div)
+DECLARE_TIME_1OP (mpc_sqrt)
+DECLARE_TIME_1OP (mpc_exp)
+DECLARE_TIME_1OP (mpc_log)
+DECLARE_TIME_1OP (mpc_sin)
+DECLARE_TIME_1OP (mpc_cos)
+DECLARE_TIME_1OP (mpc_asin)
+DECLARE_TIME_1OP (mpc_acos)
+
+/* number of operations to score*/
+#define NB_BENCH_OP 11
+/* number of random numbers */
+#define NB_RAND_CPLX 10000
+
+/* list of functions to compute the score */
+const struct benchfunc
+ arrayfunc[NB_BENCH_OP] = {
+ {"mul", ADDR_TIME_NOP (mpc_mul), ADDR_ACCURATE_TIME_NOP (mpc_mul), egroup_arith, 2},
+ {"add", ADDR_TIME_NOP (mpc_add), ADDR_ACCURATE_TIME_NOP (mpc_add), egroup_arith, 2},
+ {"sub", ADDR_TIME_NOP (mpc_sub), ADDR_ACCURATE_TIME_NOP (mpc_sub), egroup_arith, 2},
+ {"div", ADDR_TIME_NOP (mpc_div), ADDR_ACCURATE_TIME_NOP (mpc_div), egroup_arith, 2},
+ {"sqrt", ADDR_TIME_NOP (mpc_sqrt), ADDR_ACCURATE_TIME_NOP (mpc_sqrt), egroup_special, 1},
+ {"exp", ADDR_TIME_NOP (mpc_exp), ADDR_ACCURATE_TIME_NOP (mpc_exp), egroup_special, 1},
+ {"log", ADDR_TIME_NOP (mpc_log), ADDR_ACCURATE_TIME_NOP (mpc_log), egroup_special, 1},
+ {"cos", ADDR_TIME_NOP (mpc_cos), ADDR_ACCURATE_TIME_NOP (mpc_cos), egroup_special, 1},
+ {"sin", ADDR_TIME_NOP (mpc_sin), ADDR_ACCURATE_TIME_NOP (mpc_sin), egroup_special, 1},
+ {"acos", ADDR_TIME_NOP (mpc_acos), ADDR_ACCURATE_TIME_NOP (mpc_acos), egroup_special, 1},
+ {"asin", ADDR_TIME_NOP (mpc_asin), ADDR_ACCURATE_TIME_NOP (mpc_asin), egroup_special, 1}
+ };
+
+/* the following arrays must have the same number of elemnts */
+
+/* list of precision to test for the first operand */
+const int arrayprecision_op1[] =
+ { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
+ 50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 1500, 3000, 5000,
+};
+
+/* list of precision to test for the second operand */
+const int arrayprecision_op2[] =
+ { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
+ 50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 3000, 6000, 10000
+
+};
+
+/*! get the time in microseconds */
+static unsigned long
+get_cputime (void)
+{
+#ifdef HAVE_GETRUSAGE
+ struct rusage ru;
+
+ getrusage (RUSAGE_SELF, &ru);
+ return ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec
+ +ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
+#else
+ printf("\nthe function getrusage not available\n");
+ exit(1);
+ return 0;
+#endif
+}
+
+/* initialize an array of n random complex numbers */
+static mpc_t *
+bench_random_array (int n, mpfr_prec_t precision, gmp_randstate_t randstate)
+{
+ int j;
+
+ mpc_t *ptr;
+
+ ptr = (mpc_t *) malloc (n * sizeof (mpc_t));
+ if (ptr == NULL)
+ {
+ printf ("Can't allocate memory for %d complex numbers\n", n);
+ exit (1);
+ return NULL;
+ }
+ for (j = 0; j < n; j++)
+ {
+ mpc_init2 (ptr[j], precision);
+ mpc_urandom (ptr[j], randstate);
+ /*mpc_out_str(stdout, 10, 20, ptr[j], MPC_RNDNN);
+ fputs("\n", stdout); */
+ }
+ return ptr;
+}
+
+/* compute the score for the operation arrayfunc[op] */
+static void
+compute_score (mpz_t zscore, int op, gmp_randstate_t randstate)
+{
+ mpc_t *xptr, *yptr, *zptr;
+
+ int i, j;
+ size_t k;
+
+ unsigned long niter, ti;
+
+ double t;
+
+ unsigned long ops_per_sec;
+
+ int countprec = 0;
+
+ mpz_init_set_si (zscore, 1);
+
+ i = op;
+ for (k = 0; k < (int)sizeof (arrayprecision_op1) / sizeof (arrayprecision_op1[0]);
+ k++, countprec++)
+ {
+
+ mpfr_prec_t precision1 = arrayprecision_op1[k];
+ mpfr_prec_t precision2 = arrayprecision_op2[k];
+ mpfr_prec_t precision3 = arrayprecision_op2[k];
+ /* allocate array of random numbers */
+ xptr = bench_random_array (NB_RAND_CPLX, precision1, randstate);
+ yptr = bench_random_array (NB_RAND_CPLX, precision2, randstate);
+ zptr = bench_random_array (NB_RAND_CPLX, precision3, randstate);
+
+ /* compute the number of operations per seconds */
+ if (arrayfunc[i].noperands==2)
+ {
+ printf ("operation %5s, precision : %5lux%5lu to %5lu bits ... ", arrayfunc[i].name, precision1, precision2, precision3);
+ }
+ else
+ {
+ printf ("operation %5s, precision : %5lu to %5lu bits ... ", arrayfunc[i].name, precision1, precision3);
+ }
+ fflush (stdout);
+
+ t = arrayfunc[i].func_init (NB_RAND_CPLX, zptr, xptr, yptr);
+ niter = 1 + (unsigned long) (1e6 / t);
+
+ printf (" %10lu iterations ...", niter);
+ fflush (stdout);
+
+ /* ti expressed in microseconds */
+ ti = arrayfunc[i].func_accurate (niter, NB_RAND_CPLX, zptr, xptr, yptr, arrayfunc[i].noperands);
+
+ ops_per_sec = (unsigned long) (1000000E0 * niter / (double) ti);
+
+ printf (" %10lu operations per second\n", ops_per_sec);
+
+ mpz_mul_ui (zscore, zscore, ops_per_sec);
+
+ /* free memory */
+ for (j = 0; j < NB_RAND_CPLX; j++)
+ {
+ mpc_clear (xptr[j]);
+ mpc_clear (yptr[j]);
+ mpc_clear (zptr[j]);
+ }
+ free (xptr);
+ free (yptr);
+ free (zptr);
+ }
+
+ mpz_root (zscore, zscore, countprec);
+}
+
+/* compute the score for all groups */
+static void
+compute_groupscore (mpz_t groupscore[], int countop, mpz_t zscore[])
+{
+ int op;
+ enum egroupfunc group;
+ int countgroupop;
+
+ for (group = (enum egroupfunc)0; group != egroup_last; group++)
+ {
+ mpz_init_set_si (groupscore[group], 1);
+ for (op = 0, countgroupop = 0; op < countop; op++)
+ {
+ if (group == arrayfunc[op].group)
+ {
+ mpz_mul (groupscore[group], groupscore[group], zscore[op]);
+ countgroupop++;
+ }
+ }
+ mpz_root (groupscore[group], groupscore[group], countgroupop);
+ }
+}
+
+
+/* compute the global score */
+static void
+compute_globalscore (mpz_t globalscore, int countop, mpz_t zscore[])
+{
+ int op;
+
+ mpz_init_set_si (globalscore, 1);
+ for (op = 0; op < countop; op++)
+ {
+ mpz_mul (globalscore, globalscore, zscore[op]);
+ }
+ mpz_root (globalscore, globalscore, countop);
+}
+
+int
+main (void)
+{
+ int i;
+
+ enum egroupfunc group;
+
+ mpz_t score[NB_BENCH_OP];
+
+ mpz_t globalscore, groupscore[egroup_last];
+
+ gmp_randstate_t randstate;
+
+
+ gmp_randinit_default (randstate);
+
+ for (i = 0; i < NB_BENCH_OP; i++)
+ {
+ compute_score (score[i], i, randstate);
+ }
+ compute_globalscore (globalscore, NB_BENCH_OP, score);
+ compute_groupscore (groupscore, NB_BENCH_OP, score);
+
+ printf ("\n=================================================================\n\n");
+ printf ("GMP : %s MPFR : %s MPC: %s\n", gmp_version,
+ mpfr_get_version (), mpc_get_version ());
+#ifdef __GMP_CC
+ printf ("GMP compiler : %s\n", __GMP_CC);
+#endif
+#ifdef __GMP_CFLAGS
+ printf ("GMP flags : %s\n", __GMP_CFLAGS);
+#endif
+ printf ("\n\n");
+
+ for (i = 0; i < NB_BENCH_OP; i++)
+ {
+ gmp_printf ("\tscore for %5s : %12Zd\n", arrayfunc[i].name, score[i]);
+ if (i == NB_BENCH_OP-1 || arrayfunc[i +1].group != arrayfunc[i].group)
+ {
+ enum egroupfunc g = arrayfunc[i].group;
+ gmp_printf ("group score %s : %12Zd\n\n", groupname[g], groupscore[g]);
+ }
+ }
+ gmp_printf ("global score : %12Zd\n\n", globalscore);
+
+
+ for (i = 0; i < NB_BENCH_OP; i++)
+ {
+ mpz_clear (score[i]);
+ }
+
+ for (group = (enum egroupfunc)0; group != egroup_last; group++)
+ {
+ mpz_clear (groupscore[group]);
+ }
+ mpz_clear (globalscore);
+ gmp_randclear (randstate);
+ return 0;
+}