diff mbox

RFC: Allow emergency EH pool size to be controlled (for stage 1)

Message ID 20161213135000.GP6326@redhat.com
State New
Headers show

Commit Message

Jonathan Wakely Dec. 13, 2016, 1:50 p.m. UTC
This patch allows the size of the emergency buffer for exception
handling to be controlled by a build-time macro (to avoid dynamic
allocation) or by a run-time environment variable (to allocate a
larger or smaller buffer).

This will have to wait for the next stage 1 now, as it's too late for
GCC 7, but this shows what I'm thinking about and so might avoid
anybody else reinventing the wheel.

The patch doesn't include documentation updates for the manual, which
would be needed to explain the use of the macro and the env var. We
could also add a --with-libstdcxx-static-eh-pool=N configure flag to
make it easier to set the macro.

Comments

Richard Biener Dec. 13, 2016, 2:42 p.m. UTC | #1
On Tue, Dec 13, 2016 at 2:50 PM, Jonathan Wakely <jwakely@redhat.com> wrote:
> This patch allows the size of the emergency buffer for exception

> handling to be controlled by a build-time macro (to avoid dynamic

> allocation) or by a run-time environment variable (to allocate a

> larger or smaller buffer).

>

> This will have to wait for the next stage 1 now, as it's too late for

> GCC 7, but this shows what I'm thinking about and so might avoid

> anybody else reinventing the wheel.

>

> The patch doesn't include documentation updates for the manual, which

> would be needed to explain the use of the macro and the env var. We

> could also add a --with-libstdcxx-static-eh-pool=N configure flag to

> make it easier to set the macro.


Looks reasonable.  But I wonder whether we'd want the default
arena size to be configurable as well, thus split static-eh-pool=N
into default-eh-pool-size=N and -static-eh-pool (without =N).

Also maybe N should be the number of exception objects rather
than bytes?  Otherwise a target independent N is hard to specify
for say, a distribution that wants either a different default or a
static buffer.

Richard.

>
Ville Voutilainen Dec. 13, 2016, 2:45 p.m. UTC | #2
On 13 December 2016 at 16:42, Richard Biener <richard.guenther@gmail.com> wrote:
> Also maybe N should be the number of exception objects rather

> than bytes?  Otherwise a target independent N is hard to specify

> for say, a distribution that wants either a different default or a

> static buffer.



But how to specify the number of exception objects that may have
different sizes?
Richard Biener Dec. 13, 2016, 2:52 p.m. UTC | #3
On Tue, Dec 13, 2016 at 3:45 PM, Ville Voutilainen
<ville.voutilainen@gmail.com> wrote:
> On 13 December 2016 at 16:42, Richard Biener <richard.guenther@gmail.com> wrote:

>> Also maybe N should be the number of exception objects rather

>> than bytes?  Otherwise a target independent N is hard to specify

>> for say, a distribution that wants either a different default or a

>> static buffer.

>

>

> But how to specify the number of exception objects that may have

> different sizes?


We have EMERGENCY_OBJ_SIZE for this (yeah, some guesstimate)
which can be easily target configured in libstdc++ itself.  We possibly
should split it into a sizeof () of the exception header plus some
payload guesstimate.

Richard.
Ville Voutilainen Dec. 13, 2016, 2:58 p.m. UTC | #4
On 13 December 2016 at 16:52, Richard Biener <richard.guenther@gmail.com> wrote:
> On Tue, Dec 13, 2016 at 3:45 PM, Ville Voutilainen

> <ville.voutilainen@gmail.com> wrote:

>> On 13 December 2016 at 16:42, Richard Biener <richard.guenther@gmail.com> wrote:

>>> Also maybe N should be the number of exception objects rather

>>> than bytes?  Otherwise a target independent N is hard to specify

>>> for say, a distribution that wants either a different default or a

>>> static buffer.

>>

>>

>> But how to specify the number of exception objects that may have

>> different sizes?

>

> We have EMERGENCY_OBJ_SIZE for this (yeah, some guesstimate)

> which can be easily target configured in libstdc++ itself.  We possibly

> should split it into a sizeof () of the exception header plus some

> payload guesstimate.



Ah, yes, that's what the patch does with the default-size when there
is nothing in the environment to customize
the value. Makes sense.

I don't know whether a separate byte-wise count would be useful, I
must admit I have no field experience with such
tunings.
diff mbox

Patch

commit 4e021613dcda14dfec5c88286f8faf3001afcd17
Author: Jonathan Wakely <jwakely@redhat.com>
Date:   Tue Dec 13 13:23:48 2016 +0000

    Allow pool size to be set by macro or env var

diff --git a/libstdc++-v3/configure.ac b/libstdc++-v3/configure.ac
index 7d0fafa..be4679e 100644
--- a/libstdc++-v3/configure.ac
+++ b/libstdc++-v3/configure.ac
@@ -257,6 +257,7 @@  if $GLIBCXX_IS_NATIVE; then
 
   AC_CHECK_FUNCS(__cxa_thread_atexit_impl)
   AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
+  AC_CHECK_FUNCS(secure_getenv)
 
   # For iconv support.
   AM_ICONV
diff --git a/libstdc++-v3/crossconfig.m4 b/libstdc++-v3/crossconfig.m4
index 8cc788c..c01213a 100644
--- a/libstdc++-v3/crossconfig.m4
+++ b/libstdc++-v3/crossconfig.m4
@@ -184,6 +184,7 @@  case "${host}" in
     GCC_CHECK_TLS
     AC_CHECK_FUNCS(__cxa_thread_atexit_impl)
     AC_CHECK_FUNCS(aligned_alloc posix_memalign memalign _aligned_malloc)
+    AC_CHECK_FUNCS(secure_getenv)
     AM_ICONV
     ;;
   *-mingw32*)
diff --git a/libstdc++-v3/libsupc++/eh_alloc.cc b/libstdc++-v3/libsupc++/eh_alloc.cc
index d362e40..571fe6b 100644
--- a/libstdc++-v3/libsupc++/eh_alloc.cc
+++ b/libstdc++-v3/libsupc++/eh_alloc.cc
@@ -29,6 +29,7 @@ 
 #include <cstdlib>
 #if _GLIBCXX_HOSTED
 #include <cstring>
+#include <cerrno>
 #endif
 #include <climits>
 #include <exception>
@@ -36,6 +37,14 @@ 
 #include <ext/concurrence.h>
 #include <new>
 
+#ifdef STATIC_EH_ALLOC_POOL_BYTES
+char* alloc_pool_arena(std::size_t& size)
+{
+  size = STATIC_EH_ALLOC_POOL_BYTES;
+  static alignas(void*) char arena[STATIC_EH_ALLOC_POOL_BYTES];
+  return arena;
+}
+#else
 #if _GLIBCXX_HOSTED
 using std::free;
 using std::malloc;
@@ -50,8 +59,6 @@  extern "C" void *memset (void *, int, std::size_t);
 
 using namespace __cxxabiv1;
 
-// ??? How to control these parameters.
-
 // Guess from the size of basic types how large a buffer is reasonable.
 // Note that the basic c++ exception header has 13 pointers and 2 ints,
 // so on a system with PSImode pointers we're talking about 56 bytes
@@ -73,6 +80,32 @@  using namespace __cxxabiv1;
 # define EMERGENCY_OBJ_COUNT	4
 #endif
 
+char *alloc_pool_arena(std::size_t& size)
+{
+  size = 0;
+#if _GLIBCXX_HOSTED
+  const char *name = "GLIBCXX_EH_ARENA_SIZE";
+  char *env = nullptr;
+# ifdef _GLIBCXX_HAVE_SECURE_GETENV
+  env = ::secure_getenv (name);
+# else
+  env = std::getenv (name);
+# endif
+  if (env)
+    {
+      char *end;
+      size = strtoul(env, &end, 0);
+      if (*end || (size == ULONG_MAX && errno == ERANGE))
+	size = 0;
+    }
+#endif // _GLIBCXX_HOSTED
+  if (size == 0)
+    size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT
+	    + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception));
+  return (char *)malloc (size);
+}
+#endif // STATIC_EH_ALLOC_POOL_BYTES
+
 namespace __gnu_cxx
 {
   void __freeres();
@@ -107,7 +140,7 @@  namespace
       // The free-list
       free_entry *first_free_entry;
       // The arena itself - we need to keep track of these only
-      // to implement in_pool.
+      // to implement in_pool and __freeres.
       char *arena;
       std::size_t arena_size;
 
@@ -116,11 +149,8 @@  namespace
 
   pool::pool()
     {
-      // Allocate the arena - we could add a GLIBCXX_EH_ARENA_SIZE environment
-      // to make this tunable.
-      arena_size = (EMERGENCY_OBJ_SIZE * EMERGENCY_OBJ_COUNT
-		    + EMERGENCY_OBJ_COUNT * sizeof (__cxa_dependent_exception));
-      arena = (char *)malloc (arena_size);
+      // Allocate the arena.
+      arena = alloc_pool_arena (arena_size);
       if (!arena)
 	{
 	  // If the allocation failed go without an emergency pool.
@@ -255,11 +285,13 @@  namespace __gnu_cxx
   void
   __freeres()
   {
+#ifndef STATIC_EH_ALLOC_POOL_BYTES
     if (emergency_pool.arena)
       {
 	::free(emergency_pool.arena);
 	emergency_pool.arena = 0;
       }
+#endif
   }
 }