| /* Tune various threshold of MPFR |
| |
| Copyright 2005-2016 Free Software Foundation, Inc. |
| Contributed by the AriC and Caramba projects, INRIA. |
| |
| This file is part of the GNU MPFR Library. |
| |
| The GNU 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 GNU 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 GNU MPFR Library; see the file COPYING.LESSER. 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 <stdlib.h> |
| #include <time.h> |
| |
| #define MPFR_NEED_LONGLONG_H |
| #include "mpfr-impl.h" |
| |
| /* extracted from mulders.c */ |
| #ifdef MPFR_MULHIGH_TAB_SIZE |
| static short mulhigh_ktab[MPFR_MULHIGH_TAB_SIZE]; |
| #else |
| static short mulhigh_ktab[] = {MPFR_MULHIGH_TAB}; |
| #define MPFR_MULHIGH_TAB_SIZE \ |
| ((mp_size_t) (sizeof(mulhigh_ktab) / sizeof(mulhigh_ktab[0]))) |
| #endif |
| |
| #undef _PROTO |
| #define _PROTO __GMP_PROTO |
| #include "speed.h" |
| |
| int verbose; |
| |
| /* s->size: precision of both input and output |
| s->xp : Mantissa of first input |
| s->yp : mantissa of second input */ |
| |
| #define SPEED_MPFR_FUNC(mean_fun) do { \ |
| unsigned i; \ |
| mpfr_limb_ptr wp; \ |
| double t; \ |
| mpfr_t w, x; \ |
| mp_size_t size; \ |
| MPFR_TMP_DECL (marker); \ |
| \ |
| SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ |
| SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ |
| MPFR_TMP_MARK (marker); \ |
| \ |
| size = (s->size-1)/GMP_NUMB_BITS+1; \ |
| s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ |
| MPFR_TMP_INIT1 (s->xp, x, s->size); \ |
| MPFR_SET_EXP (x, 0); \ |
| \ |
| MPFR_TMP_INIT (wp, w, s->size, size); \ |
| \ |
| speed_operand_src (s, s->xp, size); \ |
| speed_operand_dst (s, wp, size); \ |
| speed_cache_fill (s); \ |
| \ |
| speed_starttime (); \ |
| i = s->reps; \ |
| do \ |
| mean_fun (w, x, MPFR_RNDN); \ |
| while (--i != 0); \ |
| t = speed_endtime (); \ |
| \ |
| MPFR_TMP_FREE (marker); \ |
| return t; \ |
| } while (0) |
| |
| #define SPEED_MPFR_OP(mean_fun) do { \ |
| unsigned i; \ |
| mpfr_limb_ptr wp; \ |
| double t; \ |
| mpfr_t w, x, y; \ |
| mp_size_t size; \ |
| MPFR_TMP_DECL (marker); \ |
| \ |
| SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ |
| SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ |
| MPFR_TMP_MARK (marker); \ |
| \ |
| size = (s->size-1)/GMP_NUMB_BITS+1; \ |
| s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ |
| MPFR_TMP_INIT1 (s->xp, x, s->size); \ |
| MPFR_SET_EXP (x, 0); \ |
| s->yp[size-1] |= MPFR_LIMB_HIGHBIT; \ |
| MPFR_TMP_INIT1 (s->yp, y, s->size); \ |
| MPFR_SET_EXP (y, 0); \ |
| \ |
| MPFR_TMP_INIT (wp, w, s->size, size); \ |
| \ |
| speed_operand_src (s, s->xp, size); \ |
| speed_operand_src (s, s->yp, size); \ |
| speed_operand_dst (s, wp, size); \ |
| speed_cache_fill (s); \ |
| \ |
| speed_starttime (); \ |
| i = s->reps; \ |
| do \ |
| mean_fun (w, x, y, MPFR_RNDN); \ |
| while (--i != 0); \ |
| t = speed_endtime (); \ |
| \ |
| MPFR_TMP_FREE (marker); \ |
| return t; \ |
| } while (0) |
| |
| |
| /* First we include all the functions we want to tune inside this program. |
| We can't use GNU MPFR library since the THRESHOLD can't vary */ |
| |
| /* Setup mpfr_mul */ |
| mpfr_prec_t mpfr_mul_threshold = MPFR_MUL_THRESHOLD; |
| static double speed_mpfr_mul (struct speed_params *s) { |
| SPEED_MPFR_OP (mpfr_mul); |
| } |
| |
| |
| |
| /************************************************ |
| * Common functions (inspired by GMP function) * |
| ************************************************/ |
| #define THRESHOLD_WINDOW 16 |
| #define THRESHOLD_FINAL_WINDOW 128 |
| static double domeasure (mpfr_prec_t *threshold, |
| double (*func) (struct speed_params *), |
| mpfr_prec_t p) |
| { |
| struct speed_params s; |
| mp_size_t size; |
| double t; |
| |
| s.align_xp = s.align_yp = s.align_wp = 64; |
| s.size = p; |
| size = (p - 1)/GMP_NUMB_BITS+1; |
| s.xp = malloc (2*size*sizeof (mp_limb_t)); |
| if (s.xp == NULL) |
| { |
| fprintf (stderr, "Can't allocate memory.\n"); |
| abort (); |
| } |
| mpn_random (s.xp, size); |
| s.yp = s.xp + size; |
| mpn_random (s.yp, size); |
| t = speed_measure (func, &s); |
| if (t == -1.0) |
| { |
| fprintf (stderr, "Failed to measure function!\n"); |
| abort (); |
| } |
| free (s.xp); |
| return t; |
| } |
| |
| /* Tune a function with a simple THRESHOLD |
| The function doesn't depend on another threshold. |
| It assumes that it uses algo1 if p < THRESHOLD |
| and algo2 otherwise. |
| if algo2 is better for low prec, and algo1 better for high prec, |
| the behaviour of this function is undefined. */ |
| static void |
| tune_simple_func (mpfr_prec_t *threshold, |
| double (*func) (struct speed_params *), |
| mpfr_prec_t pstart, mpfr_prec_t pend) |
| { |
| double measure; |
| mpfr_prec_t p = pstart; |
| mp_size_t k, n; |
| |
| while (p <= pend) |
| { |
| measure = domeasure (threshold, func, p); |
| printf ("prec=%lu mpfr_mul=%e ", p, measure); |
| n = 1 + (p - 1) / GMP_NUMB_BITS; |
| if (n <= MPFR_MUL_THRESHOLD) |
| k = MUL_FFT_THRESHOLD + 1; |
| else if (n < MPFR_MULHIGH_TAB_SIZE) |
| k = mulhigh_ktab[n]; |
| else |
| k = 2*n/3; |
| if (k < 0) |
| printf ("[mpn_mul_basecase]\n"); |
| else if (k == 0) |
| printf ("[mpfr_mulhigh_n_basecase]\n"); |
| else if (k > MUL_FFT_THRESHOLD) |
| printf ("[mpn_mul_n]\n"); |
| else |
| printf ("[mpfr_mulhigh_n]\n"); |
| p = p + p / 10; |
| } |
| } |
| |
| /******************************************************* |
| * Tune all the threshold of MPFR * |
| * Warning: tune the function in their dependent order!* |
| *******************************************************/ |
| static void |
| all (void) |
| { |
| FILE *f = stdout; |
| time_t start_time, end_time; |
| struct tm *tp; |
| |
| speed_time_init (); |
| if (verbose) { |
| printf ("Using: %s\n", speed_time_string); |
| printf ("speed_precision %d", speed_precision); |
| if (speed_unittime == 1.0) |
| printf (", speed_unittime 1 cycle"); |
| else |
| printf (", speed_unittime %.2e secs", speed_unittime); |
| if (speed_cycletime == 1.0 || speed_cycletime == 0.0) |
| printf (", CPU freq unknown\n"); |
| else |
| printf (", CPU freq %.2f MHz\n\n", 1e-6/speed_cycletime); |
| } |
| |
| time (&start_time); |
| tp = localtime (&start_time); |
| fprintf (f, "/* Generated by MPFR's tuneup.c, %d-%02d-%02d, ", |
| tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); |
| |
| #ifdef __ICC |
| fprintf (f, "icc %d.%d.%d */\n", __ICC / 100, __ICC / 10 % 10, __ICC % 10); |
| #elif defined(__GNUC__) |
| fprintf (f, "gcc %d.%d */\n", __GNUC__, __GNUC_MINOR__); |
| #elif defined (__SUNPRO_C) |
| fprintf (f, "Sun C %d.%d */\n", __SUNPRO_C / 0x100, __SUNPRO_C % 0x100); |
| #elif defined (__sgi) && defined (_COMPILER_VERSION) |
| fprintf (f, "MIPSpro C %d.%d.%d */\n", |
| _COMPILER_VERSION / 100, |
| _COMPILER_VERSION / 10 % 10, |
| _COMPILER_VERSION % 10); |
| #elif defined (__DECC) && defined (__DECC_VER) |
| fprintf (f, "DEC C %d */\n", __DECC_VER); |
| #else |
| fprintf (f, "system compiler */\n"); |
| #endif |
| fprintf (f, "\n"); |
| |
| /* Tune mpfr_mul (threshold is in limbs, but it doesn't matter too much) */ |
| if (verbose) |
| printf ("Measuring mpfr_mul with mpfr_mul_threshold=%lu...\n", |
| mpfr_mul_threshold); |
| tune_simple_func (&mpfr_mul_threshold, speed_mpfr_mul, |
| 2*GMP_NUMB_BITS+1, 1000); |
| |
| /* End of tuning */ |
| time (&end_time); |
| if (verbose) |
| printf ("Complete (took %ld seconds).\n", end_time - start_time); |
| } |
| |
| |
| /* Main function */ |
| int main (int argc, char *argv[]) |
| { |
| /* Unbuffered so if output is redirected to a file it isn't lost if the |
| program is killed part way through. */ |
| setbuf (stdout, NULL); |
| setbuf (stderr, NULL); |
| |
| verbose = argc > 1; |
| |
| if (verbose) |
| printf ("Tuning MPFR (Coffee time?)...\n"); |
| |
| all (); |
| |
| return 0; |
| } |