1 /* Tune various threshold of MPFR 2 3 Copyright 2005-2018 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 #undef _PROTO 30 #define _PROTO __GMP_PROTO 31 #include "speed.h" 32 33 /* Undefine static assertion system */ 34 #undef MPFR_DECL_STATIC_ASSERT 35 #undef MPFR_STAT_STATIC_ASSERT 36 #define MPFR_DECL_STATIC_ASSERT(a) MPFR_ASSERTN(a) 37 #define MPFR_STAT_STATIC_ASSERT(a) MPFR_ASSERTN(a) 38 39 int verbose; 40 41 /* template for an unary function */ 42 /* s->size: precision of both input and output 43 s->xp : Mantissa of first input 44 s->yp : mantissa of second input */ 45 #define SPEED_MPFR_FUNC(mean_fun) \ 46 do \ 47 { \ 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 } \ 80 while (0) 81 82 /* same as SPEED_MPFR_FUNC, but for say mpfr_sin_cos (y, z, x, r) */ 83 #define SPEED_MPFR_FUNC2(mean_fun) \ 84 do \ 85 { \ 86 unsigned i; \ 87 mpfr_limb_ptr vp, wp; \ 88 double t; \ 89 mpfr_t v, w, x; \ 90 mp_size_t size; \ 91 MPFR_TMP_DECL (marker); \ 92 \ 93 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 94 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 95 MPFR_TMP_MARK (marker); \ 96 \ 97 size = (s->size-1)/GMP_NUMB_BITS+1; \ 98 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 99 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 100 MPFR_SET_EXP (x, 0); \ 101 \ 102 MPFR_TMP_INIT (vp, v, s->size, size); \ 103 MPFR_TMP_INIT (wp, w, s->size, size); \ 104 \ 105 speed_operand_src (s, s->xp, size); \ 106 speed_operand_dst (s, vp, size); \ 107 speed_operand_dst (s, wp, size); \ 108 speed_cache_fill (s); \ 109 \ 110 speed_starttime (); \ 111 i = s->reps; \ 112 do \ 113 mean_fun (v, w, x, MPFR_RNDN); \ 114 while (--i != 0); \ 115 t = speed_endtime (); \ 116 \ 117 MPFR_TMP_FREE (marker); \ 118 return t; \ 119 } \ 120 while (0) 121 122 /* template for a function like mpfr_mul */ 123 #define SPEED_MPFR_OP(mean_fun) \ 124 do \ 125 { \ 126 unsigned i; \ 127 mpfr_limb_ptr wp; \ 128 double t; \ 129 mpfr_t w, x, y; \ 130 mp_size_t size; \ 131 MPFR_TMP_DECL (marker); \ 132 \ 133 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 134 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 135 MPFR_TMP_MARK (marker); \ 136 \ 137 size = (s->size-1)/GMP_NUMB_BITS+1; \ 138 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 139 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 140 MPFR_SET_EXP (x, 0); \ 141 s->yp[size-1] |= MPFR_LIMB_HIGHBIT; \ 142 MPFR_TMP_INIT1 (s->yp, y, s->size); \ 143 MPFR_SET_EXP (y, 0); \ 144 \ 145 MPFR_TMP_INIT (wp, w, s->size, size); \ 146 \ 147 speed_operand_src (s, s->xp, size); \ 148 speed_operand_src (s, s->yp, size); \ 149 speed_operand_dst (s, wp, size); \ 150 speed_cache_fill (s); \ 151 \ 152 speed_starttime (); \ 153 i = s->reps; \ 154 do \ 155 mean_fun (w, x, y, MPFR_RNDN); \ 156 while (--i != 0); \ 157 t = speed_endtime (); \ 158 \ 159 MPFR_TMP_FREE (marker); \ 160 return t; \ 161 } \ 162 while (0) 163 164 /* special template for mpfr_mul(a,b,b) */ 165 #define SPEED_MPFR_SQR(mean_fun) \ 166 do \ 167 { \ 168 unsigned i; \ 169 mpfr_limb_ptr wp; \ 170 double t; \ 171 mpfr_t w, x; \ 172 mp_size_t size; \ 173 MPFR_TMP_DECL (marker); \ 174 \ 175 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 176 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 177 MPFR_TMP_MARK (marker); \ 178 \ 179 size = (s->size-1)/GMP_NUMB_BITS+1; \ 180 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 181 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 182 MPFR_SET_EXP (x, 0); \ 183 \ 184 MPFR_TMP_INIT (wp, w, s->size, size); \ 185 \ 186 speed_operand_src (s, s->xp, size); \ 187 speed_operand_dst (s, wp, size); \ 188 speed_cache_fill (s); \ 189 \ 190 speed_starttime (); \ 191 i = s->reps; \ 192 do \ 193 mean_fun (w, x, x, MPFR_RNDN); \ 194 while (--i != 0); \ 195 t = speed_endtime (); \ 196 \ 197 MPFR_TMP_FREE (marker); \ 198 return t; \ 199 } \ 200 while (0) 201 202 /* s->size: precision of both input and output 203 s->xp : Mantissa of first input 204 s->r : exponent 205 s->align_xp : sign (1 means positive, 2 means negative) 206 */ 207 #define SPEED_MPFR_FUNC_WITH_EXPONENT(mean_fun) \ 208 do \ 209 { \ 210 unsigned i; \ 211 mpfr_limb_ptr wp; \ 212 double t; \ 213 mpfr_t w, x; \ 214 mp_size_t size; \ 215 MPFR_TMP_DECL (marker); \ 216 \ 217 SPEED_RESTRICT_COND (s->size >= MPFR_PREC_MIN); \ 218 SPEED_RESTRICT_COND (s->size <= MPFR_PREC_MAX); \ 219 MPFR_TMP_MARK (marker); \ 220 \ 221 size = (s->size-1)/GMP_NUMB_BITS+1; \ 222 s->xp[size-1] |= MPFR_LIMB_HIGHBIT; \ 223 MPFR_TMP_INIT1 (s->xp, x, s->size); \ 224 MPFR_SET_EXP (x, s->r); \ 225 if (s->align_xp == 2) MPFR_SET_NEG (x); \ 226 \ 227 MPFR_TMP_INIT (wp, w, s->size, size); \ 228 \ 229 speed_operand_src (s, s->xp, size); \ 230 speed_operand_dst (s, wp, size); \ 231 speed_cache_fill (s); \ 232 \ 233 speed_starttime (); \ 234 i = s->reps; \ 235 do \ 236 mean_fun (w, x, MPFR_RNDN); \ 237 while (--i != 0); \ 238 t = speed_endtime (); \ 239 \ 240 MPFR_TMP_FREE (marker); \ 241 return t; \ 242 } \ 243 while (0) 244 245 /* First we include all the functions we want to tune inside this program. 246 We can't use the GNU MPFR library since the thresholds are fixed macros. */ 247 248 /* Setup mpfr_exp_2 */ 249 mpfr_prec_t mpfr_exp_2_threshold; 250 #undef MPFR_EXP_2_THRESHOLD 251 #define MPFR_EXP_2_THRESHOLD mpfr_exp_2_threshold 252 #include "exp_2.c" 253 static double 254 speed_mpfr_exp_2 (struct speed_params *s) 255 { 256 SPEED_MPFR_FUNC (mpfr_exp_2); 257 } 258 259 /* Setup mpfr_exp */ 260 mpfr_prec_t mpfr_exp_threshold; 261 #undef MPFR_EXP_THRESHOLD 262 #define MPFR_EXP_THRESHOLD mpfr_exp_threshold 263 #include "exp.c" 264 static double 265 speed_mpfr_exp (struct speed_params *s) 266 { 267 SPEED_MPFR_FUNC (mpfr_exp); 268 } 269 270 /* Setup mpfr_sin_cos */ 271 mpfr_prec_t mpfr_sincos_threshold; 272 #undef MPFR_SINCOS_THRESHOLD 273 #define MPFR_SINCOS_THRESHOLD mpfr_sincos_threshold 274 #include "sin_cos.c" 275 #include "cos.c" 276 static double 277 speed_mpfr_sincos (struct speed_params *s) 278 { 279 SPEED_MPFR_FUNC2 (mpfr_sin_cos); 280 } 281 282 /* Setup mpfr_mul, mpfr_sqr and mpfr_div */ 283 /* Since mpfr_mul() deals with both mul and sqr, and contains an assert that 284 the thresholds are >= 1, we initialize both values to 1 to avoid a failed 285 assertion (let's recall that static assertions are replaced by normal 286 dynamic assertions here). */ 287 mpfr_prec_t mpfr_mul_threshold = 1; 288 mpfr_prec_t mpfr_sqr_threshold = 1; 289 mpfr_prec_t mpfr_div_threshold; 290 #undef MPFR_MUL_THRESHOLD 291 #define MPFR_MUL_THRESHOLD mpfr_mul_threshold 292 #undef MPFR_SQR_THRESHOLD 293 #define MPFR_SQR_THRESHOLD mpfr_sqr_threshold 294 #undef MPFR_DIV_THRESHOLD 295 #define MPFR_DIV_THRESHOLD mpfr_div_threshold 296 #include "mul.c" 297 #include "div.c" 298 static double 299 speed_mpfr_mul (struct speed_params *s) 300 { 301 SPEED_MPFR_OP (mpfr_mul); 302 } 303 static double 304 speed_mpfr_sqr (struct speed_params *s) 305 { 306 SPEED_MPFR_SQR (mpfr_mul); 307 } 308 static double 309 speed_mpfr_div (struct speed_params *s) 310 { 311 SPEED_MPFR_OP (mpfr_div); 312 } 313 314 /************************************************ 315 * Common functions (inspired by GMP function) * 316 ************************************************/ 317 static int 318 analyze_data (double *dat, int ndat) 319 { 320 double x, min_x; 321 int j, min_j; 322 323 x = 0.0; 324 for (j = 0; j < ndat; j++) 325 if (dat[j] > 0.0) 326 x += dat[j]; 327 328 min_x = x; 329 min_j = 0; 330 331 for (j = 0; j < ndat; x -= dat[j], j++) 332 { 333 if (x < min_x) 334 { 335 min_x = x; 336 min_j = j; 337 } 338 } 339 return min_j; 340 } 341 342 static double 343 mpfr_speed_measure (speed_function_t fun, struct speed_params *s, char *m) 344 { 345 double t = -1.0; 346 int i; 347 int number_of_iterations = 30; 348 for (i = 1; i <= number_of_iterations && t == -1.0; i++) 349 { 350 t = speed_measure (fun, s); 351 if ( (t == -1.0) && (i+1 <= number_of_iterations) ) 352 printf("speed_measure failed for size %lu. Trying again... (%d/%d)\n", 353 s->size, i+1, number_of_iterations); 354 } 355 if (t == -1.0) 356 { 357 fprintf (stderr, "Failed to measure %s!\n", m); 358 fprintf (stderr, "If CPU frequency scaling is enabled, please disable it:\n"); 359 fprintf (stderr, " under Linux: cpufreq-selector -g performance\n"); 360 fprintf (stderr, "On a multi-core processor, you might also try to load all the cores\n"); 361 abort (); 362 } 363 return t; 364 } 365 366 #define THRESHOLD_WINDOW 16 367 #define THRESHOLD_FINAL_WINDOW 128 368 static double 369 domeasure (mpfr_prec_t *threshold, 370 double (*func) (struct speed_params *), 371 mpfr_prec_t p) 372 { 373 struct speed_params s; 374 mp_size_t size; 375 double t1, t2, d; 376 377 s.align_xp = s.align_yp = s.align_wp = 64; 378 s.size = p; 379 size = (p - 1)/GMP_NUMB_BITS+1; 380 s.xp = malloc (2*size*sizeof (mp_limb_t)); 381 if (s.xp == NULL) 382 { 383 fprintf (stderr, "Can't allocate memory.\n"); 384 abort (); 385 } 386 mpn_random (s.xp, size); 387 s.yp = s.xp + size; 388 mpn_random (s.yp, size); 389 *threshold = MPFR_PREC_MAX; 390 t1 = mpfr_speed_measure (func, &s, "function 1"); 391 *threshold = 1; 392 t2 = mpfr_speed_measure (func, &s, "function 2"); 393 free (s.xp); 394 /* t1 is the time of the first algo (used for low prec) */ 395 if (t2 >= t1) 396 d = (t2 - t1) / t2; 397 else 398 d = (t2 - t1) / t1; 399 /* d > 0 if we have to use algo 1. 400 d < 0 if we have to use algo 2 */ 401 return d; 402 } 403 404 /* Performs measures when both the precision and the point of evaluation 405 shall vary. s.yp is ignored and not initialized. 406 It assumes that func depends on three thresholds with a boundary of the 407 form threshold1*x + threshold2*p = some scaling factor, if x<0, 408 and threshold3*x + threshold2*p = some scaling factor, if x>=0. 409 */ 410 static double 411 domeasure2 (long int *threshold1, long int *threshold2, long int *threshold3, 412 double (*func) (struct speed_params *), 413 mpfr_prec_t p, 414 mpfr_t x) 415 { 416 struct speed_params s; 417 mp_size_t size; 418 double t1, t2, d; 419 mpfr_t xtmp; 420 421 if (MPFR_IS_SINGULAR (x)) 422 { 423 mpfr_fprintf (stderr, "x=%RNf is not a regular number.\n"); 424 abort (); 425 } 426 if (MPFR_IS_NEG (x)) 427 s.align_xp = 2; 428 else 429 s.align_xp = 1; 430 431 s.align_yp = s.align_wp = 64; 432 s.size = p; 433 size = (p - 1)/GMP_NUMB_BITS+1; 434 435 mpfr_init2 (xtmp, p); 436 mpn_random (xtmp->_mpfr_d, size); 437 xtmp->_mpfr_d[size-1] |= MPFR_LIMB_HIGHBIT; 438 MPFR_SET_EXP (xtmp, -53); 439 mpfr_add_ui (xtmp, xtmp, 1, MPFR_RNDN); 440 mpfr_mul (xtmp, xtmp, x, MPFR_RNDN); /* xtmp = x*(1+perturb) */ 441 /* where perturb ~ 2^(-53) is */ 442 /* randomly chosen. */ 443 s.xp = xtmp->_mpfr_d; 444 s.r = MPFR_GET_EXP (xtmp); 445 446 *threshold1 = 0; 447 *threshold2 = 0; 448 *threshold3 = 0; 449 t1 = mpfr_speed_measure (func, &s, "function 1"); 450 451 if (MPFR_IS_NEG (x)) 452 *threshold1 = INT_MIN; 453 else 454 *threshold3 = INT_MAX; 455 *threshold2 = INT_MAX; 456 t2 = mpfr_speed_measure (func, &s, "function 2"); 457 458 /* t1 is the time of the first algo (used for low prec) */ 459 if (t2 >= t1) 460 d = (t2 - t1) / t2; 461 else 462 d = (t2 - t1) / t1; 463 /* d > 0 if we have to use algo 1. 464 d < 0 if we have to use algo 2 */ 465 mpfr_clear (xtmp); 466 return d; 467 } 468 469 /* Tune a function with a simple THRESHOLD 470 The function doesn't depend on another threshold. 471 It assumes that it uses algo1 if p < THRESHOLD 472 and algo2 otherwise. 473 if algo2 is better for low prec, and algo1 better for high prec, 474 the behaviour of this function is undefined. */ 475 static void 476 tune_simple_func (mpfr_prec_t *threshold, 477 double (*func) (struct speed_params *), 478 mpfr_prec_t pstart) 479 { 480 double measure[THRESHOLD_FINAL_WINDOW+1]; 481 double d; 482 mpfr_prec_t pstep; 483 int i, numpos, numneg, try; 484 mpfr_prec_t pmin, pmax, p; 485 486 /* first look for a lower bound within 10% */ 487 pmin = p = pstart; 488 d = domeasure (threshold, func, pmin); 489 if (d < 0.0) 490 { 491 if (verbose) 492 printf ("Oops: even for %lu, algo 2 seems to be faster!\n", 493 (unsigned long) pmin); 494 *threshold = MPFR_PREC_MIN; 495 return; 496 } 497 if (d >= 1.00) 498 for (;;) 499 { 500 d = domeasure (threshold, func, pmin); 501 if (d < 1.00) 502 break; 503 p = pmin; 504 pmin += pmin/2; 505 } 506 pmin = p; 507 for (;;) 508 { 509 d = domeasure (threshold, func, pmin); 510 if (d < 0.10) 511 break; 512 pmin += GMP_NUMB_BITS; 513 } 514 515 /* then look for an upper bound within 20% */ 516 pmax = pmin * 2; 517 for (;;) 518 { 519 d = domeasure (threshold, func, pmax); 520 if (d < -0.20) 521 break; 522 pmax += pmin / 2; /* don't increase too rapidly */ 523 } 524 525 /* The threshold is between pmin and pmax. Affine them */ 526 try = 0; 527 while ((pmax-pmin) >= THRESHOLD_FINAL_WINDOW) 528 { 529 pstep = MAX(MIN(GMP_NUMB_BITS/2,(pmax-pmin)/(2*THRESHOLD_WINDOW)),1); 530 if (verbose) 531 printf ("Pmin = %8lu Pmax = %8lu Pstep=%lu\n", pmin, pmax, pstep); 532 p = (pmin + pmax) / 2; 533 for (i = numpos = numneg = 0 ; i < THRESHOLD_WINDOW + 1 ; i++) 534 { 535 measure[i] = domeasure (threshold, func, 536 p+(i-THRESHOLD_WINDOW/2)*pstep); 537 if (measure[i] > 0) 538 numpos ++; 539 else if (measure[i] < 0) 540 numneg ++; 541 } 542 if (numpos > numneg) 543 /* We use more often algo 1 than algo 2 */ 544 pmin = p - THRESHOLD_WINDOW/2*pstep; 545 else if (numpos < numneg) 546 pmax = p + THRESHOLD_WINDOW/2*pstep; 547 else 548 /* numpos == numneg ... */ 549 if (++ try > 2) 550 { 551 *threshold = p; 552 if (verbose) 553 printf ("Quick find: %lu\n", *threshold); 554 return ; 555 } 556 } 557 558 /* Final tune... */ 559 if (verbose) 560 printf ("Finalizing in [%lu, %lu]... ", pmin, pmax); 561 for (i = 0 ; i < THRESHOLD_FINAL_WINDOW+1 ; i++) 562 measure[i] = domeasure (threshold, func, pmin+i); 563 i = analyze_data (measure, THRESHOLD_FINAL_WINDOW+1); 564 *threshold = pmin + i; 565 if (verbose) 566 printf ("%lu\n", *threshold); 567 return; 568 } 569 570 /* Tune a function which behavior depends on both p and x, 571 in a given direction. 572 It assumes that for (x,p) close to zero, algo1 is used 573 and algo2 is used when (x,p) is far from zero. 574 If algo2 is better for low prec, and algo1 better for high prec, 575 the behavior of this function is undefined. 576 This tuning function tries couples (x,p) of the form (ell*dirx, ell*dirp) 577 until it finds a point on the boundary. It returns ell. 578 */ 579 static void 580 tune_simple_func_in_some_direction (long int *threshold1, 581 long int *threshold2, 582 long int *threshold3, 583 double (*func) (struct speed_params *), 584 mpfr_prec_t pstart, 585 int dirx, int dirp, 586 mpfr_t xres, mpfr_prec_t *pres) 587 { 588 double measure[THRESHOLD_FINAL_WINDOW+1]; 589 double d; 590 mpfr_prec_t pstep; 591 int i, numpos, numneg, try; 592 mpfr_prec_t pmin, pmax, p; 593 mpfr_t xmin, xmax, x; 594 mpfr_t ratio; 595 596 mpfr_init2 (ratio, MPFR_SMALL_PRECISION); 597 mpfr_set_si (ratio, dirx, MPFR_RNDN); 598 mpfr_div_si (ratio, ratio, dirp, MPFR_RNDN); 599 600 mpfr_init2 (xmin, MPFR_SMALL_PRECISION); 601 mpfr_init2 (xmax, MPFR_SMALL_PRECISION); 602 mpfr_init2 (x, MPFR_SMALL_PRECISION); 603 604 /* first look for a lower bound within 10% */ 605 pmin = p = pstart; 606 mpfr_mul_ui (xmin, ratio, (unsigned int)pmin, MPFR_RNDN); 607 mpfr_set (x, xmin, MPFR_RNDN); 608 609 d = domeasure2 (threshold1, threshold2, threshold3, func, pmin, xmin); 610 if (d < 0.0) 611 { 612 if (verbose) 613 printf ("Oops: even for %lu, algo 2 seems to be faster!\n", 614 (unsigned long) pmin); 615 *pres = MPFR_PREC_MIN; 616 mpfr_mul_ui (xres, ratio, (unsigned int)*pres, MPFR_RNDN); 617 mpfr_clear (ratio); mpfr_clear (x); mpfr_clear (xmin); mpfr_clear (xmax); 618 return; 619 } 620 if (d >= 1.00) 621 for (;;) 622 { 623 d = domeasure2 (threshold1, threshold2, threshold3, func, pmin, xmin); 624 if (d < 1.00) 625 break; 626 p = pmin; 627 mpfr_set (x, xmin, MPFR_RNDN); 628 pmin += pmin/2; 629 mpfr_mul_ui (xmin, ratio, (unsigned int)pmin, MPFR_RNDN); 630 } 631 pmin = p; 632 mpfr_set (xmin, x, MPFR_RNDN); 633 for (;;) 634 { 635 d = domeasure2 (threshold1, threshold2, threshold3, func, pmin, xmin); 636 if (d < 0.10) 637 break; 638 pmin += GMP_NUMB_BITS; 639 mpfr_mul_ui (xmin, ratio, (unsigned int)pmin, MPFR_RNDN); 640 } 641 642 /* then look for an upper bound within 20% */ 643 pmax = pmin * 2; 644 mpfr_mul_ui (xmax, ratio, (unsigned int)pmax, MPFR_RNDN); 645 for (;;) 646 { 647 d = domeasure2 (threshold1, threshold2, threshold3, func, pmax, xmax); 648 if (d < -0.20) 649 break; 650 pmax += pmin / 2; /* don't increase too rapidly */ 651 mpfr_mul_ui (xmax, ratio, (unsigned int)pmax, MPFR_RNDN); 652 } 653 654 /* The threshold is between pmin and pmax. Affine them */ 655 try = 0; 656 while ((pmax-pmin) >= THRESHOLD_FINAL_WINDOW) 657 { 658 pstep = MAX(MIN(GMP_NUMB_BITS/2,(pmax-pmin)/(2*THRESHOLD_WINDOW)),1); 659 if (verbose) 660 printf ("Pmin = %8lu Pmax = %8lu Pstep=%lu\n", pmin, pmax, pstep); 661 p = (pmin + pmax) / 2; 662 mpfr_mul_ui (x, ratio, (unsigned int)p, MPFR_RNDN); 663 for (i = numpos = numneg = 0 ; i < THRESHOLD_WINDOW + 1 ; i++) 664 { 665 *pres = p+(i-THRESHOLD_WINDOW/2)*pstep; 666 mpfr_mul_ui (xres, ratio, (unsigned int)*pres, MPFR_RNDN); 667 measure[i] = domeasure2 (threshold1, threshold2, threshold3, 668 func, *pres, xres); 669 if (measure[i] > 0) 670 numpos ++; 671 else if (measure[i] < 0) 672 numneg ++; 673 } 674 if (numpos > numneg) 675 { 676 /* We use more often algo 1 than algo 2 */ 677 pmin = p - THRESHOLD_WINDOW/2*pstep; 678 mpfr_mul_ui (xmin, ratio, (unsigned int)pmin, MPFR_RNDN); 679 } 680 else if (numpos < numneg) 681 { 682 pmax = p + THRESHOLD_WINDOW/2*pstep; 683 mpfr_mul_ui (xmax, ratio, (unsigned int)pmax, MPFR_RNDN); 684 } 685 else 686 /* numpos == numneg ... */ 687 if (++ try > 2) 688 { 689 *pres = p; 690 mpfr_mul_ui (xres, ratio, (unsigned int)*pres, MPFR_RNDN); 691 if (verbose) 692 printf ("Quick find: %lu\n", *pres); 693 mpfr_clear (ratio); 694 mpfr_clear (x); mpfr_clear (xmin); mpfr_clear (xmax); 695 return ; 696 } 697 } 698 699 /* Final tune... */ 700 if (verbose) 701 printf ("Finalizing in [%lu, %lu]... ", pmin, pmax); 702 for (i = 0 ; i < THRESHOLD_FINAL_WINDOW+1 ; i++) 703 { 704 *pres = pmin+i; 705 mpfr_mul_ui (xres, ratio, (unsigned int)*pres, MPFR_RNDN); 706 measure[i] = domeasure2 (threshold1, threshold2, threshold3, 707 func, *pres, xres); 708 } 709 i = analyze_data (measure, THRESHOLD_FINAL_WINDOW+1); 710 *pres = pmin + i; 711 mpfr_mul_ui (xres, ratio, (unsigned int)*pres, MPFR_RNDN); 712 if (verbose) 713 printf ("%lu\n", *pres); 714 mpfr_clear (ratio); mpfr_clear (x); mpfr_clear (xmin); mpfr_clear (xmax); 715 return; 716 } 717 718 /************************************ 719 * Tune Mulders' mulhigh function * 720 ************************************/ 721 #define TOLERANCE 1.00 722 #define MULDERS_TABLE_SIZE 1024 723 #ifndef MPFR_MULHIGH_SIZE 724 # define MPFR_MULHIGH_SIZE MULDERS_TABLE_SIZE 725 #endif 726 #ifndef MPFR_SQRHIGH_SIZE 727 # define MPFR_SQRHIGH_SIZE MULDERS_TABLE_SIZE 728 #endif 729 #ifndef MPFR_DIVHIGH_SIZE 730 # define MPFR_DIVHIGH_SIZE MULDERS_TABLE_SIZE 731 #endif 732 #define MPFR_MULHIGH_TAB_SIZE MPFR_MULHIGH_SIZE 733 #define MPFR_SQRHIGH_TAB_SIZE MPFR_SQRHIGH_SIZE 734 #define MPFR_DIVHIGH_TAB_SIZE MPFR_DIVHIGH_SIZE 735 #include "mulders.c" 736 737 static double 738 speed_mpfr_mulhigh (struct speed_params *s) 739 { 740 SPEED_ROUTINE_MPN_MUL_N (mpfr_mulhigh_n); 741 } 742 743 static double 744 speed_mpfr_sqrhigh (struct speed_params *s) 745 { 746 SPEED_ROUTINE_MPN_SQR (mpfr_sqrhigh_n); 747 } 748 749 static double 750 speed_mpfr_divhigh (struct speed_params *s) 751 { 752 SPEED_ROUTINE_MPN_DC_DIVREM_CALL (mpfr_divhigh_n (q, a, d, s->size)); 753 } 754 755 #define MAX_STEPS 513 /* maximum number of values of k tried for a given n */ 756 757 /* Tune mpfr_mulhigh_n for size n */ 758 static mp_size_t 759 tune_mul_mulders_upto (mp_size_t n) 760 { 761 struct speed_params s; 762 mp_size_t k, kbest, step; 763 double t, tbest; 764 MPFR_TMP_DECL (marker); 765 766 if (n == 0) 767 return -1; 768 769 MPFR_TMP_MARK (marker); 770 s.align_xp = s.align_yp = s.align_wp = 64; 771 s.size = n; 772 s.xp = MPFR_TMP_ALLOC (n * sizeof (mp_limb_t)); 773 s.yp = MPFR_TMP_ALLOC (n * sizeof (mp_limb_t)); 774 mpn_random (s.xp, n); 775 mpn_random (s.yp, n); 776 777 /* Check k == -1, mpn_mul_basecase */ 778 mulhigh_ktab[n] = -1; 779 kbest = -1; 780 tbest = mpfr_speed_measure (speed_mpfr_mulhigh, &s, "mpfr_mulhigh"); 781 782 /* Check k == 0, mpn_mulhigh_n_basecase */ 783 mulhigh_ktab[n] = 0; 784 t = mpfr_speed_measure (speed_mpfr_mulhigh, &s, "mpfr_mulhigh"); 785 if (t * TOLERANCE < tbest) 786 kbest = 0, tbest = t; 787 788 /* Check Mulders with cutoff point k */ 789 step = 1 + n / (2 * MAX_STEPS); 790 /* we need k >= (n+3)/2, which translates into k >= (n+4)/2 in C */ 791 for (k = (n + 4) / 2 ; k < n ; k += step) 792 { 793 mulhigh_ktab[n] = k; 794 t = mpfr_speed_measure (speed_mpfr_mulhigh, &s, "mpfr_mulhigh"); 795 if (t * TOLERANCE < tbest) 796 kbest = k, tbest = t; 797 } 798 799 mulhigh_ktab[n] = kbest; 800 801 MPFR_TMP_FREE (marker); 802 return kbest; 803 } 804 805 /* Tune mpfr_sqrhigh_n for size n */ 806 static mp_size_t 807 tune_sqr_mulders_upto (mp_size_t n) 808 { 809 struct speed_params s; 810 mp_size_t k, kbest, step; 811 double t, tbest; 812 MPFR_TMP_DECL (marker); 813 814 if (n == 0) 815 return -1; 816 817 MPFR_TMP_MARK (marker); 818 s.align_xp = s.align_wp = 64; 819 s.size = n; 820 s.xp = MPFR_TMP_ALLOC (n * sizeof (mp_limb_t)); 821 mpn_random (s.xp, n); 822 823 /* Check k == -1, mpn_sqr_basecase */ 824 sqrhigh_ktab[n] = -1; 825 kbest = -1; 826 tbest = mpfr_speed_measure (speed_mpfr_sqrhigh, &s, "mpfr_sqrhigh"); 827 828 /* Check k == 0, mpfr_mulhigh_n_basecase */ 829 sqrhigh_ktab[n] = 0; 830 t = mpfr_speed_measure (speed_mpfr_sqrhigh, &s, "mpfr_sqrhigh"); 831 if (t * TOLERANCE < tbest) 832 kbest = 0, tbest = t; 833 834 /* Check Mulders */ 835 step = 1 + n / (2 * MAX_STEPS); 836 /* we need k >= (n+3)/2, which translates into k >= (n+4)/2 in C */ 837 for (k = (n + 4) / 2 ; k < n ; k += step) 838 { 839 sqrhigh_ktab[n] = k; 840 t = mpfr_speed_measure (speed_mpfr_sqrhigh, &s, "mpfr_sqrhigh"); 841 if (t * TOLERANCE < tbest) 842 kbest = k, tbest = t; 843 } 844 845 sqrhigh_ktab[n] = kbest; 846 847 MPFR_TMP_FREE (marker); 848 return kbest; 849 } 850 851 /* Tune mpfr_divhigh_n for size n */ 852 static mp_size_t 853 tune_div_mulders_upto (mp_size_t n) 854 { 855 struct speed_params s; 856 mp_size_t k, kbest, step; 857 double t, tbest; 858 MPFR_TMP_DECL (marker); 859 860 if (n == 0) 861 return 0; 862 863 MPFR_TMP_MARK (marker); 864 s.align_xp = s.align_yp = s.align_wp = s.align_wp2 = 64; 865 s.size = n; 866 s.xp = MPFR_TMP_ALLOC (n * sizeof (mp_limb_t)); 867 s.yp = MPFR_TMP_ALLOC (n * sizeof (mp_limb_t)); 868 mpn_random (s.xp, n); 869 mpn_random (s.yp, n); 870 871 /* Check k == n, i.e., mpn_divrem */ 872 divhigh_ktab[n] = n; 873 kbest = n; 874 tbest = mpfr_speed_measure (speed_mpfr_divhigh, &s, "mpfr_divhigh"); 875 876 /* Check k == 0, i.e., mpfr_divhigh_n_basecase */ 877 #if defined(WANT_GMP_INTERNALS) && defined(HAVE___GMPN_SBPI1_DIVAPPR_Q) 878 if (n > 2) /* mpn_sbpi1_divappr_q requires dn > 2 */ 879 #endif 880 { 881 divhigh_ktab[n] = 0; 882 t = mpfr_speed_measure (speed_mpfr_divhigh, &s, "mpfr_divhigh"); 883 if (t * TOLERANCE < tbest) 884 kbest = 0, tbest = t; 885 } 886 887 /* Check Mulders */ 888 step = 1 + n / (2 * MAX_STEPS); 889 /* we should have (n+3)/2 <= k < n, which translates into 890 (n+4)/2 <= k < n in C */ 891 for (k = (n + 4) / 2 ; k < n ; k += step) 892 { 893 divhigh_ktab[n] = k; 894 t = mpfr_speed_measure (speed_mpfr_divhigh, &s, "mpfr_divhigh"); 895 if (t * TOLERANCE < tbest) 896 kbest = k, tbest = t; 897 } 898 899 divhigh_ktab[n] = kbest; 900 901 MPFR_TMP_FREE (marker); 902 903 return kbest; 904 } 905 906 static void 907 tune_mul_mulders (FILE *f) 908 { 909 mp_size_t k; 910 911 if (verbose) 912 printf ("Tuning mpfr_mulhigh_n[%d]", (int) MPFR_MULHIGH_TAB_SIZE); 913 fprintf (f, "#define MPFR_MULHIGH_TAB \\\n "); 914 for (k = 0 ; k < MPFR_MULHIGH_TAB_SIZE ; k++) 915 { 916 fprintf (f, "%d", (int) tune_mul_mulders_upto (k)); 917 if (k != MPFR_MULHIGH_TAB_SIZE-1) 918 fputc (',', f); 919 if ((k+1) % 16 == 0) 920 fprintf (f, " \\\n "); 921 if (verbose) 922 putchar ('.'); 923 } 924 fprintf (f, " \n"); 925 if (verbose) 926 putchar ('\n'); 927 } 928 929 static void 930 tune_sqr_mulders (FILE *f) 931 { 932 mp_size_t k; 933 934 if (verbose) 935 printf ("Tuning mpfr_sqrhigh_n[%d]", (int) MPFR_SQRHIGH_TAB_SIZE); 936 fprintf (f, "#define MPFR_SQRHIGH_TAB \\\n "); 937 for (k = 0 ; k < MPFR_SQRHIGH_TAB_SIZE ; k++) 938 { 939 fprintf (f, "%d", (int) tune_sqr_mulders_upto (k)); 940 if (k != MPFR_SQRHIGH_TAB_SIZE-1) 941 fputc (',', f); 942 if ((k+1) % 16 == 0) 943 fprintf (f, " \\\n "); 944 if (verbose) 945 putchar ('.'); 946 } 947 fprintf (f, " \n"); 948 if (verbose) 949 putchar ('\n'); 950 } 951 952 static void 953 tune_div_mulders (FILE *f) 954 { 955 mp_size_t k; 956 957 if (verbose) 958 printf ("Tuning mpfr_divhigh_n[%d]", (int) MPFR_DIVHIGH_TAB_SIZE); 959 fprintf (f, "#define MPFR_DIVHIGH_TAB \\\n "); 960 for (k = 0 ; k < MPFR_DIVHIGH_TAB_SIZE ; k++) 961 { 962 fprintf (f, "%d", (int) tune_div_mulders_upto (k)); 963 if (k != MPFR_DIVHIGH_TAB_SIZE - 1) 964 fputc (',', f); 965 if ((k+1) % 16 == 0) 966 fprintf (f, " /*%zu-%zu*/ \\\n ", (size_t) k - 15, (size_t) k); 967 if (verbose) 968 putchar ('.'); 969 } 970 fprintf (f, " \n"); 971 if (verbose) 972 putchar ('\n'); 973 } 974 975 /******************************************************* 976 * Tuning functions for mpfr_ai * 977 *******************************************************/ 978 979 long int mpfr_ai_threshold1; 980 long int mpfr_ai_threshold2; 981 long int mpfr_ai_threshold3; 982 #undef MPFR_AI_THRESHOLD1 983 #define MPFR_AI_THRESHOLD1 mpfr_ai_threshold1 984 #undef MPFR_AI_THRESHOLD2 985 #define MPFR_AI_THRESHOLD2 mpfr_ai_threshold2 986 #undef MPFR_AI_THRESHOLD3 987 #define MPFR_AI_THRESHOLD3 mpfr_ai_threshold3 988 989 #include "ai.c" 990 991 static double 992 speed_mpfr_ai (struct speed_params *s) 993 { 994 SPEED_MPFR_FUNC_WITH_EXPONENT (mpfr_ai); 995 } 996 997 998 /******************************************************* 999 * Tune all the threshold of MPFR * 1000 * Warning: tune the function in their dependent order!* 1001 *******************************************************/ 1002 static void 1003 all (const char *filename) 1004 { 1005 FILE *f; 1006 time_t start_time, end_time; 1007 struct tm *tp; 1008 mpfr_t x1, x2, x3, tmp1, tmp2; 1009 mpfr_prec_t p1, p2, p3; 1010 1011 f = fopen (filename, "w"); 1012 if (f == NULL) 1013 { 1014 fprintf (stderr, "Can't open file '%s' for writing.\n", filename); 1015 abort (); 1016 } 1017 1018 speed_time_init (); 1019 if (verbose) 1020 { 1021 printf ("Using: %s\n", speed_time_string); 1022 printf ("speed_precision %d", speed_precision); 1023 if (speed_unittime == 1.0) 1024 printf (", speed_unittime 1 cycle"); 1025 else 1026 printf (", speed_unittime %.2e secs", speed_unittime); 1027 if (speed_cycletime == 1.0 || speed_cycletime == 0.0) 1028 printf (", CPU freq unknown\n"); 1029 else 1030 printf (", CPU freq %.2f MHz\n\n", 1e-6/speed_cycletime); 1031 } 1032 1033 time (&start_time); 1034 tp = localtime (&start_time); 1035 fprintf (f, "/* Generated by MPFR's tuneup.c, %d-%02d-%02d, ", 1036 tp->tm_year+1900, tp->tm_mon+1, tp->tm_mday); 1037 1038 #ifdef __ICC 1039 fprintf (f, "icc %d.%d.%d */\n", __ICC / 100, __ICC / 10 % 10, __ICC % 10); 1040 #elif defined(__GNUC__) 1041 #ifdef __GNUC_PATCHLEVEL__ 1042 fprintf (f, "gcc %d.%d.%d */\n", __GNUC__, __GNUC_MINOR__, 1043 __GNUC_PATCHLEVEL__); 1044 #else 1045 fprintf (f, "gcc %d.%d */\n", __GNUC__, __GNUC_MINOR__); 1046 #endif 1047 #elif defined (__SUNPRO_C) 1048 fprintf (f, "Sun C %d.%d */\n", __SUNPRO_C / 0x100, __SUNPRO_C % 0x100); 1049 #elif defined (__sgi) && defined (_COMPILER_VERSION) 1050 fprintf (f, "MIPSpro C %d.%d.%d */\n", 1051 _COMPILER_VERSION / 100, 1052 _COMPILER_VERSION / 10 % 10, 1053 _COMPILER_VERSION % 10); 1054 #elif defined (__DECC) && defined (__DECC_VER) 1055 fprintf (f, "DEC C %d */\n", __DECC_VER); 1056 #else 1057 fprintf (f, "system compiler */\n"); 1058 #endif 1059 fprintf (f, "\n\n"); 1060 fprintf (f, "#ifndef MPFR_TUNE_CASE\n"); 1061 fprintf (f, "#define MPFR_TUNE_CASE \"src/mparam.h\"\n"); 1062 fprintf (f, "#endif\n\n"); 1063 1064 /* Tune mulhigh */ 1065 tune_mul_mulders (f); 1066 1067 /* Tune sqrhigh */ 1068 tune_sqr_mulders (f); 1069 1070 /* Tune divhigh */ 1071 tune_div_mulders (f); 1072 fflush (f); 1073 1074 /* Tune mpfr_mul (threshold is in limbs, but it doesn't matter too much) */ 1075 if (verbose) 1076 printf ("Tuning mpfr_mul...\n"); 1077 tune_simple_func (&mpfr_mul_threshold, speed_mpfr_mul, 1078 2*GMP_NUMB_BITS+1); 1079 fprintf (f, "#define MPFR_MUL_THRESHOLD %lu /* limbs */\n", 1080 (unsigned long) (mpfr_mul_threshold - 1) / GMP_NUMB_BITS + 1); 1081 1082 /* Tune mpfr_sqr (threshold is in limbs, but it doesn't matter too much) */ 1083 if (verbose) 1084 printf ("Tuning mpfr_sqr...\n"); 1085 tune_simple_func (&mpfr_sqr_threshold, speed_mpfr_sqr, 1086 2*GMP_NUMB_BITS+1); 1087 fprintf (f, "#define MPFR_SQR_THRESHOLD %lu /* limbs */\n", 1088 (unsigned long) (mpfr_sqr_threshold - 1) / GMP_NUMB_BITS + 1); 1089 1090 /* Tune mpfr_div (threshold is in limbs, but it doesn't matter too much) */ 1091 if (verbose) 1092 printf ("Tuning mpfr_div...\n"); 1093 tune_simple_func (&mpfr_div_threshold, speed_mpfr_div, 1094 2*GMP_NUMB_BITS+1); 1095 fprintf (f, "#define MPFR_DIV_THRESHOLD %lu /* limbs */\n", 1096 (unsigned long) (mpfr_div_threshold - 1) / GMP_NUMB_BITS + 1); 1097 1098 /* Tune mpfr_exp_2 */ 1099 if (verbose) 1100 printf ("Tuning mpfr_exp_2...\n"); 1101 tune_simple_func (&mpfr_exp_2_threshold, speed_mpfr_exp_2, GMP_NUMB_BITS); 1102 fprintf (f, "#define MPFR_EXP_2_THRESHOLD %lu /* bits */\n", 1103 (unsigned long) mpfr_exp_2_threshold); 1104 1105 /* Tune mpfr_exp */ 1106 if (verbose) 1107 printf ("Tuning mpfr_exp...\n"); 1108 tune_simple_func (&mpfr_exp_threshold, speed_mpfr_exp, 1109 MPFR_PREC_MIN+3*GMP_NUMB_BITS); 1110 fprintf (f, "#define MPFR_EXP_THRESHOLD %lu /* bits */\n", 1111 (unsigned long) mpfr_exp_threshold); 1112 1113 /* Tune mpfr_sin_cos */ 1114 if (verbose) 1115 printf ("Tuning mpfr_sin_cos...\n"); 1116 tune_simple_func (&mpfr_sincos_threshold, speed_mpfr_sincos, 1117 MPFR_PREC_MIN+3*GMP_NUMB_BITS); 1118 fprintf (f, "#define MPFR_SINCOS_THRESHOLD %lu /* bits */\n", 1119 (unsigned long) mpfr_sincos_threshold); 1120 1121 /* Tune mpfr_ai */ 1122 if (verbose) 1123 printf ("Tuning mpfr_ai...\n"); 1124 mpfr_init2 (x1, MPFR_SMALL_PRECISION); 1125 mpfr_init2 (x2, MPFR_SMALL_PRECISION); 1126 mpfr_init2 (x3, MPFR_SMALL_PRECISION); 1127 mpfr_init2 (tmp1, MPFR_SMALL_PRECISION); 1128 mpfr_init2 (tmp2, MPFR_SMALL_PRECISION); 1129 1130 tune_simple_func_in_some_direction (&mpfr_ai_threshold1, &mpfr_ai_threshold2, 1131 &mpfr_ai_threshold3, speed_mpfr_ai, 1132 MPFR_PREC_MIN+GMP_NUMB_BITS, 1133 -60, 200, x1, &p1); 1134 tune_simple_func_in_some_direction (&mpfr_ai_threshold1, &mpfr_ai_threshold2, 1135 &mpfr_ai_threshold3, speed_mpfr_ai, 1136 MPFR_PREC_MIN+GMP_NUMB_BITS, 1137 -20, 500, x2, &p2); 1138 tune_simple_func_in_some_direction (&mpfr_ai_threshold1, &mpfr_ai_threshold2, 1139 &mpfr_ai_threshold3, speed_mpfr_ai, 1140 MPFR_PREC_MIN+GMP_NUMB_BITS, 1141 40, 200, x3, &p3); 1142 1143 mpfr_mul_ui (tmp1, x2, (unsigned long)p1, MPFR_RNDN); 1144 mpfr_mul_ui (tmp2, x1, (unsigned long)p2, MPFR_RNDN); 1145 mpfr_sub (tmp1, tmp1, tmp2, MPFR_RNDN); 1146 mpfr_div_ui (tmp1, tmp1, MPFR_AI_SCALE, MPFR_RNDN); 1147 1148 mpfr_set_ui (tmp2, (unsigned long)p1, MPFR_RNDN); 1149 mpfr_sub_ui (tmp2, tmp2, (unsigned long)p2, MPFR_RNDN); 1150 mpfr_div (tmp2, tmp2, tmp1, MPFR_RNDN); 1151 mpfr_ai_threshold1 = mpfr_get_si (tmp2, MPFR_RNDN); 1152 1153 mpfr_sub (tmp2, x2, x1, MPFR_RNDN); 1154 mpfr_div (tmp2, tmp2, tmp1, MPFR_RNDN); 1155 mpfr_ai_threshold2 = mpfr_get_si (tmp2, MPFR_RNDN); 1156 1157 mpfr_set_ui (tmp1, (unsigned long)p3, MPFR_RNDN); 1158 mpfr_mul_si (tmp1, tmp1, mpfr_ai_threshold2, MPFR_RNDN); 1159 mpfr_ui_sub (tmp1, MPFR_AI_SCALE, tmp1, MPFR_RNDN); 1160 mpfr_div (tmp1, tmp1, x3, MPFR_RNDN); 1161 mpfr_ai_threshold3 = mpfr_get_si (tmp1, MPFR_RNDN); 1162 1163 fprintf (f, "#define MPFR_AI_THRESHOLD1 %ld /* threshold for negative input of mpfr_ai */\n", mpfr_ai_threshold1); 1164 fprintf (f, "#define MPFR_AI_THRESHOLD2 %ld\n", mpfr_ai_threshold2); 1165 fprintf (f, "#define MPFR_AI_THRESHOLD3 %ld\n", mpfr_ai_threshold3); 1166 1167 mpfr_clear (x1); mpfr_clear (x2); mpfr_clear (x3); 1168 mpfr_clear (tmp1); mpfr_clear (tmp2); 1169 1170 /* End of tuning */ 1171 time (&end_time); 1172 fprintf (f, "/* Tuneup completed successfully, took %ld seconds */\n", 1173 (long) (end_time - start_time)); 1174 if (verbose) 1175 printf ("Complete (took %ld seconds).\n", (long) (end_time - start_time)); 1176 1177 fclose (f); 1178 } 1179 1180 1181 /* Main function */ 1182 int main (int argc, char *argv[]) 1183 { 1184 /* Unbuffered so if output is redirected to a file it isn't lost if the 1185 program is killed part way through. */ 1186 setbuf (stdout, NULL); 1187 setbuf (stderr, NULL); 1188 1189 verbose = argc > 1; 1190 1191 if (verbose) 1192 printf ("Tuning MPFR (Coffee time?)...\n"); 1193 1194 all ("mparam.h"); 1195 1196 return 0; 1197 } 1198