"Tunables are a feature in the GNU C Library that allows application authors and distribution maintainers to alter the runtime library behavior to match their workload." https://www.gnu.org/software/libc/manual/html_node/Tunables.html We should support them in libstdc++ too. The resource types in <memory_resource> are obvious candidates, but there might be others too (default std::async launch policy?). Possible tunables: For monotonic_buffer_resource: the initial buffer size and growth factor. For the pool resources: the supported pool sizes, if/when empty chunks are released to the upstream resource, the default max_blocks_per_chunk and default largest_required_pool_block, initial number of blocks per chunk (in _M_alloc_pools). For the pool resources it would also be possible to tune some of those numbers per-resource by inventing an __extended_pool_options type that goes beyond the two params that std::pmr::pool_options controls.
I forgot to list the growth factor for pool resource too (currently hardcoded to 2 in __pool_resource::_Pool::replenish())
The emergency EH pool size should be tunable too. From libsupc++/eh_alloc.cc: // 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);
Another useful tunable would be to alter the meaning of the "default" token for the std::random_device constructor: if (token == "default") { default_token = true; fname = "/dev/urandom"; #if defined _GLIBCXX_USE_CRT_RAND_S which = rand_s; #elif defined USE_RDSEED which = rdseed; #elif defined USE_RDRAND which = rdrand; #elif defined _GLIBCXX_USE_DEV_RANDOM which = device_file; #else # error "either define USE_MT19937 above or set the default device here" #endif } In a build of libstdc++ that defaults to rdrand it would be useful to be able to force "default" to mean /dev/urandom or /dev/random at runtime, to workaround RDRAND bugs in AMD processors.
The master branch has been updated by Jonathan Wakely <redi@gcc.gnu.org>: https://gcc.gnu.org/g:637e3668fdc17c4e226538fb14f9fab225433d01 commit r13-3234-g637e3668fdc17c4e226538fb14f9fab225433d01 Author: Jonathan Wakely <jwakely@redhat.com> Date: Wed Oct 5 21:21:54 2022 +0100 libstdc++: Allow emergency EH alloc pool size to be tuned [PR68606] Implement a long-standing request to support tuning the size of the emergency buffer for allocating exceptions after malloc fails, or to disable that buffer entirely. It's now possible to disable the dynamic allocation of the buffer and use a fixed-size static buffer, via --enable-libstdcxx-static-eh-pool. This is a built-time choice that is baked into libstdc++ and so affects all code linked against that build of libstdc++. The size of the pool can be set by --with-libstdcxx-eh-pool-obj-count=N which is measured in units of sizeof(void*) not bytes. A given exception type such as std::system_error depends on the target, so giving a size in bytes wouldn't be portable across 16/32/64-bit targets. When libstdc++ is configured to use a dynamic buffer, the size of that buffer can now be tuned at runtime by setting the GLIBCXX_TUNABLES environment variable (c.f. PR libstdc++/88264). The number of exceptions to reserve space for is controlled by the "glibcxx.eh_pool.obj_count" and "glibcxx.eh_pool.obj_size" tunables. The pool will be sized to be able to allocate obj_count exceptions of size obj_size*sizeof(void*) and obj_count "dependent" exceptions rethrown by std::rethrow_exception. With the ability to tune the buffer size, we can reduce the default pool size on 32-bit and 16-bit targets. Most users never need to throw 1kB exceptions in parallel from hundreds of threads after malloc is OOM. The users who do need that can use the tunables to select larger sizes. The old defaults can be chosen at runtime by setting GLIBCXX_TUNABLES to: 64-bit: glibcxx.eh_pool.obj_count=64:glibcxx.eh_pool.obj_size=112 32-bit: glibcxx.eh_pool.obj_count=32:glibcxx.eh_pool.obj_size=104 Or approximated by configuring with: 64-bit: --with-libstdcxx-eh-pool-obj-count=252 32-bit: --with-libstdcxx-eh-pool-obj-count=94 libstdc++-v3/ChangeLog: PR libstdc++/68606 * Makefile.in: Regenerate. * acinclude.m4 (GLIBCXX_EMERGENCY_EH_ALLOC): New macro. * configure: Regenerate. * configure.ac: Use GLIBCXX_EMERGENCY_EH_ALLOC. * crossconfig.m4: Check for secure_getenv. * doc/Makefile.in: Regenerate. * doc/xml/manual/configure.xml: Document new configure options. * doc/xml/manual/evolution.xml: Document addition of tunables. * doc/xml/manual/using_exceptions.xml: Document emergency buffer and tunables. * doc/html/*: Regenerate. * include/Makefile.in: Regenerate. * libsupc++/Makefile.am: Use EH_POOL_FLAGS. * libsupc++/Makefile.in: Regenerate. * libsupc++/eh_alloc.cc (EMERGENCY_OBJ_SIZE): Define in units of sizeof(void*) not including the ABI's exception header. (EMERGENCY_OBJ_COUNT): Define as target-independent calculation based on word size. (MAX_OBJ_COUNT): Define macro for upper limit on pool size. (pool) [_GLIBCXX_EH_POOL_STATIC]: Use fixed-size buffer. (pool::buffer_size_in_bytes): New static member function. (pool::pool): Parse GLIBCXX_TUNABLES environment variable to set pool size at runtime. (pool::in_pool): Use std::less<void*> for total order. (__freeres) [_GLIBCXX_EH_POOL_STATIC]: Do nothing. (__cxa_free_exception, __cxa_free_dependent_exception): Add [[unlikely]] attributes. * po/Makefile.in: Regenerate. * python/Makefile.in: Regenerate. * src/Makefile.in: Regenerate. * src/c++11/Makefile.in: Regenerate. * src/c++17/Makefile.in: Regenerate. * src/c++20/Makefile.in: Regenerate. * src/c++98/Makefile.in: Regenerate. * src/filesystem/Makefile.in: Regenerate. * src/libbacktrace/Makefile.in: Regenerate. * testsuite/Makefile.in: Regenerate.
(In reply to Jonathan Wakely from comment #2) > The emergency EH pool size should be tunable too. > > From libsupc++/eh_alloc.cc: > > // 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); Done for PR 68606.
This can't be done safely in libstdc++ because we can't call getenv safely. We could be dlopened while another thread is calling setenv. But if that could be solved, other useful tunables would be the filenames to use for chrono::tzdb (for tzdata.zi and leapseconds), and formatting options for the default contract violation handler (e.g. human readable vs log-friendly).
Another tunable idea: disable exceptions from the runtime. We use _GLIBCXX_THROW_OR_ABORT so that throwing an exception will abort instead when -fno-exceptions is defined. However, this only works when the code doing the throw is compiled with that flag. For all the __throw_foo_error functions declared in <bits/functexcept.h> the actual definition is src/c++11/functexcept.cc which isn't affected by any -fno-exceptions that users compile with. You need to recompile libstdc++ itself with -fno-exceptions. We could add a tunable to disable all exceptions within the runtime. (If doing this, don't forget places like throw_revursive_init_exception in libsupc++/guard.cc which doesn't use _GLIBCXX_THROW_OR_ABORT because it wants to trap not std::abort(), presumably for freestanding reasons.)