1 /* mpcbench.c -- perform the benchmark on the complex numbers.
2
3 Copyright (C) 2014 CNRS - INRIA
4
5 This file is part of GNU MPC.
6
7 GNU MPC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU Lesser General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11
12 GNU MPC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14 FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
15 more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with this program. If not, see http://www.gnu.org/licenses/ .
19 */
20
21 #include "config.h"
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <math.h>
25 #ifdef HAVE_SYS_TIME_H
26 #include <sys/time.h>
27 #endif
28 #ifdef HAVE_SYS_RESOURCE_H
29 #include <sys/resource.h>
30 #endif
31 #include "mpc.h"
32 #include "benchtime.h"
33
34 static unsigned long get_cputime (void);
35
36 /* enumeration of the group of functions */
37 enum egroupfunc
38 {
39 egroup_arith = 0, /* e.g., arith ... */
40 egroup_special, /* e.g., cos, ... */
41 egroup_last /* to get the number of enum */
42 };
43
44 /* name of the group of functions */
45 const char *groupname [] = {
46 "Arith ",
47 "Special"
48 };
49
50
51
52 struct benchfunc
53 {
54 const char *name; /* name of the function */
55 double (*func_init) (int n, mpc_t * z, mpc_t * x, mpc_t * y); /* compute the time for one call (not accurate) */
56 unsigned long int (*func_accurate) (unsigned long int niter, int n, mpc_t * z, mpc_t * x, mpc_t * y, int nop); /* compute the time for "niter" calls (accurate) */
57 enum egroupfunc group; /* group of the function */
58 int noperands; /* number of operands */
59 };
60
61
62 /* declare the function to compute the cost for one call of the mpc function */
63 DECLARE_TIME_2OP (mpc_add)
64 DECLARE_TIME_2OP (mpc_sub)
65 DECLARE_TIME_2OP (mpc_mul)
66 DECLARE_TIME_2OP (mpc_div)
67 DECLARE_TIME_1OP (mpc_sqrt)
68 DECLARE_TIME_1OP (mpc_exp)
69 DECLARE_TIME_1OP (mpc_log)
70 DECLARE_TIME_2OP (mpc_pow)
71 DECLARE_TIME_1OP (mpc_sin)
72 DECLARE_TIME_1OP (mpc_cos)
73 DECLARE_TIME_1OP (mpc_asin)
74 DECLARE_TIME_1OP (mpc_acos)
75
76 /* number of operations to score*/
77 #define NB_BENCH_OP 12
78 /* number of random numbers */
79 #define NB_RAND_CPLX 10000
80
81 /* list of functions to compute the score */
82 const struct benchfunc
83 arrayfunc[NB_BENCH_OP] = {
84 {"add", ADDR_TIME_NOP (mpc_add), ADDR_ACCURATE_TIME_NOP (mpc_add), egroup_arith, 2},
85 {"sub", ADDR_TIME_NOP (mpc_sub), ADDR_ACCURATE_TIME_NOP (mpc_sub), egroup_arith, 2},
86 {"mul", ADDR_TIME_NOP (mpc_mul), ADDR_ACCURATE_TIME_NOP (mpc_mul), egroup_arith, 2},
87 {"div", ADDR_TIME_NOP (mpc_div), ADDR_ACCURATE_TIME_NOP (mpc_div), egroup_arith, 2},
88 {"sqrt", ADDR_TIME_NOP (mpc_sqrt), ADDR_ACCURATE_TIME_NOP (mpc_sqrt), egroup_arith, 1},
89 {"exp", ADDR_TIME_NOP (mpc_exp), ADDR_ACCURATE_TIME_NOP (mpc_exp), egroup_special, 1},
90 {"log", ADDR_TIME_NOP (mpc_log), ADDR_ACCURATE_TIME_NOP (mpc_log), egroup_special, 1},
91 {"pow", ADDR_TIME_NOP (mpc_pow), ADDR_ACCURATE_TIME_NOP (mpc_pow), egroup_special, 2},
92 {"sin", ADDR_TIME_NOP (mpc_sin), ADDR_ACCURATE_TIME_NOP (mpc_sin), egroup_special, 1},
93 {"cos", ADDR_TIME_NOP (mpc_cos), ADDR_ACCURATE_TIME_NOP (mpc_cos), egroup_special, 1},
94 {"asin", ADDR_TIME_NOP (mpc_asin), ADDR_ACCURATE_TIME_NOP (mpc_asin), egroup_special, 1},
95 {"acos", ADDR_TIME_NOP (mpc_acos), ADDR_ACCURATE_TIME_NOP (mpc_acos), egroup_special, 1}
96 };
97
98 /* the following arrays must have the same number of elements */
99
100 /* list of precisions to test for the first operand */
101 const int arrayprecision_op1[] =
102 { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
103 50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 1500, 3000, 5000,
104 };
105
106 /* list of precisions to test for the second operand */
107 const int arrayprecision_op2[] =
108 { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
109 50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 3000, 6000, 10000
110
111 };
112
113 /* get the time in microseconds */
114 static unsigned long
get_cputime(void)115 get_cputime (void)
116 {
117 #ifdef HAVE_GETRUSAGE
118 struct rusage ru;
119
120 getrusage (RUSAGE_SELF, &ru);
121 return ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec
122 +ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
123 #else
124 printf("\nthe function getrusage not available\n");
125 exit(1);
126 return 0;
127 #endif
128 }
129
130 /* initialize an array of n random complex numbers */
131 static mpc_t *
bench_random_array(int n,mpfr_prec_t precision,gmp_randstate_t randstate)132 bench_random_array (int n, mpfr_prec_t precision, gmp_randstate_t randstate)
133 {
134 int j;
135
136 mpc_t *ptr;
137
138 ptr = (mpc_t *) malloc (n * sizeof (mpc_t));
139 if (ptr == NULL)
140 {
141 printf ("Can't allocate memory for %d complex numbers\n", n);
142 exit (1);
143 return NULL;
144 }
145 for (j = 0; j < n; j++)
146 {
147 mpc_init2 (ptr[j], precision);
148 mpc_urandom (ptr[j], randstate);
149 }
150 return ptr;
151 }
152
153
154 /* Print the positive number x with 3 significant digits or at most 3 digits
155 after the komma, using 7 digits before the komma. */
sensible_print(double x)156 static void sensible_print (double x)
157 {
158 if (x < 1)
159 printf ("%11.3f", x);
160 else if (x < 10)
161 printf ("%10.2f", x);
162 else if (x < 100)
163 printf ("%9.1f", x);
164 else {
165 unsigned long int r;
166 unsigned int e = 0;
167 while (round (x) >= 1000) {
168 x /= 10;
169 e++;
170 }
171 r = (unsigned long int) round (x);
172 while (e > 0) {
173 r *= 10;
174 e--;
175 }
176 printf ("%7lu", r);
177 }
178 }
179
180
181 /* compute the score for the operation arrayfunc[op] */
182 static void
compute_score(double * zscore,int op,gmp_randstate_t randstate)183 compute_score (double *zscore, int op, gmp_randstate_t randstate)
184 {
185 mpc_t *xptr, *yptr, *zptr;
186
187 int i, j;
188 size_t k;
189
190 unsigned long niter, ti;
191
192 double t;
193
194 double ops_per_time;
195
196 int countprec = 0;
197
198 *zscore = 1.0;
199
200 i = op;
201 for (k = 0; k < (int)sizeof (arrayprecision_op1) / sizeof (arrayprecision_op1[0]);
202 k++, countprec++)
203 {
204
205 mpfr_prec_t precision1 = arrayprecision_op1[k];
206 mpfr_prec_t precision2 = arrayprecision_op2[k];
207 mpfr_prec_t precision3 = arrayprecision_op2[k];
208 /* allocate array of random numbers */
209 xptr = bench_random_array (NB_RAND_CPLX, precision1, randstate);
210 yptr = bench_random_array (NB_RAND_CPLX, precision2, randstate);
211 zptr = bench_random_array (NB_RAND_CPLX, precision3, randstate);
212
213 /* compute the number of operations per seconds */
214 if (arrayfunc[i].noperands==2)
215 printf ("op %4s, prec %5lux%5lu->%5lu:",
216 arrayfunc[i].name, precision1, precision2, precision3);
217 else
218 printf ("op %4s, prec %5lu ->%5lu:",
219 arrayfunc[i].name, precision1, precision3);
220 fflush (stdout);
221
222 t = arrayfunc[i].func_init (NB_RAND_CPLX, zptr, xptr, yptr);
223 niter = 1 + (unsigned long) (1e6 / t);
224
225 printf ("%9lu iter:", niter);
226 fflush (stdout);
227
228 /* ti expressed in microseconds */
229 niter = (niter + 9) / 10;
230 ti = arrayfunc[i].func_accurate (niter, NB_RAND_CPLX, zptr, xptr, yptr, arrayfunc[i].noperands);
231
232 ops_per_time = 1e5 * niter / (double) ti;
233 /* use 0.1s */
234
235 sensible_print (ops_per_time);
236 printf ("\n");
237
238 *zscore *= ops_per_time;
239
240 /* free memory */
241 for (j = 0; j < NB_RAND_CPLX; j++)
242 {
243 mpc_clear (xptr[j]);
244 mpc_clear (yptr[j]);
245 mpc_clear (zptr[j]);
246 }
247 free (xptr);
248 free (yptr);
249 free (zptr);
250 }
251
252 *zscore = pow (*zscore, 1.0 / (double) countprec);
253 }
254
255 /* compute the score for all groups */
256 static void
compute_groupscore(double groupscore[],int countop,double zscore[])257 compute_groupscore (double groupscore[], int countop, double zscore[])
258 {
259 int op;
260 enum egroupfunc group;
261 int countgroupop;
262
263 for (group = (enum egroupfunc)0; group != egroup_last; group++)
264 {
265 groupscore[group] = 1.0;
266 for (op = 0, countgroupop = 0; op < countop; op++)
267 {
268 if (group == arrayfunc[op].group)
269 {
270 groupscore[group] *= zscore[op];
271 countgroupop++;
272 }
273 }
274 groupscore[group] = pow (groupscore[group], 1.0 / (double) countgroupop);
275 }
276 }
277
278
279 /* compute the global score */
280 static void
compute_globalscore(double * globalscore,int countop,double zscore[])281 compute_globalscore (double *globalscore, int countop, double zscore[])
282 {
283 int op;
284
285 *globalscore = 1.0;
286 for (op = 0; op < countop; op++)
287 *globalscore *= zscore[op];
288 *globalscore = pow (*globalscore, 1.0 / (double) countop);
289 }
290
291 int
main(void)292 main (void)
293 {
294 int i;
295
296 double score[NB_BENCH_OP];
297
298 double globalscore, groupscore[egroup_last];
299
300 gmp_randstate_t randstate;
301
302 gmp_randinit_default (randstate);
303
304 for (i = 0; i < NB_BENCH_OP; i++)
305 compute_score (&(score[i]), i, randstate);
306 compute_globalscore (&globalscore, NB_BENCH_OP, score);
307 compute_groupscore (groupscore, NB_BENCH_OP, score);
308
309 printf ("\n=================================================================\n\n");
310 printf ("GMP: %s, MPFR: %s, MPC: %s\n", gmp_version,
311 mpfr_get_version (), mpc_get_version ());
312 #ifdef __GMP_CC
313 printf ("GMP compiler: %s\n", __GMP_CC);
314 #endif
315 #ifdef __GMP_CFLAGS
316 printf ("GMP flags : %s\n", __GMP_CFLAGS);
317 #endif
318 printf ("\n");
319
320 for (i = 0; i < NB_BENCH_OP; i++)
321 {
322 printf (" score for %4s ", arrayfunc[i].name);
323 sensible_print (score[i]);
324 printf ("\n");
325 if (i == NB_BENCH_OP-1 || arrayfunc[i +1].group != arrayfunc[i].group)
326 {
327 enum egroupfunc g = arrayfunc[i].group;
328 printf ("group score %s", groupname[g]);
329 sensible_print (groupscore[g]);
330 printf ("\n\n");
331 }
332 }
333 printf ("global score ");
334 sensible_print (globalscore);
335 printf ("\n\n");
336
337 gmp_randclear (randstate);
338 return 0;
339 }
340