1/* Tune various threshold of MPFR 2 3Copyright 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc. 4Contributed by the Arenaire and Cacao projects, INRIA. 5 6This file is part of the GNU MPFR Library. 7 8The GNU MPFR Library is free software; you can redistribute it and/or modify 9it under the terms of the GNU Lesser General Public License as published by 10the Free Software Foundation; either version 3 of the License, or (at your 11option) any later version. 12 13The GNU MPFR Library is distributed in the hope that it will be useful, but 14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16License for more details. 17 18You should have received a copy of the GNU Lesser General Public License 19along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ 22 23#include <stdlib.h> 24#include <time.h> 25 26#define MPFR_NEED_LONGLONG_H 27#include "mpfr-impl.h" 28 29/* extracted from mulders.c */ 30#ifdef MPFR_MULHIGH_TAB_SIZE 31static short mulhigh_ktab[MPFR_MULHIGH_TAB_SIZE]; 32#else 33static short mulhigh_ktab[] = {MPFR_MULHIGH_TAB}; 34#define MPFR_MULHIGH_TAB_SIZE \ 35 ((mp_size_t) (sizeof(mulhigh_ktab) / sizeof(mulhigh_ktab[0]))) 36#endif 37 38#undef _PROTO 39#define _PROTO __GMP_PROTO 40#include "speed.h" 41 42int verbose; 43 44/* s->size: precision of both input and output 45 s->xp : Mantissa of first input 46 s->yp : mantissa of second input */ 47 48#define SPEED_MPFR_FUNC(mean_fun) do { \ 49 unsigned i; \ 50 mpfr_limb_ptr wp; \ 51 double t; \ 52 mpfr_t w, x; \ 53 mp_size_t size; \ 54 MPFR_TMP_DECL (marker); \ 55 \ 56 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 57 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 58 MPFR_TMP_MARK (marker); \ 59 \ 60 size = (s->size-1)/GMP_NUMB_BITS+1; \ 61 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 62 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 63 MPFR_SET_EXP (x, 0); \ 64 \ 65 MPFR_TMP_INIT (wp, w, s->size, size); \ 66 \ 67 speed_operand_src (s, s->xp, size); \ 68 speed_operand_dst (s, wp, size); \ 69 speed_cache_fill (s); \ 70 \ 71 speed_starttime (); \ 72 i = s->reps; \ 73 do \ 74 mean_fun (w, x, MPFR_RNDN); \ 75 while (--i != 0); \ 76 t = speed_endtime (); \ 77 \ 78 MPFR_TMP_FREE (marker); \ 79 return t; \ 80} while (0) 81 82#define SPEED_MPFR_OP(mean_fun) do { \ 83 unsigned i; \ 84 mpfr_limb_ptr wp; \ 85 double t; \ 86 mpfr_t w, x, y; \ 87 mp_size_t size; \ 88 MPFR_TMP_DECL (marker); \ 89 \ 90 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 91 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 92 MPFR_TMP_MARK (marker); \ 93 \ 94 size = (s->size-1)/GMP_NUMB_BITS+1; \ 95 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 96 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 97 MPFR_SET_EXP (x, 0); \ 98 s->yp[size-1] |= MPFR_LIMB_HIGHBIT; \ 99 MPFR_TMP_INIT1 (s->yp, y, s->size); \ 100 MPFR_SET_EXP (y, 0); \ 101 \ 102 MPFR_TMP_INIT (wp, w, s->size, size); \ 103 \ 104 speed_operand_src (s, s->xp, size); \ 105 speed_operand_src (s, s->yp, size); \ 106 speed_operand_dst (s, wp, size); \ 107 speed_cache_fill (s); \ 108 \ 109 speed_starttime (); \ 110 i = s->reps; \ 111 do \ 112 mean_fun (w, x, y, MPFR_RNDN); \ 113 while (--i != 0); \ 114 t = speed_endtime (); \ 115 \ 116 MPFR_TMP_FREE (marker); \ 117 return t; \ 118} while (0) 119 120 121/* First we include all the functions we want to tune inside this program. 122 We can't use GNU MPFR library since the THRESHOLD can't vary */ 123 124/* Setup mpfr_mul */ 125mpfr_prec_t mpfr_mul_threshold = MPFR_MUL_THRESHOLD; 126static double speed_mpfr_mul (struct speed_params *s) { 127 SPEED_MPFR_OP (mpfr_mul); 128} 129 130 131 132/************************************************ 133 * Common functions (inspired by GMP function) * 134 ************************************************/ 135#define THRESHOLD_WINDOW 16 136#define THRESHOLD_FINAL_WINDOW 128 137static double domeasure (mpfr_prec_t *threshold, 138 double (*func) (struct speed_params *), 139 mpfr_prec_t p) 140{ 141 struct speed_params s; 142 mp_size_t size; 143 double t; 144 145 s.align_xp = s.align_yp = s.align_wp = 64; 146 s.size = p; 147 size = (p - 1)/GMP_NUMB_BITS+1; 148 s.xp = malloc (2*size*sizeof (mp_limb_t)); 149 if (s.xp == NULL) 150 { 151 fprintf (stderr, "Can't allocate memory.\n"); 152 abort (); 153 } 154 mpn_random (s.xp, size); 155 s.yp = s.xp + size; 156 mpn_random (s.yp, size); 157 t = speed_measure (func, &s); 158 if (t == -1.0) 159 { 160 fprintf (stderr, "Failed to measure function!\n"); 161 abort (); 162 } 163 free (s.xp); 164 return t; 165} 166 167/* Tune a function with a simple THRESHOLD 168 The function doesn't depend on another threshold. 169 It assumes that it uses algo1 if p < THRESHOLD 170 and algo2 otherwise. 171 if algo2 is better for low prec, and algo1 better for high prec, 172 the behaviour of this function is undefined. */ 173static void 174tune_simple_func (mpfr_prec_t *threshold, 175 double (*func) (struct speed_params *), 176 mpfr_prec_t pstart, mpfr_prec_t pend) 177{ 178 double measure; 179 mpfr_prec_t p = pstart; 180 mp_size_t k, n; 181 182 while (p <= pend) 183 { 184 measure = domeasure (threshold, func, p); 185 printf ("prec=%lu mpfr_mul=%e ", p, measure); 186 n = 1 + (p - 1) / GMP_NUMB_BITS; 187 if (n <= MPFR_MUL_THRESHOLD) 188 k = MUL_FFT_THRESHOLD + 1; 189 else if (n < MPFR_MULHIGH_TAB_SIZE) 190 k = mulhigh_ktab[n]; 191 else 192 k = 2*n/3; 193 if (k < 0) 194 printf ("[mpn_mul_basecase]\n"); 195 else if (k == 0) 196 printf ("[mpfr_mulhigh_n_basecase]\n"); 197 else if (k > MUL_FFT_THRESHOLD) 198 printf ("[mpn_mul_n]\n"); 199 else 200 printf ("[mpfr_mulhigh_n]\n"); 201 p = p + p / 10; 202 } 203} 204 205/******************************************************* 206 * Tune all the threshold of MPFR * 207 * Warning: tune the function in their dependent order!* 208 *******************************************************/ 209static void 210all (void) 211{ 212 FILE *f = stdout; 213 time_t start_time, end_time; 214 struct tm *tp; 215 216 speed_time_init (); 217 if (verbose) { 218 printf ("Using: %s\n", speed_time_string); 219 printf ("speed_precision %d", speed_precision); 220 if (speed_unittime == 1.0) 221 printf (", speed_unittime 1 cycle"); 222 else 223 printf (", speed_unittime %.2e secs", speed_unittime); 224 if (speed_cycletime == 1.0 || speed_cycletime == 0.0) 225 printf (", CPU freq unknown\n"); 226 else 227 printf (", CPU freq %.2f MHz\n\n", 1e-6/speed_cycletime); 228 } 229 230 time (&start_time); 231 tp = localtime (&start_time); 232 fprintf (f, "/* Generated by MPFR's tuneup.c, %d-%02d-%02d, ", 233 tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); 234 235#ifdef __ICC 236 fprintf (f, "icc %d.%d.%d */\n", __ICC / 100, __ICC / 10 % 10, __ICC % 10); 237#elif defined(__GNUC__) 238 fprintf (f, "gcc %d.%d */\n", __GNUC__, __GNUC_MINOR__); 239#elif defined (__SUNPRO_C) 240 fprintf (f, "Sun C %d.%d */\n", __SUNPRO_C / 0x100, __SUNPRO_C % 0x100); 241#elif defined (__sgi) && defined (_COMPILER_VERSION) 242 fprintf (f, "MIPSpro C %d.%d.%d */\n", 243 _COMPILER_VERSION / 100, 244 _COMPILER_VERSION / 10 % 10, 245 _COMPILER_VERSION % 10); 246#elif defined (__DECC) && defined (__DECC_VER) 247 fprintf (f, "DEC C %d */\n", __DECC_VER); 248#else 249 fprintf (f, "system compiler */\n"); 250#endif 251 fprintf (f, "\n"); 252 253 /* Tune mpfr_mul (threshold is in limbs, but it doesn't matter too much) */ 254 if (verbose) 255 printf ("Measuring mpfr_mul with mpfr_mul_threshold=%lu...\n", 256 mpfr_mul_threshold); 257 tune_simple_func (&mpfr_mul_threshold, speed_mpfr_mul, 258 2*GMP_NUMB_BITS+1, 1000); 259 260 /* End of tuning */ 261 time (&end_time); 262 if (verbose) 263 printf ("Complete (took %ld seconds).\n", end_time - start_time); 264} 265 266 267/* Main function */ 268int main (int argc, char *argv[]) 269{ 270 /* Unbuffered so if output is redirected to a file it isn't lost if the 271 program is killed part way through. */ 272 setbuf (stdout, NULL); 273 setbuf (stderr, NULL); 274 275 verbose = argc > 1; 276 277 if (verbose) 278 printf ("Tuning MPFR (Coffee time?)...\n"); 279 280 all (); 281 282 return 0; 283} 284