Home | History | Annotate | Line # | Download | only in src
      1 /* mpz_t pool
      2 
      3 Copyright 2014-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 #define MPFR_POOL_DONT_REDEFINE
     24 #include "mpfr-impl.h"
     25 
     26 #ifndef MPFR_POOL_MAX_SIZE
     27 # define MPFR_POOL_MAX_SIZE 32 /* maximal size (in limbs) for each entry */
     28 #endif
     29 
     30 /* If the number of entries of the mpz_t pool is not zero */
     31 #if MPFR_POOL_NENTRIES
     32 
     33 /* Index in the stack table of mpz_t and stack table of mpz_t */
     34 static MPFR_THREAD_ATTR int n_alloc = 0;
     35 static MPFR_THREAD_ATTR __mpz_struct mpz_tab[MPFR_POOL_NENTRIES];
     36 
     37 MPFR_HOT_FUNCTION_ATTR void
     38 mpfr_mpz_init (mpz_ptr z)
     39 {
     40   if (MPFR_LIKELY (n_alloc > 0))
     41     {
     42       /* Get a mpz_t from the MPFR stack of previously used mpz_t.
     43          It reduces memory pressure, and it allows to reuse
     44          a mpz_t that should be sufficiently big. */
     45       MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
     46       memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
     47       SIZ(z) = 0;
     48     }
     49   else
     50     {
     51       /* Call the real GMP function */
     52       mpz_init (z);
     53     }
     54 }
     55 
     56 MPFR_HOT_FUNCTION_ATTR void
     57 mpfr_mpz_init2 (mpz_ptr z, mp_bitcnt_t n)
     58 {
     59   /* The condition on n is used below as the argument n will be ignored if
     60      the mpz_t is obtained from the MPFR stack of previously used mpz_t.
     61      Said otherwise, it z is expected to have a large size at the end, then
     62      it is better to allocate this size directly than to get a mpz_t of
     63      small size, with possibly several realloc's on it. But if n satisfies
     64      the condition and is larger than the stacked mpz_t, this may still
     65      yield useless realloc's. This is not ideal. We might consider to use
     66      mpz_init2 with the maximum size in mpfr_mpz_init to solve this issue. */
     67   if (MPFR_LIKELY (n_alloc > 0 && n <= MPFR_POOL_MAX_SIZE * GMP_NUMB_BITS))
     68     {
     69       /* Get a mpz_t from the MPFR stack of previously used mpz_t.
     70          It reduces memory pressure, and it allows to reuse
     71          a mpz_t that should be sufficiently big. */
     72       MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
     73       memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
     74       SIZ(z) = 0;
     75     }
     76   else
     77     {
     78       /* Call the real GMP function */
     79       mpz_init2 (z, n);
     80     }
     81 }
     82 
     83 
     84 MPFR_HOT_FUNCTION_ATTR void
     85 mpfr_mpz_clear (mpz_ptr z)
     86 {
     87   /* We only put objects with at most MPFR_POOL_MAX_SIZE in the mpz_t pool,
     88      to avoid it takes too much memory (and anyway the speedup is mainly
     89      for small precision). */
     90   if (MPFR_LIKELY (n_alloc < numberof (mpz_tab) &&
     91                    ALLOC (z) <= MPFR_POOL_MAX_SIZE))
     92     {
     93       /* Push back the mpz_t inside the stack of the used mpz_t */
     94       MPFR_ASSERTD (n_alloc >= 0);
     95       memcpy (&mpz_tab[n_alloc++], z, sizeof (mpz_t));
     96     }
     97   else
     98     {
     99       /* Call the real GMP function */
    100       mpz_clear (z);
    101     }
    102 }
    103 
    104 #endif
    105 
    106 void
    107 mpfr_free_pool (void)
    108 {
    109 #if MPFR_POOL_NENTRIES
    110   int i;
    111 
    112   MPFR_ASSERTD (n_alloc >= 0 && n_alloc <= numberof (mpz_tab));
    113   for (i = 0; i < n_alloc; i++)
    114     mpz_clear (&mpz_tab[i]);
    115   n_alloc = 0;
    116 #endif
    117 }
    118