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