(root)/
mpfr-4.2.1/
tools/
bench/
mpfrbench.c
       1  /* mpfrbench.c  -- compute the timings for the MPFRbench benchmark
       2  
       3  Copyright 1999, 2001-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 <stdio.h>
      25  #ifdef HAVE_GETRUSAGE
      26  #include <sys/time.h>
      27  #include <sys/resource.h>
      28  #else
      29  #include <time.h>
      30  #endif
      31  #include "mpfr.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, mpfr_t * z, mpfr_t * x, mpfr_t * y); /* compute the time for one call (not accurate) */
      56    unsigned long int (*func_accurate) (unsigned long int niter, int n, mpfr_t * z, mpfr_t * x, mpfr_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 function */
      63  DECLARE_TIME_2OP (mpfr_mul)
      64  DECLARE_TIME_2OP (mpfr_add)
      65  DECLARE_TIME_2OP (mpfr_sub)
      66  DECLARE_TIME_2OP (mpfr_div)
      67  DECLARE_TIME_1OP (mpfr_sqrt)
      68  DECLARE_TIME_1OP (mpfr_exp)
      69  DECLARE_TIME_1OP (mpfr_log)
      70  DECLARE_TIME_1OP (mpfr_sin)
      71  DECLARE_TIME_1OP (mpfr_cos)
      72  DECLARE_TIME_1OP (mpfr_asin)
      73  DECLARE_TIME_1OP (mpfr_acos)
      74  
      75  /* number of operations to score */
      76  #define NB_BENCH_OP 11
      77  /* number of random numbers */
      78  #define NB_RAND_FLOAT 10000
      79  
      80  /* list of functions to compute the score */
      81  const struct benchfunc arrayfunc[NB_BENCH_OP] = {
      82    {"mul", ADDR_TIME_NOP (mpfr_mul), ADDR_ACCURATE_TIME_NOP (mpfr_mul), egroup_arith, 2},
      83    {"add", ADDR_TIME_NOP (mpfr_add), ADDR_ACCURATE_TIME_NOP (mpfr_add), egroup_arith, 2},
      84    {"sub", ADDR_TIME_NOP (mpfr_sub), ADDR_ACCURATE_TIME_NOP (mpfr_sub), egroup_arith, 2},
      85    {"div", ADDR_TIME_NOP (mpfr_div), ADDR_ACCURATE_TIME_NOP (mpfr_div), egroup_arith, 2},
      86    {"sqrt", ADDR_TIME_NOP (mpfr_sqrt), ADDR_ACCURATE_TIME_NOP (mpfr_sqrt), egroup_special, 1},
      87    {"exp", ADDR_TIME_NOP (mpfr_exp), ADDR_ACCURATE_TIME_NOP (mpfr_exp), egroup_special, 1},
      88    {"log", ADDR_TIME_NOP (mpfr_log), ADDR_ACCURATE_TIME_NOP (mpfr_log), egroup_special, 1},
      89    {"cos", ADDR_TIME_NOP (mpfr_cos), ADDR_ACCURATE_TIME_NOP (mpfr_cos), egroup_special, 1},
      90    {"sin", ADDR_TIME_NOP (mpfr_sin), ADDR_ACCURATE_TIME_NOP (mpfr_sin), egroup_special, 1},
      91    {"acos", ADDR_TIME_NOP (mpfr_acos), ADDR_ACCURATE_TIME_NOP (mpfr_acos), egroup_special, 1},
      92    {"asin", ADDR_TIME_NOP (mpfr_asin), ADDR_ACCURATE_TIME_NOP (mpfr_asin), egroup_special, 1}
      93  };
      94  
      95  /* the following arrays must have the same number of elements */
      96  
      97  /* list of precisions to test for the first operand */
      98  const int arrayprecision_op1[] =
      99    { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
     100      50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 1500, 3000, 5000,
     101    };
     102  
     103  /* list of precisions to test for the second operand */
     104  const int arrayprecision_op2[] =
     105    { 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384,
     106      50, 100, 200, 350, 700, 1500, 3000, 6000, 10000, 3000, 6000, 10000
     107    };
     108  
     109  /* get the time in microseconds */
     110  static unsigned long
     111  get_cputime (void)
     112  {
     113  #ifdef HAVE_GETRUSAGE
     114    struct rusage ru;
     115  
     116    getrusage (RUSAGE_SELF, &ru);
     117    return ru.ru_utime.tv_sec * 1000000 + ru.ru_utime.tv_usec
     118         + ru.ru_stime.tv_sec * 1000000 + ru.ru_stime.tv_usec;
     119  #else
     120    return (unsigned long) ((double) clock () / ((double) CLOCKS_PER_SEC / 1e6));
     121  #endif
     122  }
     123  
     124  /* initialize an array of n random numbers */
     125  static mpfr_t *
     126  bench_random_array (int n, mpfr_prec_t precision, gmp_randstate_t randstate)
     127  {
     128    int j;
     129    mpfr_t *ptr;
     130  
     131    ptr = (mpfr_t *) malloc (n * sizeof (mpfr_t));
     132    if (ptr == NULL)
     133      {
     134        printf ("Can't allocate memory for %d numbers\n", n);
     135        exit (1);
     136        return NULL;
     137      }
     138    for (j = 0; j < n; j++)
     139      {
     140        mpfr_init2 (ptr[j], precision);
     141        mpfr_urandomb (ptr[j], randstate);
     142      }
     143    return ptr;
     144  }
     145  
     146  /* compute the score for the operation arrayfunc[op] */
     147  static void
     148  compute_score (mpz_t zscore, int op, gmp_randstate_t randstate)
     149  {
     150    mpfr_t *xptr, *yptr, *zptr;
     151    int i, j;
     152    size_t k;
     153    unsigned long niter, ti;
     154    double t;
     155    unsigned long ops_per_sec;
     156    int countprec = 0;
     157  
     158    mpz_init_set_si (zscore, 1);
     159  
     160    i = op;
     161    for (k = 0; k < (int) sizeof (arrayprecision_op1) / sizeof (arrayprecision_op1[0]);
     162         k++, countprec++)
     163      {
     164        mpfr_prec_t precision1 = arrayprecision_op1[k];
     165        mpfr_prec_t precision2 = arrayprecision_op2[k];
     166        mpfr_prec_t precision3 = arrayprecision_op2[k];
     167  
     168        /* allocate array of random numbers */
     169        xptr = bench_random_array (NB_RAND_FLOAT, precision1, randstate);
     170        yptr = bench_random_array (NB_RAND_FLOAT, precision2, randstate);
     171        zptr = bench_random_array (NB_RAND_FLOAT, precision3, randstate);
     172  
     173        /* compute the number of operations per second */
     174        if (arrayfunc[i].noperands==2)
     175          {
     176            printf ("operation %5s, precision : %5lux%5lu to %5lu bits ... ", arrayfunc[i].name, precision1, precision2, precision3);
     177          }
     178        else
     179          {
     180            printf ("operation %5s, precision :       %5lu to %5lu bits ... ", arrayfunc[i].name, precision1, precision3);
     181          }
     182        fflush (stdout);
     183  
     184        t = arrayfunc[i].func_init (NB_RAND_FLOAT, zptr, xptr, yptr);
     185        niter = 1 + (unsigned long) (1e6 / t);
     186  
     187        printf (" %10lu iterations ...", niter);
     188        fflush (stdout);
     189  
     190        /* ti expressed in microseconds */
     191        ti = arrayfunc[i].func_accurate (niter, NB_RAND_FLOAT, zptr, xptr, yptr, arrayfunc[i].noperands);
     192  
     193        ops_per_sec = (unsigned long) (1000000E0 * niter / (double) ti);
     194  
     195        printf (" %10lu operations per second\n", ops_per_sec);
     196  
     197        mpz_mul_ui (zscore, zscore, ops_per_sec);
     198  
     199        /* free memory */
     200        for (j = 0; j < NB_RAND_FLOAT; j++)
     201          {
     202            mpfr_clear (xptr[j]);
     203            mpfr_clear (yptr[j]);
     204            mpfr_clear (zptr[j]);
     205          }
     206        free (xptr);
     207        free (yptr);
     208        free (zptr);
     209      }
     210  
     211    mpz_root (zscore, zscore, countprec);
     212  }
     213  
     214  /* compute the score for all groups */
     215  static void
     216  compute_groupscore (mpz_t groupscore[], int countop, mpz_t zscore[])
     217  {
     218    int op;
     219    enum egroupfunc group;
     220    int countgroupop;
     221  
     222    for (group = (enum egroupfunc)0; group != egroup_last; group++)
     223      {
     224        mpz_init_set_si (groupscore[group], 1);
     225        for (op = 0, countgroupop = 0; op < countop; op++)
     226          {
     227            if (group == arrayfunc[op].group)
     228              {
     229                mpz_mul (groupscore[group], groupscore[group], zscore[op]);
     230                countgroupop++;
     231              }
     232          }
     233        mpz_root (groupscore[group], groupscore[group], countgroupop);
     234      }
     235  }
     236  
     237  
     238  /* compute the global score */
     239  static void
     240  compute_globalscore (mpz_t globalscore, int countop, mpz_t zscore[])
     241  {
     242    int op;
     243  
     244    mpz_init_set_si (globalscore, 1);
     245    for (op = 0; op < countop; op++)
     246      {
     247        mpz_mul (globalscore, globalscore, zscore[op]);
     248      }
     249    mpz_root (globalscore, globalscore, countop);
     250  }
     251  
     252  int
     253  main (void)
     254  {
     255    int i;
     256    enum egroupfunc group;
     257    mpz_t score[NB_BENCH_OP];
     258    mpz_t globalscore, groupscore[egroup_last];
     259    gmp_randstate_t randstate;
     260  
     261    gmp_randinit_default (randstate);
     262  
     263    for (i = 0; i < NB_BENCH_OP; i++)
     264      {
     265        compute_score (score[i], i, randstate);
     266      }
     267    compute_globalscore (globalscore, NB_BENCH_OP, score);
     268    compute_groupscore (groupscore, NB_BENCH_OP, score);
     269  
     270    printf ("\n=================================================================\n\n");
     271    printf ("GMP : %s  MPFR : %s \n", gmp_version, mpfr_get_version ());
     272  #ifdef __GMP_CC
     273    printf ("GMP compiler : %s\n", __GMP_CC);
     274  #endif
     275  #ifdef __GMP_CFLAGS
     276    printf ("GMP flags    : %s\n", __GMP_CFLAGS);
     277  #endif
     278    printf ("\n\n");
     279  
     280    for (i = 0; i < NB_BENCH_OP; i++)
     281      {
     282        gmp_printf ("\tscore for %5s : %12Zd\n", arrayfunc[i].name, score[i]);
     283        if (i == NB_BENCH_OP-1 || arrayfunc[i+1].group != arrayfunc[i].group)
     284          {
     285            enum egroupfunc g = arrayfunc[i].group;
     286            gmp_printf ("group score %s : %12Zd\n\n", groupname[g], groupscore[g]);
     287          }
     288      }
     289    /* divide by 132 the global score to get about 10^3 on a
     290       Intel(R) Core(TM)2 Quad CPU    Q9550  @ 2.83GHz
     291       with GMP : 5.1.3  MPFR : 3.1.2
     292       GMP compiler: gcc -std=gnu99, GMP flags: -O2 -pedantic
     293       -fomit-frame-pointer -m64 -mtune=core2 -march=core2 */
     294    mpz_div_ui (globalscore, globalscore, 132);
     295    gmp_printf ("global score : %12Zd\n\n", globalscore);
     296  
     297    for (i = 0; i < NB_BENCH_OP; i++)
     298      {
     299        mpz_clear (score[i]);
     300      }
     301  
     302    for (group = (enum egroupfunc)0; group != egroup_last; group++)
     303      {
     304        mpz_clear (groupscore[group]);
     305      }
     306    mpz_clear (globalscore);
     307    gmp_randclear (randstate);
     308    return 0;
     309  }