xref: /netbsd-src/external/lgpl3/mpfr/dist/tune/speed.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Tune various threshold of MPFR
2 
3 Copyright 2005-2023 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;
speed_mpfr_mul(struct speed_params * s)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
domeasure(mpfr_prec_t * threshold,double (* func)(struct speed_params *),mpfr_prec_t p)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
tune_simple_func(mpfr_prec_t * threshold,double (* func)(struct speed_params *),mpfr_prec_t pstart,mpfr_prec_t pend)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
all(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 */
main(int argc,char * argv[])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