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