summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2017-12-06 16:34:16 +0000
committervlefevre <vlefevre@280ebfd0-de03-0410-8827-d642c229c3f4>2017-12-06 16:34:16 +0000
commitf2dfd7d60c02b7ca46a6182ab21416fa52f9bf6c (patch)
treec82e77c4d6e937feadebe11f28137e570e74412d
parent6872fdc006aaf96157958ade355eaa0c9d58080d (diff)
downloadmpfr-f2dfd7d60c02b7ca46a6182ab21416fa52f9bf6c.tar.gz
Cleanup and fixes for the mpz_t pool.
* Split src/free_cache.c to itself and a new source file src/pool.c containing pool related code. * src/mpfr-impl.h, src/pool.c: cleanup and fixes. In particular: - renamed MPFR_MY_MPZ_INIT to MPFR_POOL_NENTRIES; - no longer use GMP's symbols __gmpz_init, etc. directly; - improved the condition for mpfr_mpz_init2; - fixed the condition in mpfr_mpz_clear (we want to consider the allocated size, not the size of the current number). * src/Makefile.am: added pool.c. * src/mpfr.h: added mpfr_free_pool prototype. * doc/mpfr.texi: updated pool description in "Memory Handling"; new function mpfr_free_pool. * doc/README.dev: update due to the rename of MPFR_MY_MPZ_INIT. * NEWS: better announcement of the mpz_t pool. git-svn-id: svn://scm.gforge.inria.fr/svn/mpfr/trunk@11922 280ebfd0-de03-0410-8827-d642c229c3f4
-rw-r--r--NEWS5
-rw-r--r--doc/README.dev2
-rw-r--r--doc/mpfr.texi18
-rw-r--r--src/Makefile.am2
-rw-r--r--src/free_cache.c92
-rw-r--r--src/mpfr-impl.h23
-rw-r--r--src/mpfr.h1
-rw-r--r--src/pool.c117
8 files changed, 153 insertions, 107 deletions
diff --git a/NEWS b/NEWS
index df1b95c17..76a03b3d0 100644
--- a/NEWS
+++ b/NEWS
@@ -87,7 +87,10 @@ Changes from versions 3.1.* to version 4.0.0:
- Old, deprecated macros mpfr_add_one_ulp and mpfr_sub_one_ulp removed.
The mpfr_next* functions should be used instead.
- Internally, improved caching: a minimum of 10% increase of the precision
- is guaranteed to avoid too many recomputations; added mpz_t caching.
+ is guaranteed to avoid too many recomputations.
+- Added internal small-precision mpz_t pool, which aims to avoid the
+ overhead of memory allocation, in particular.
+ New function mpfr_free_pool.
- Added configure option --enable-assert=none to avoid checking any assertion.
- The --enable-decimal-float configure option no longer requires
--with-gmp-build, and support for decimal floats is now automatically
diff --git a/doc/README.dev b/doc/README.dev
index ca2eb266e..170307aaa 100644
--- a/doc/README.dev
+++ b/doc/README.dev
@@ -237,7 +237,7 @@ To make a release (for the MPFR team):
Check with "-UHAVE_BIG_ENDIAN -UHAVE_LITTLE_ENDIAN" to simulate
platforms where the endianness is unknown (or can't be specified
without AC_CONFIG_HEADERS).
- Check also without mpz_t caching (-DMPFR_MY_MPZ_INIT=0).
+ Check also without the mpz_t pool (-DMPFR_POOL_NENTRIES=0).
Check the generic code, e.g. with -DMPFR_GENERIC_ABI in $CFLAGS
(useful because most tests are written for low precision) and with
mpfr_cv_c_long_double_format=unknown (as a variable assignment).
diff --git a/doc/mpfr.texi b/doc/mpfr.texi
index 2eef02008..93d3c1c01 100644
--- a/doc/mpfr.texi
+++ b/doc/mpfr.texi
@@ -981,12 +981,10 @@ When more precision is needed, the value is automatically recomputed;
a minimum of 10% increase of the precision is guaranteed to avoid too
many recomputations.
-MPFR functions may also create pools for internal use to avoid the cost
-of memory allocation.
-@c FIXME: Say a bit more about the mpz_t pool. Make it configurable at
-@c run time, with a compile-time bound on the number of entries? Pools
-@c may be a bad idea if the allocator is fast and/or if there are many
-@c threads (since they are thread-local).
+MPFR functions may also create thread-local pools for internal use
+to avoid the cost of memory allocation. The pools can be freed with
+@code{mpfr_free_pool} (but with a default MPFR build, they should not
+take much memory, as the allocation size is limited).
At any time, the user can free various caches and pools with
@code{mpfr_free_cache} and @code{mpfr_free_cache2}. It is strongly advised
@@ -2398,6 +2396,12 @@ Note: @code{mpfr_free_cache2(MPFR_FREE_LOCAL_CACHE|MPFR_FREE_GLOBAL_CACHE)}
is currently equivalent to @code{mpfr_free_cache()}.
@end deftypefun
+@deftypefun void mpfr_free_pool (void)
+Free the pools used by MPFR internally.
+Note: This function is automatically called after the thread-local caches
+are freed (with @code{mpfr_free_cache} or @code{mpfr_free_cache2}).
+@end deftypefun
+
@deftypefun int mpfr_mp_memory_cleanup (void)
This function should be called before calling @code{mp_set_memory_functions}.
@xref{Memory Handling}, for more information.
@@ -3967,6 +3971,8 @@ in MPFR 4.0.
@item @code{mpfr_free_cache2} in MPFR 4.0.
+@item @code{mpfr_free_pool} in MPFR 4.0.
+
@item @code{mpfr_frexp} in MPFR 3.1.
@item @code{mpfr_gamma_inc} in MPFR 4.0.
diff --git a/src/Makefile.am b/src/Makefile.am
index 9251ee377..810f27397 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -60,7 +60,7 @@ scale2.c set_z_exp.c ai.c gammaonethird.c ieee_floats.h \
grandom.c fpif.c set_float128.c get_float128.c rndna.c nrandom.c \
random_deviate.h random_deviate.c erandom.c mpfr-mini-gmp.c \
mpfr-mini-gmp.h fmma.c log_ui.c gamma_inc.c ubf.c invert_limb.h \
-invsqrt_limb.h beta.c odd_p.c get_q.c
+invsqrt_limb.h beta.c odd_p.c get_q.c pool.c
libmpfr_la_LIBADD = @LIBOBJS@
diff --git a/src/free_cache.c b/src/free_cache.c
index ca8327d9c..dcc5b0478 100644
--- a/src/free_cache.c
+++ b/src/free_cache.c
@@ -22,80 +22,7 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
#include "mpfr-impl.h"
-#ifndef MPFR_MY_MPZ_INIT
-# define MPFR_MY_MPZ_INIT 32 /* number of entries for the mpz_t pool */
-# define MPFR_POOL_MAX_SIZE 32 /* maximal size (in limbs) of each entry */
-#endif
-
-/* If the number of entries of the mpz_t pool is not zero */
-#if MPFR_MY_MPZ_INIT
-
-/* Index in the stack table of mpz_t and stack table of mpz_t */
-static MPFR_THREAD_ATTR int n_alloc = 0;
-static MPFR_THREAD_ATTR __mpz_struct mpz_tab[MPFR_MY_MPZ_INIT];
-
-MPFR_HOT_FUNCTION_ATTR void
-mpfr_mpz_init (mpz_t z)
-{
- if (MPFR_LIKELY (n_alloc > 0))
- {
- /* Get a mpz_t from the MPFR stack of previously used mpz_t.
- It reduces memory pressure, and it allows to reuse
- a mpz_t which should be sufficiently big. */
- MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
- memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
- SIZ(z) = 0;
- }
- else
- {
- /* Call real GMP function */
- (__gmpz_init) (z);
- }
-}
-
-MPFR_HOT_FUNCTION_ATTR void
-mpfr_mpz_init2 (mpz_t z, mp_bitcnt_t n)
-{
- if (MPFR_LIKELY (n_alloc > 0))
- {
- /* Get a mpz_t from the MPFR stack of previously used mpz_t.
- It reduces memory pressure, and it allows to reuse
- a mpz_t which should be sufficiently big. */
- MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
- memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
- SIZ(z) = 0;
- }
- else
- {
- /* Call real GMP function */
- (__gmpz_init2) (z, n);
- }
-}
-
-
-MPFR_HOT_FUNCTION_ATTR void
-mpfr_mpz_clear (mpz_t z)
-{
- /* we only put objects with at most MPFR_POOL_MAX_SIZE in the mpz_t pool,
- to avoid it takes too much memory (and anyway the speedup is mainly
- for small precision) */
- if (MPFR_LIKELY (n_alloc < numberof (mpz_tab) &&
- mpz_size (z) <= MPFR_POOL_MAX_SIZE))
- {
- /* Push back the mpz_t inside the stack of the used mpz_t */
- MPFR_ASSERTD (n_alloc >= 0);
- memcpy (&mpz_tab[n_alloc++], z, sizeof (mpz_t));
- }
- else
- {
- /* Call real GMP function */
- (__gmpz_clear) (z);
- }
-}
-
-#endif
-
-/* Theses caches may be global to all threads or local to the current */
+/* Theses caches may be global to all threads or local to the current one. */
static void
mpfr_free_const_caches (void)
{
@@ -112,22 +39,15 @@ mpfr_free_const_caches (void)
mpfr_clear_cache (__gmpfr_cache_const_catalan);
}
-/* Theses caches are always local to a thread */
+/* Theses caches/pools are always local to a thread. */
static void
mpfr_free_local_cache (void)
{
- /* Before mpz caching */
+ /* Before freeing the mpz_t pool, we need to free any cache of
+ mpz_t numbers, since freeing such a cache may add entries to
+ the mpz_t pool. */
mpfr_bernoulli_freecache ();
-
-#if MPFR_MY_MPZ_INIT
- { /* Avoid mixed declarations and code (for ISO C90 support). */
- int i;
- MPFR_ASSERTD (n_alloc >= 0 && n_alloc <= numberof (mpz_tab));
- for (i = 0; i < n_alloc; i++)
- (__gmpz_clear) (&mpz_tab[i]);
- n_alloc = 0;
- }
-#endif
+ mpfr_free_pool ();
}
void
diff --git a/src/mpfr-impl.h b/src/mpfr-impl.h
index 0c55b8f72..d035c349c 100644
--- a/src/mpfr-impl.h
+++ b/src/mpfr-impl.h
@@ -2272,30 +2272,29 @@ __MPFR_DECLSPEC int mpfr_vasnprintf_aux (char**, char*, size_t, const char*,
#endif
-/******************************************************
- *************** Internal mpz caching ***************
- ******************************************************/
+/*****************************************************
+ *************** Internal mpz_t pool ***************
+ *****************************************************/
-/* don't use mpz caching with mini-gmp */
+/* don't use the mpz_t pool with mini-gmp */
#ifdef MPFR_USE_MINI_GMP
-#define MPFR_MY_MPZ_INIT 0
+# define MPFR_POOL_NENTRIES 0
#endif
-/* define MPFR_MY_MPZ_INIT to 0 here to disable the mpz_t pool
- (see src/free_cache.c) */
-/* #define MPFR_MY_MPZ_INIT 0 */
+#ifndef MPFR_POOL_NENTRIES
+# define MPFR_POOL_NENTRIES 32 /* default number of entries of the pool */
+#endif
-/* Cache for mpz_t */
-#if !defined(MPFR_MY_MPZ_INIT) || MPFR_MY_MPZ_INIT != 0
+#if MPFR_POOL_NENTRIES && !defined(MPFR_POOL_DONT_REDEFINE)
# undef mpz_init
# undef mpz_init2
# undef mpz_clear
+# undef mpz_init_set_ui
+# undef mpz_init_set
# define mpz_init mpfr_mpz_init
# define mpz_init2 mpfr_mpz_init2
# define mpz_clear mpfr_mpz_clear
-# undef mpz_init_set_ui
# define mpz_init_set_ui(a,b) do { mpz_init (a); mpz_set_ui (a, b); } while (0)
-# undef mpz_init_set
# define mpz_init_set(a,b) do { mpz_init (a); mpz_set (a, b); } while (0)
#endif
diff --git a/src/mpfr.h b/src/mpfr.h
index cf472766b..e731e00d0 100644
--- a/src/mpfr.h
+++ b/src/mpfr.h
@@ -737,6 +737,7 @@ __MPFR_DECLSPEC int mpfr_sum (mpfr_ptr, const mpfr_ptr *, unsigned long,
__MPFR_DECLSPEC void mpfr_free_cache (void);
__MPFR_DECLSPEC void mpfr_free_cache2 (mpfr_free_cache_t);
+__MPFR_DECLSPEC void mpfr_free_pool (void);
__MPFR_DECLSPEC int mpfr_mp_memory_cleanup (void);
__MPFR_DECLSPEC int mpfr_subnormalize (mpfr_ptr, int, mpfr_rnd_t);
diff --git a/src/pool.c b/src/pool.c
new file mode 100644
index 000000000..d031543ab
--- /dev/null
+++ b/src/pool.c
@@ -0,0 +1,117 @@
+/* mpfr_free_cache... - Free cache/pool memory used by MPFR.
+
+Copyright 2004-2017 Free Software Foundation, Inc.
+Contributed by the AriC and Caramba projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
+http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#define MPFR_POOL_DONT_REDEFINE
+#include "mpfr-impl.h"
+
+#ifndef MPFR_POOL_MAX_SIZE
+# define MPFR_POOL_MAX_SIZE 32 /* maximal size (in limbs) for each entry */
+#endif
+
+/* If the number of entries of the mpz_t pool is not zero */
+#if MPFR_POOL_NENTRIES
+
+/* Index in the stack table of mpz_t and stack table of mpz_t */
+static MPFR_THREAD_ATTR int n_alloc = 0;
+static MPFR_THREAD_ATTR __mpz_struct mpz_tab[MPFR_POOL_NENTRIES];
+
+MPFR_HOT_FUNCTION_ATTR void
+mpfr_mpz_init (mpz_t z)
+{
+ if (MPFR_LIKELY (n_alloc > 0))
+ {
+ /* Get a mpz_t from the MPFR stack of previously used mpz_t.
+ It reduces memory pressure, and it allows to reuse
+ a mpz_t that should be sufficiently big. */
+ MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
+ memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
+ SIZ(z) = 0;
+ }
+ else
+ {
+ /* Call the real GMP function */
+ mpz_init (z);
+ }
+}
+
+MPFR_HOT_FUNCTION_ATTR void
+mpfr_mpz_init2 (mpz_t z, mp_bitcnt_t n)
+{
+ /* The condition on n is used below as the argument n will be ignored if
+ the mpz_t is obtained from the MPFR stack of previously used mpz_t.
+ Said otherwise, it z is expected to have a large size at the end, then
+ it is better to allocate this size directly than to get a mpz_t of
+ small size, with possibly several realloc's on it. But if n satisfies
+ the condition and is larger than the stacked mpz_t, this may still
+ yield useless realloc's. This is not ideal. We might consider to use
+ mpz_init2 with the maximum size in mpfr_mpz_init to solve this issue. */
+ if (MPFR_LIKELY (n_alloc > 0 && n <= MPFR_POOL_MAX_SIZE * GMP_NUMB_BITS))
+ {
+ /* Get a mpz_t from the MPFR stack of previously used mpz_t.
+ It reduces memory pressure, and it allows to reuse
+ a mpz_t that should be sufficiently big. */
+ MPFR_ASSERTD (n_alloc <= numberof (mpz_tab));
+ memcpy (z, &mpz_tab[--n_alloc], sizeof (mpz_t));
+ SIZ(z) = 0;
+ }
+ else
+ {
+ /* Call the real GMP function */
+ mpz_init2 (z, n);
+ }
+}
+
+
+MPFR_HOT_FUNCTION_ATTR void
+mpfr_mpz_clear (mpz_t z)
+{
+ /* We only put objects with at most MPFR_POOL_MAX_SIZE in the mpz_t pool,
+ to avoid it takes too much memory (and anyway the speedup is mainly
+ for small precision). */
+ if (MPFR_LIKELY (n_alloc < numberof (mpz_tab) &&
+ ALLOC (z) <= MPFR_POOL_MAX_SIZE))
+ {
+ /* Push back the mpz_t inside the stack of the used mpz_t */
+ MPFR_ASSERTD (n_alloc >= 0);
+ memcpy (&mpz_tab[n_alloc++], z, sizeof (mpz_t));
+ }
+ else
+ {
+ /* Call the real GMP function */
+ mpz_clear (z);
+ }
+}
+
+#endif
+
+void
+mpfr_free_pool (void)
+{
+#if MPFR_POOL_NENTRIES
+ int i;
+
+ MPFR_ASSERTD (n_alloc >= 0 && n_alloc <= numberof (mpz_tab));
+ for (i = 0; i < n_alloc; i++)
+ mpz_clear (&mpz_tab[i]);
+ n_alloc = 0;
+#endif
+}