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