From dc2d36717cccde3cdf1d66737e59e9934a221526 Mon Sep 17 00:00:00 2001 From: Stephan Bauroth Date: Mon, 9 Nov 2026 17:03:30 +0100 Subject: [PATCH 1/4] build-bench-env.sh: build a shared tcmalloc for the tcg test The bazel tcmalloc target is a static library, so bench.sh finds no shared object to preload and runs the job with an empty allocator list. Add a linkshared cc_binary for it. --- build-bench-env.sh | 9 +++++++-- patches/tcg.patch | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 2 deletions(-) create mode 100644 patches/tcg.patch diff --git a/build-bench-env.sh b/build-bench-env.sh index 99c5234..bc3f496 100755 --- a/build-bench-env.sh +++ b/build-bench-env.sh @@ -649,10 +649,15 @@ fi if test "$setup_tcg" = "1"; then checkout tcg $version_tcg https://github.com/google/tcmalloc + # tcmalloc only builds static libraries, so add a target for the shared + # library that bench.sh preloads + set +e + patch -p1 -N -r- < ../../patches/tcg.patch + set -e if command -v bazelisk > /dev/null; then - USE_BAZEL_VERSION=$version_bazel bazelisk build -c opt tcmalloc + USE_BAZEL_VERSION=$version_bazel bazelisk build -c opt tcmalloc //tcmalloc:libtcmalloc.so else - bazel build -c opt tcmalloc + bazel build -c opt tcmalloc //tcmalloc:libtcmalloc.so fi popd fi diff --git a/patches/tcg.patch b/patches/tcg.patch new file mode 100644 index 0000000..efc379e --- /dev/null +++ b/patches/tcg.patch @@ -0,0 +1,14 @@ +diff --git a/tcmalloc/BUILD b/tcmalloc/BUILD +index 47b0f065..cfb1570a 100644 +--- a/tcmalloc/BUILD ++++ b/tcmalloc/BUILD +@@ -1610,3 +1610,9 @@ cc_library( + ], + deps = ["@com_google_absl//absl/base:core_headers"], + ) ++ ++cc_binary( ++ name = "libtcmalloc.so", ++ linkshared = 1, ++ deps = [":tcmalloc"], ++) From fd896d3ab63115534e2f91afa8c7551f5b09fad2 Mon Sep 17 00:00:00 2001 From: Stephan Bauroth Date: Mon, 9 Nov 2026 17:03:30 +0100 Subject: [PATCH 2/4] platform.yml: raise vm.max_map_count for the stress tests hardened_malloc maps guard pages per allocation and sh6bench keeps tens of thousands of them alive, so it needs over 140000 mappings; at the default 65530 mprotect fails and malloc returns null although memory is free. --- .github/workflows/platform.yml | 6 ++++++ README.md | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/.github/workflows/platform.yml b/.github/workflows/platform.yml index 6f86c7e..c9ed7d0 100644 --- a/.github/workflows/platform.yml +++ b/.github/workflows/platform.yml @@ -85,6 +85,12 @@ jobs: - name: Unload host AppArmor profiles run: sudo aa-teardown || true + # Some tests (e.g. sh6bench) keep tens of thousands of allocations live at + # once and some allocators (e.g. hardened_malloc) map guard pages per + # allocation, so they hit vm.max_map_count. Increase to make them pass. + - name: Raise vm.max_map_count for the benchmarks + run: sudo sysctl -w vm.max_map_count=1048576 + - name: Build allocator and run benchmarks in Docker id: docker_build uses: docker/build-push-action@v7 diff --git a/README.md b/README.md index 82a0fa1..5459eaa 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,18 @@ sudo aa-teardown GitHub CI runners have this profile, so the CI workflow unloads the host profiles before building. +**`sh6bench` reports "Out of memory" for some allocators although the machine +has plenty of memory?** +Some allocators (hardened_malloc `hm` for example) map guard pages around their +allocations, so every live allocation costs at least one extra kernel mapping, +and `sh6bench` keeps tens of thousands of them alive at once: with 16 threads it +measures over 140000 mappings, more than the default `vm.max_map_count` of +65530. Once the limit is reached, `mprotect` fails and `malloc` returns null. +Raise the limit: +``` +sudo sysctl -w vm.max_map_count=1048576 +``` + ## Current Allocators Supported allocators are as follow, see From 2f691b1d40ee747737d266f8be745fc95daa45c6 Mon Sep 17 00:00:00 2001 From: Stephan Bauroth Date: Mon, 9 Nov 2026 17:03:30 +0100 Subject: [PATCH 3/4] build-bench-env.sh: define the sized free functions for hoard libhoard.cpp does not define them but Heap-Layers' wrapper.cpp calls them, so libhoard.so has undefined symbols and every c++ test dies at its first sized delete. Define them as weak defaults, as the mac wrapper does. --- build-bench-env.sh | 3 +++ patches/hoard.patch | 17 +++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 patches/hoard.patch diff --git a/build-bench-env.sh b/build-bench-env.sh index bc3f496..2e2baa0 100755 --- a/build-bench-env.sh +++ b/build-bench-env.sh @@ -664,6 +664,9 @@ fi if test "$setup_hd" = "1"; then checkout hd $version_hd https://github.com/emeryberger/Hoard + set +e + patch -p1 -N -r- < ../../patches/hoard.patch + set -e cd src if [ "`uname -m -s`" = "Darwin x86_64" ] ; then sed -i_orig 's/-arch arm64/ /g' GNUmakefile # fix the makefile diff --git a/patches/hoard.patch b/patches/hoard.patch new file mode 100644 index 0000000..741edc7 --- /dev/null +++ b/patches/hoard.patch @@ -0,0 +1,17 @@ +diff --git a/src/source/libhoard.cpp b/src/source/libhoard.cpp +index 0f7567a..0b36a79 100644 +--- a/src/source/libhoard.cpp ++++ b/src/source/libhoard.cpp +@@ -163,3 +163,12 @@ extern "C" { + // include gnuwrapper here to aid inlining of xxmalloc + friends + #include "wrappers/gnuwrapper.cpp" + #endif ++ ++ ++// Heap-Layers' macwrapper.cpp defines these as weak defaults; its linux ++// wrapper.cpp calls them but libhoard.cpp did not define them, so libhoard.so ++// ended up with undefined symbols. ++extern "C" { ++ __attribute__((weak)) void xxfree_sized (void * ptr, size_t) { xxfree(ptr); } ++ __attribute__((weak)) void xxfree_aligned_sized (void * ptr, size_t, size_t) { xxfree(ptr); } ++} From 9ac68c3b1179a9f1750935676b4455369f42da0a Mon Sep 17 00:00:00 2001 From: derSteFfi Date: Mon, 9 Nov 2026 22:16:44 +0100 Subject: [PATCH 4/4] specify allocations for which hm places guard pages more precisely Co-authored-by: Julien Voisin --- .github/workflows/platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/platform.yml b/.github/workflows/platform.yml index c9ed7d0..ec2b705 100644 --- a/.github/workflows/platform.yml +++ b/.github/workflows/platform.yml @@ -87,7 +87,7 @@ jobs: # Some tests (e.g. sh6bench) keep tens of thousands of allocations live at # once and some allocators (e.g. hardened_malloc) map guard pages per - # allocation, so they hit vm.max_map_count. Increase to make them pass. + # large allocation, so they hit vm.max_map_count. Increase to make them pass. - name: Raise vm.max_map_count for the benchmarks run: sudo sysctl -w vm.max_map_count=1048576