1 /* Tune various threshold of MPFR 2 3 Copyright 2005-2016 Free Software Foundation, Inc. 4 Contributed by the AriC and Caramba projects, INRIA. 5 6 This file is part of the GNU MPFR Library. 7 8 The GNU MPFR Library is free software; you can redistribute it and/or modify 9 it under the terms of the GNU Lesser General Public License as published by 10 the Free Software Foundation; either version 3 of the License, or (at your 11 option) any later version. 12 13 The GNU MPFR Library is distributed in the hope that it will be useful, but 14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 15 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 16 License for more details. 17 18 You should have received a copy of the GNU Lesser General Public License 19 along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see 20 http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc., 21 51 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 31 static short mulhigh_ktab[MPFR_MULHIGH_TAB_SIZE]; 32 #else 33 static 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 42 int 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 */ 125 mpfr_prec_t mpfr_mul_threshold = MPFR_MUL_THRESHOLD; 126 static 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 137 static 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. */ 173 static void 174 tune_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 *******************************************************/ 209 static void 210 all (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 */ 268 int 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