xref: /netbsd-src/external/lgpl3/mpc/dist/tools/bench/mpcbench.c (revision d536862b7d93d77932ef5de7eebdc48d76921b77)
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
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 *
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. */
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
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
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
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
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