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