/* Copyright 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. Contributed by Patrick Pelissier and Paul Zimmermann, INRIA. This file is part of the MPFR Library. The MPFR Library 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. The MPFR Library 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 the MPFR Library; see the file COPYING.LIB. If not, see http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include #include "timp.h" /* To avoid __gmpf_cmp to be declared as pure */ #define __GMP_NO_ATTRIBUTE_CONST_PURE #include "gmp.h" #include "mpfr.h" #ifdef SCS_SUPPORT # define SCS(x) x # include "scs.h" # define EXTRA_TEST_LIST \ BENCH("SCSLIB( Compiled var ):::::::::::", ; ); \ BENCH("scs_add", scs_add(sc1,sc2,sc3)); \ BENCH("scs_sub", scs_sub(sc1,sc2,sc3)); \ BENCH("scs_mul", scs_mul(sc1,sc2,sc3)); \ BENCH("scs_div", scs_div(sc1,sc2,sc3)); \ BENCH("scs_set", scs_set(sc1,sc2)); \ BENCH("scs_set0", scs_set_si(sc1,0)); \ BENCH("scs_set1", scs_set_si(sc1,1)); #else # define SCS(x) ((void) 0) # define EXTRA_TEST_LIST ((void)0); #endif #undef EXTRA_TEST_LIST # define EXTRA_TEST_LIST \ BENCH("mpfr_exp", mpfr_exp(a,b,GMP_RNDN)); \ BENCH("mpfr_log", mpfr_log(a,b,GMP_RNDN)); \ BENCH("mpfr_sin", mpfr_sin(a,b,GMP_RNDN)); \ BENCH("mpfr_cos", mpfr_cos(a,b,GMP_RNDN)); \ BENCH("mpfr_tan", mpfr_tan(a,b,GMP_RNDN)); \ BENCH("mpfr_asin", mpfr_asin(a,b,GMP_RNDN)); \ BENCH("mpfr_acos", mpfr_acos(a,b,GMP_RNDN)); \ BENCH("mpfr_atan", mpfr_atan(a,b,GMP_RNDN)); \ BENCH("mpfr_agm", mpfr_agm(a,b,c,GMP_RNDN)); \ BENCH("mpfr_const_log2", (mpfr_const_log2) (a, GMP_RNDN)); \ BENCH("mpfr_const_pi", (mpfr_const_pi)(a, GMP_RNDN)); \ BENCH("mpfr_sinh", mpfr_sinh(a,b,GMP_RNDN)); \ BENCH("mpfr_cosh", mpfr_cosh(a,b,GMP_RNDN)); \ BENCH("mpfr_tanh", mpfr_tanh(a,b,GMP_RNDN)); \ BENCH("mpfr_asinh", mpfr_asinh(a,b,GMP_RNDN)); \ BENCH("mpfr_acosh", mpfr_acosh(a,b,GMP_RNDN)); \ BENCH("mpfr_atanh", mpfr_atanh(a,b,GMP_RNDN)); /* Theses macros help the compiler to determine if a test is likely*/ /* or unlikely. */ #if __GNUC__ >= 3 # define LIKELY(x) (__builtin_expect(!!(x),1)) # define UNLIKELY(x) (__builtin_expect((x),0)) #else # define LIKELY(x) (x) # define UNLIKELY(x) (x) #endif /* * List of all the tests to do. * Macro "BENCH" is defined below. */ #define TEST_LIST \ BENCH("MPFR::::::::::", ; ); \ BENCH("mpfr_add", mpfr_add(a,b,c,GMP_RNDN)); \ BENCH("mpfr_sub", mpfr_sub(a,b,c,GMP_RNDN)); \ BENCH("mpfr_mul", mpfr_mul(a,b,c,GMP_RNDN)); \ BENCH("mpfr_div", mpfr_div(a,b,c,GMP_RNDN)); \ BENCH("mpfr_sqrt", mpfr_sqrt(a,b,GMP_RNDN)); \ BENCH("mpfr_cmp", mpfr_cmp(b,c)); \ BENCH("mpfr_sgn", mpfr_sgn(b)); \ BENCH("mpfr_set", mpfr_set(a,b, GMP_RNDN)); \ BENCH("mpfr_set0", mpfr_set_si(a,0,GMP_RNDN)); \ BENCH("mpfr_set1", mpfr_set_si(a,1,GMP_RNDN)); \ BENCH("mpfr_swap", mpfr_swap(b,c)); \ BENCH("MPF:::::::::::", ; ); \ BENCH("mpf_add", mpf_add(x,y,z)); \ BENCH("mpf_sub", mpf_sub(x,y,z)); \ BENCH("mpf_mul", mpf_mul(x,y,z)); \ BENCH("mpf_div", mpf_div(x,y,z)); \ BENCH("mpf_sqrt", mpf_sqrt(x,y)); \ BENCH("mpf_cmp", mpf_cmp(y,z)); \ BENCH("mpf_set", mpf_set(x,y)); \ BENCH("mpf_set0", mpf_set_si(x,0)); \ BENCH("mpf_set1", mpf_set_si(x,1)); \ BENCH("mpf_swap", mpf_swap(y,z)); \ EXTRA_TEST_LIST #define USAGE \ "Get the graph of the low-level functions of Mpfr (gnuplot).\n" \ __FILE__" " __DATE__" " __TIME__" GCC "__VERSION__ "\n" \ "Usage: mpfr-gfx [-bPREC_BEGIN] [-ePREC_END] [-sPREC_STEP] [-rPREC_RATIO]\n" \ " [-mSTAT_SIZE] [-oFILENAME] [-xFUNCTION_NUM] [-yFUNCTION_NUM] [-c]\n" \ " [-fSMOOTH] [-p]\n" unsigned long num; mpf_t *xt, *yt, *zt; int smooth = 3; /* (default) minimal number of routine calls for each number */ void lets_start(unsigned long n, mp_prec_t p) { unsigned long i; gmp_randstate_t state; num = n; xt = malloc(sizeof(mpf_t) * num); yt = malloc(sizeof(mpf_t) * num); zt = malloc(sizeof(mpf_t) * num); if (xt==NULL || yt==NULL || zt==NULL) { fprintf(stderr, "Can't allocate tables!\n"); abort(); } gmp_randinit_lc_2exp_size (state, 128); gmp_randseed_ui (state, 1452369); for(i = 0 ; i < num ; i++) { mpf_init2(xt[i], p); mpf_init2(yt[i], p); mpf_init2(zt[i], p); mpf_urandomb(yt[i], state, p); mpf_urandomb(zt[i], state, p); } gmp_randclear(state); } void lets_end(void) { unsigned long i; for(i = 0 ; i < num ; i++) { mpf_clear(xt[i]); mpf_clear(yt[i]); mpf_clear(zt[i]); } free (xt); free (yt); free (zt); } double get_speed(mp_prec_t p, int select) { unsigned long long mc[num], m; mpfr_t a,b,c; mpf_t x,y,z; unsigned long long moy; int i,j=0, op, cont, print_done = 0; const char *str = "void"; SCS(( scs_t sc1, sc2, sc3 )); mpf_init2(x, p); mpf_init2(y, p); mpf_init2(z, p); mpfr_init2(a, p); mpfr_init2(b, p); mpfr_init2(c, p); for(i = 0 ; i < num ; i++) { // yt[i][0]._mp_exp = (rand() % p) / GMP_NUMB_BITS; //zt[i][0]._mp_exp = (rand() % p) / GMP_NUMB_BITS; mc[i] = 0xFFFFFFFFFFFFFFFLL; } TIMP_OVERHEAD (); /* we perform at least smooth loops */ for(j = 0, cont = smooth ; cont ; j++, cont--) { /* we loop over each of the num random numbers */ for(i = 0 ; i < num ; i++) { /* Set var for tests */ mpf_set(y, yt[i]); mpf_set(z, zt[i]); mpfr_set_f(b, yt[i], GMP_RNDN); mpfr_set_f(c, zt[i], GMP_RNDN); SCS(( scs_set_mpfr(sc2, b), scs_set_mpfr(sc3, c) )); /* if the measured time m is smaller than the smallest one observed so far mc[i] for the i-th random number, we start again the smooth loops */ #undef BENCH #define BENCH(TEST_STR, TEST) \ if (op++ == select) { \ m = TIMP_MEASURE(TEST); \ str = TEST_STR; \ if (m < mc[i]) {mc[i] = m; cont = smooth;}\ } op = 0; TEST_LIST; if (print_done == 0 && strcmp (str, "void") != 0 ) { printf("Prec=%4.4lu Func=%20.20s", p, str); fflush (stdout); print_done = 1; } } } mpfr_clear(a); mpfr_clear(b); mpfr_clear(c); mpf_clear(x); mpf_clear(y); mpf_clear(z); /* End */ /* Save result */ moy = mc[0]; for(i = 1 ; i < num ; i++) moy += mc[i]; printf(" Pass=%4.4d..................%Lu.%Lu\n", j+1, moy/num, (moy*100LL/num)%100LL); return (double) (moy) / (double) num; } /* compares two functions given by indices select1 and select2 (by default select1 refers to mpfr and select2 to mpf). If postscript=0, output is plain gnuplot; If postscript=1, output is postscript. */ int write_data (const char *filename, unsigned long num, mp_prec_t p1, mp_prec_t p2, mp_prec_t ps, float pr, int select1, int select2, int postscript) { char strf[256], strg[256]; FILE *f, *g; mp_prec_t p, step; int op = 0; lets_start (num, p2); strcpy (strf, filename); strcat (strf, ".data"); f = fopen (strf, "w"); if (f == NULL) { fprintf (stderr, "Can't open %s!\n", strf); lets_end (); abort (); } strcpy (strg, filename); strcat (strg, ".gnuplot"); g = fopen (strg, "w"); if (g == NULL) { fprintf (stderr, "Can't open %s!\n", strg); lets_end (); abort (); } fprintf (g, "set data style lines\n"); if (postscript) fprintf (g, "set terminal postscript\n"); #undef BENCH #define BENCH(TEST_STR, TEST) \ if (++op == select1) \ fprintf (g, "plot \"%s\" using 1:2 title \"%s\", \\\n", strf, \ TEST_STR); \ else if (op == select2) \ fprintf (g, " \"%s\" using 1:3 title \"%s\"\n", strf, TEST_STR); op = -1; TEST_LIST; step = ps; for (p = p1 ; p < p2 ; p+=step) { fprintf(f, "%lu\t%1.20e\t%1.20e\n", p, get_speed(p, select1), get_speed(p, select2)); if (pr != 0.0) { step = (mp_prec_t) (p * pr - p); if (step < 1) step = 1; } } fclose (f); fclose (g); lets_end (); if (postscript == 0) fprintf (stderr, "Now type: gnuplot -persist %s.gnuplot\n", filename); else fprintf (stderr, "Now type: gnuplot %s.gnuplot > %s.ps\n", filename, filename); return 0; } /* this function considers all functions from s_begin to s_end */ int write_data2 (const char *filename, unsigned long num, mp_prec_t p_begin, mp_prec_t p_end, mp_prec_t p_step, float p_r, int s_begin, int s_end) { FILE *f; mp_prec_t p, step; int s; lets_start (num, p_end); f = fopen (filename, "w"); if (f == NULL) { fprintf (stderr, "Can't open %s!\n", filename); lets_end (); exit (1); } step = p_step; for (p = p_begin ; p < p_end ; p += step) { fprintf (f, "%lu", p); for (s = s_begin ; s <= s_end ; s++) fprintf (f, "\t%1.20e", get_speed (p, s)); fprintf (f, "\n"); if (p_r != 0.0) { step = (mp_prec_t) (p * p_r - p); if (step < 1) step = 1; } } fclose (f); lets_end (); return 0; } int op_num (void) { int op; #undef BENCH #define BENCH(TEST_STR, TEST) op++; op = 0; TEST_LIST; return op; } int main(int argc, const char *argv[]) { mp_prec_t p1, p2, ps; float pr; int i; unsigned long stat; const char *filename = "plot"; int select1, select2, max_op, conti; int postscript = 0; printf (USAGE); max_op = op_num (); select1 = 1; select2 = 13; p1 = 2; p2 = 500; ps = 4; pr = 0.0; stat = 500; /* number of different random numbers */ conti = 0; for(i = 1 ; i < argc ; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case 'b': p1 = atol(argv[i]+2); break; case 'e': p2 = atol(argv[i]+2); break; case 's': ps = atol(argv[i]+2); break; case 'r': pr = atof (argv[i]+2); if (pr <= 1.0) { fprintf (stderr, "-rPREC_RATIO must be > 1.0\n"); exit (1); } break; case 'm': stat = atol(argv[i]+2); break; case 'x': select1 = atoi (argv[i]+2); select2 = select1 + 12; break; case 'y': select2 = atoi (argv[i]+2); break; case 'o': filename = argv[i]+2; break; case 'c': conti = 1; break; case 'p': postscript = 1; break; case 'f': smooth = atoi (argv[i]+2); break; default: fprintf(stderr, "Unkwown option: %s\n", argv[i]); abort (); } } } /* Set low priority */ setpriority(PRIO_PROCESS,0,14); if (pr == 0.0) printf("GMP:%s MPFR:%s From p=%lu to %lu by %lu Output: %s N=%ld\n", gmp_version, mpfr_get_version(), p1,p2,ps, filename, stat); else printf("GMP:%s MPFR:%s From p=%lu to %lu by %f Output: %s N=%ld\n", gmp_version, mpfr_get_version(), p1, p2, pr, filename, stat); if (select2 >= max_op) select2 = max_op-1; if (select1 >= max_op) select1 = max_op-1; if (conti == 0) write_data (filename, stat, p1, p2, ps, pr, select1, select2, postscript); else write_data2 (filename, stat, p1, p2, ps, pr, select1, select2); return 0; }