From d9431fed41b9d627178add414fbe364cdc27a4eb Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Wed, 25 Mar 2026 23:13:50 +0000 Subject: [PATCH 01/14] Adds comptime option to link jemalloc instead of tcmalloc Signed-off-by: Takeshi Yoneda --- bazel/BUILD | 10 ++++++ bazel/deps.yaml | 12 +++++++ bazel/envoy_internal.bzl | 2 ++ bazel/envoy_library.bzl | 1 + bazel/foreign_cc/BUILD | 14 ++++++++ bazel/repositories.bzl | 7 ++++ bazel/repository_locations.bzl | 6 ++++ source/common/memory/stats.cc | 59 ++++++++++++++++++++++++++++++++++ source/common/memory/utils.cc | 12 ++++++- 9 files changed, 122 insertions(+), 1 deletion(-) diff --git a/bazel/BUILD b/bazel/BUILD index 05ea3ea3ccfae..69ca106bca9e3 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -227,6 +227,16 @@ config_setting( values = {"define": "tcmalloc=gperftools"}, ) +bool_flag( + name = "jemalloc", + build_setting_default = False, +) + +config_setting( + name = "jemalloc_enabled", + flag_values = {":jemalloc": "True"}, +) + config_setting( name = "disable_signal_trace", values = {"define": "signal_trace=disabled"}, diff --git a/bazel/deps.yaml b/bazel/deps.yaml index 60e15c4832e60..e29be8bce92f1 100644 --- a/bazel/deps.yaml +++ b/bazel/deps.yaml @@ -910,6 +910,18 @@ gperftools: license: "BSD-3-Clause" license_url: "https://github.com/gperftools/gperftools/blob/gperftools-{version}/COPYING" +jemalloc: + project_name: "jemalloc" + project_desc: "General-purpose scalable concurrent memory allocator" + project_url: "https://github.com/jemalloc/jemalloc" + release_date: "2022-11-06" + use_category: + - dataplane_core + - controlplane + cpe: "N/A" + license: "BSD-2-Clause" + license_url: "https://github.com/jemalloc/jemalloc/blob/{version}/COPYING" + grpc_httpjson_transcoding: project_name: "grpc-httpjson-transcoding" project_desc: "Library that supports transcoding so that HTTP/JSON can be converted to gRPC" diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 8282fb3e4f56f..3de0fc66e0eb2 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -92,6 +92,7 @@ def envoy_copts(repository, test = False): _repo("//bazel:disable_tcmalloc"): ["-DABSL_MALLOC_HOOK_MMAP_DISABLE"], _repo("//bazel:debug_tcmalloc"): ["-DENVOY_MEMORY_DEBUG_ENABLED=1", "-DGPERFTOOLS_TCMALLOC"], _repo("//bazel:gperftools_tcmalloc"): ["-DGPERFTOOLS_TCMALLOC"], + _repo("//bazel:jemalloc_enabled"): ["-DJEMALLOC"], ( "@platforms//cpu:x86_64", "@platforms//cpu:aarch64", @@ -197,6 +198,7 @@ def tcmalloc_external_dep(repository): _repo("//bazel:debug_tcmalloc"), _repo("//bazel:gperftools_tcmalloc"), ): _repo("//bazel/external:gperftools"), + (_repo("//bazel:jemalloc_enabled"),): _repo("//bazel/foreign_cc:jemalloc"), "//conditions:default": _repo("//bazel:tcmalloc_lib"), }) diff --git a/bazel/envoy_library.bzl b/bazel/envoy_library.bzl index 59f59e49e1d4c..1ad14043622b7 100644 --- a/bazel/envoy_library.bzl +++ b/bazel/envoy_library.bzl @@ -30,6 +30,7 @@ def tcmalloc_external_deps(repository): _repo("//bazel:debug_tcmalloc"), _repo("//bazel:gperftools_tcmalloc"), ): [_repo("//bazel/external:gperftools")], + (_repo("//bazel:jemalloc_enabled"),): [_repo("//bazel/foreign_cc:jemalloc")], "//conditions:default": [_repo("//bazel:tcmalloc_all_libs")], }) diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index 7cd494b368ad5..bba09b65c3492 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -446,6 +446,20 @@ envoy_cc_library( }), ) +configure_make( + name = "jemalloc", + configure_options = [ + "--with-jemalloc-prefix=", + "--disable-shared", + "--enable-static", + "--disable-doc", + ], + lib_source = "@jemalloc//:all", + out_static_libs = ["libjemalloc.a"], + tags = ["skip_on_windows"], + visibility = ["//visibility:public"], +) + cc_library( name = "libcxx_msan_wrapper", visibility = ["//visibility:public"], diff --git a/bazel/repositories.bzl b/bazel/repositories.bzl index 267761ef27c28..46897855db0e8 100644 --- a/bazel/repositories.bzl +++ b/bazel/repositories.bzl @@ -182,6 +182,7 @@ def envoy_dependencies(skip_targets = []): _libsxg() _tcmalloc() _gperftools() + _jemalloc() _com_github_grpc_grpc() _rules_proto_grpc() _icu() @@ -904,6 +905,12 @@ def _gperftools(): name = "gperftools", ) +def _jemalloc(): + external_http_archive( + name = "jemalloc", + build_file_content = BUILD_ALL_CONTENT, + ) + def _wamr(): external_http_archive( name = "wamr", diff --git a/bazel/repository_locations.bzl b/bazel/repository_locations.bzl index 70edb8a8077a7..3406f8380c3f8 100644 --- a/bazel/repository_locations.bzl +++ b/bazel/repository_locations.bzl @@ -176,6 +176,12 @@ REPOSITORY_LOCATIONS_SPEC = dict( strip_prefix = "gperftools-{version}", urls = ["https://github.com/gperftools/gperftools/releases/download/gperftools-{version}/gperftools-{version}.tar.gz"], ), + jemalloc = dict( + version = "5.3.0", + sha256 = "2db82d1e7119df3e71b7640219b6dfe84789bc0537983c3b7ac4f7189aecfeaa", + strip_prefix = "jemalloc-{version}", + urls = ["https://github.com/jemalloc/jemalloc/releases/download/{version}/jemalloc-{version}.tar.bz2"], + ), com_github_grpc_grpc = dict( version = "1.76.0", sha256 = "0af37b800953130b47c075b56683ee60bdc3eda3c37fc6004193f5b569758204", diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index 31a8ea673765e..ee3f797378755 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -10,6 +10,8 @@ #include "tcmalloc/malloc_extension.h" #elif defined(GPERFTOOLS_TCMALLOC) #include "gperftools/malloc_extension.h" +#elif defined(JEMALLOC) +#include #endif namespace Envoy { @@ -27,6 +29,17 @@ void setMaxUnfreedMemoryBytes(uint64_t value) { max_unfreed_memory_bytes.store(value, std::memory_order_relaxed); } +#if defined(JEMALLOC) +namespace { +// Refresh jemalloc's epoch so that subsequently-read stats reflect current state. +void refreshJemallocEpoch() { + uint64_t epoch = 1; + size_t sz = sizeof(epoch); + mallctl("epoch", &epoch, &sz, &epoch, sz); +} +} // namespace +#endif + uint64_t Stats::totalCurrentlyAllocated() { #if defined(TCMALLOC) return tcmalloc::MallocExtension::GetNumericProperty("generic.current_allocated_bytes") @@ -35,6 +48,12 @@ uint64_t Stats::totalCurrentlyAllocated() { size_t value = 0; MallocExtension::instance()->GetNumericProperty("generic.current_allocated_bytes", &value); return value; +#elif defined(JEMALLOC) + refreshJemallocEpoch(); + size_t allocated = 0; + size_t sz = sizeof(allocated); + mallctl("stats.allocated", &allocated, &sz, nullptr, 0); + return allocated; #else return 0; #endif @@ -51,6 +70,11 @@ uint64_t Stats::totalCurrentlyReserved() { size_t value = 0; MallocExtension::instance()->GetNumericProperty("generic.heap_size", &value); return value; +#elif defined(JEMALLOC) + size_t resident = 0; + size_t sz = sizeof(resident); + mallctl("stats.resident", &resident, &sz, nullptr, 0); + return resident; #else return 0; #endif @@ -65,6 +89,9 @@ uint64_t Stats::totalThreadCacheBytes() { MallocExtension::instance()->GetNumericProperty("tcmalloc.current_total_thread_cache_bytes", &value); return value; +#elif defined(JEMALLOC) + // jemalloc uses per-arena caches rather than per-thread caches; no direct equivalent. + return 0; #else return 0; #endif @@ -77,6 +104,12 @@ uint64_t Stats::totalPageHeapFree() { size_t value = 0; MallocExtension::instance()->GetNumericProperty("tcmalloc.pageheap_free_bytes", &value); return value; +#elif defined(JEMALLOC) + size_t active = 0, allocated = 0; + size_t sz = sizeof(size_t); + mallctl("stats.active", &active, &sz, nullptr, 0); + mallctl("stats.allocated", &allocated, &sz, nullptr, 0); + return active > allocated ? active - allocated : 0; #else return 0; #endif @@ -90,6 +123,11 @@ uint64_t Stats::totalPageHeapUnmapped() { size_t value = 0; MallocExtension::instance()->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", &value); return value; +#elif defined(JEMALLOC) + size_t retained = 0; + size_t sz = sizeof(retained); + mallctl("stats.retained", &retained, &sz, nullptr, 0); + return retained; #else return 0; #endif @@ -102,6 +140,11 @@ uint64_t Stats::totalPhysicalBytes() { size_t value = 0; MallocExtension::instance()->GetNumericProperty("generic.total_physical_bytes", &value); return value; +#elif defined(JEMALLOC) + size_t resident = 0; + size_t sz = sizeof(resident); + mallctl("stats.resident", &resident, &sz, nullptr, 0); + return resident; #else return 0; #endif @@ -115,6 +158,14 @@ void Stats::dumpStatsToLog() { auto buffer = std::make_unique(buffer_size); MallocExtension::instance()->GetStats(buffer.get(), buffer_size); ENVOY_LOG_MISC(debug, "TCMalloc stats:\n{}", buffer.get()); +#elif defined(JEMALLOC) + std::string output; + malloc_stats_print( + [](void* opaque, const char* msg) { + reinterpret_cast(opaque)->append(msg); + }, + &output, nullptr); + ENVOY_LOG_MISC(debug, "jemalloc stats:\n{}", output); #else return; #endif @@ -129,6 +180,14 @@ absl::optional Stats::dumpStats() { MallocExtension::instance()->GetStats(buffer.data(), buffer_size); buffer.resize(strlen(buffer.c_str())); return buffer; +#elif defined(JEMALLOC) + std::string output; + malloc_stats_print( + [](void* opaque, const char* msg) { + reinterpret_cast(opaque)->append(msg); + }, + &output, nullptr); + return output; #else return absl::nullopt; #endif diff --git a/source/common/memory/utils.cc b/source/common/memory/utils.cc index ebab8936af4e9..670b6a09e52fe 100644 --- a/source/common/memory/utils.cc +++ b/source/common/memory/utils.cc @@ -7,6 +7,9 @@ #include "tcmalloc/malloc_extension.h" #elif defined(GPERFTOOLS_TCMALLOC) #include "gperftools/malloc_extension.h" +#elif defined(JEMALLOC) +#include +#include #endif namespace Envoy { @@ -19,6 +22,13 @@ void Utils::releaseFreeMemory(uint64_t max_unfreed_bytes) { #elif defined(GPERFTOOLS_TCMALLOC) UNREFERENCED_PARAMETER(max_unfreed_bytes); MallocExtension::instance()->ReleaseFreeMemory(); +#elif defined(JEMALLOC) + UNREFERENCED_PARAMETER(max_unfreed_bytes); + // Purge all arenas to release dirty pages back to the OS. + // MALLCTL_ARENAS_ALL is jemalloc's pseudo-index for addressing all arenas at once. + char purge_cmd[32]; + snprintf(purge_cmd, sizeof(purge_cmd), "arena.%u.purge", MALLCTL_ARENAS_ALL); + mallctl(purge_cmd, nullptr, nullptr, nullptr, 0); #else UNREFERENCED_PARAMETER(max_unfreed_bytes); #endif @@ -31,7 +41,7 @@ void Utils::releaseFreeMemory(uint64_t max_unfreed_bytes) { Ref: https://github.com/envoyproxy/envoy/pull/9471#discussion_r363825985 */ void Utils::tryShrinkHeap() { -#if defined(TCMALLOC) || defined(GPERFTOOLS_TCMALLOC) +#if defined(TCMALLOC) || defined(GPERFTOOLS_TCMALLOC) || defined(JEMALLOC) auto total_physical_bytes = Stats::totalPhysicalBytes(); auto allocated_size_by_app = Stats::totalCurrentlyAllocated(); const uint64_t threshold = maxUnfreedMemoryBytes(); From d51084e03bb410d9add7c1d94b452e0a8bf74609 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Wed, 25 Mar 2026 23:14:47 +0000 Subject: [PATCH 02/14] more Signed-off-by: Takeshi Yoneda --- ci/do_ci.sh | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index 4c5ffa6badc79..da34f6531db6b 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -413,6 +413,19 @@ case $CI_TARGET in -c fastbuild \ "${TEST_TARGETS[@]}" fi + if [[ -z "$ENVOY_SKIP_CTO_JEMALLOC" ]]; then + echo "Building and testing with jemalloc: ${TEST_TARGETS[*]}" + bazel_with_collection \ + test "${BAZEL_BUILD_OPTIONS[@]}" \ + --@envoy//bazel:jemalloc=True \ + -c fastbuild \ + @envoy//test/common/memory/... + echo "Building binary with jemalloc..." + bazel build "${BAZEL_BUILD_OPTIONS[@]}" \ + --@envoy//bazel:jemalloc=True \ + -c fastbuild \ + @envoy//source/exe:envoy-static + fi if [[ -z "$ENVOY_SKIP_CTO_WASMTIME" ]]; then exit 0 fi From 2c544c354c039b42b20b29bf68efe061eeb8b028 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Wed, 25 Mar 2026 23:36:15 +0000 Subject: [PATCH 03/14] Mutual exclusive Signed-off-by: Takeshi Yoneda --- bazel/BUILD | 21 +++++++++++++++++++++ bazel/envoy_internal.bzl | 4 ++-- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/bazel/BUILD b/bazel/BUILD index 69ca106bca9e3..65ba8f667be1e 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -237,6 +237,27 @@ config_setting( flag_values = {":jemalloc": "True"}, ) +config_setting( + name = "jemalloc_disabled", + flag_values = {":jemalloc": "False"}, +) + +selects.config_setting_group( + name = "tcmalloc_x86_64", + match_all = [ + ":jemalloc_disabled", + ":linux_x86_64", + ], +) + +selects.config_setting_group( + name = "tcmalloc_aarch64", + match_all = [ + ":jemalloc_disabled", + ":linux_aarch64", + ], +) + config_setting( name = "disable_signal_trace", values = {"define": "signal_trace=disabled"}, diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 3de0fc66e0eb2..515099dcef832 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -94,8 +94,8 @@ def envoy_copts(repository, test = False): _repo("//bazel:gperftools_tcmalloc"): ["-DGPERFTOOLS_TCMALLOC"], _repo("//bazel:jemalloc_enabled"): ["-DJEMALLOC"], ( - "@platforms//cpu:x86_64", - "@platforms//cpu:aarch64", + _repo("//bazel:tcmalloc_x86_64"), + _repo("//bazel:tcmalloc_aarch64"), ): ["-DTCMALLOC"], "//conditions:default": ["-DGPERFTOOLS_TCMALLOC"], }) + select({ From 12e17f56a9f24b91239dc268f789559bb3bf8ce5 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 00:20:20 +0000 Subject: [PATCH 04/14] format Signed-off-by: Takeshi Yoneda --- source/common/memory/stats.cc | 8 ++------ source/common/memory/utils.cc | 3 ++- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index ee3f797378755..91a230635a816 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -161,9 +161,7 @@ void Stats::dumpStatsToLog() { #elif defined(JEMALLOC) std::string output; malloc_stats_print( - [](void* opaque, const char* msg) { - reinterpret_cast(opaque)->append(msg); - }, + [](void* opaque, const char* msg) { reinterpret_cast(opaque)->append(msg); }, &output, nullptr); ENVOY_LOG_MISC(debug, "jemalloc stats:\n{}", output); #else @@ -183,9 +181,7 @@ absl::optional Stats::dumpStats() { #elif defined(JEMALLOC) std::string output; malloc_stats_print( - [](void* opaque, const char* msg) { - reinterpret_cast(opaque)->append(msg); - }, + [](void* opaque, const char* msg) { reinterpret_cast(opaque)->append(msg); }, &output, nullptr); return output; #else diff --git a/source/common/memory/utils.cc b/source/common/memory/utils.cc index 670b6a09e52fe..be25d382034d0 100644 --- a/source/common/memory/utils.cc +++ b/source/common/memory/utils.cc @@ -8,8 +8,9 @@ #elif defined(GPERFTOOLS_TCMALLOC) #include "gperftools/malloc_extension.h" #elif defined(JEMALLOC) -#include #include + +#include #endif namespace Envoy { From 52b50519081dea6d821d3a3cc158181ecfc23928 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 00:28:05 +0000 Subject: [PATCH 05/14] more Signed-off-by: Takeshi Yoneda --- bazel/BUILD | 21 --------------------- bazel/deps.yaml | 2 +- bazel/envoy_internal.bzl | 4 ++-- 3 files changed, 3 insertions(+), 24 deletions(-) diff --git a/bazel/BUILD b/bazel/BUILD index 65ba8f667be1e..69ca106bca9e3 100644 --- a/bazel/BUILD +++ b/bazel/BUILD @@ -237,27 +237,6 @@ config_setting( flag_values = {":jemalloc": "True"}, ) -config_setting( - name = "jemalloc_disabled", - flag_values = {":jemalloc": "False"}, -) - -selects.config_setting_group( - name = "tcmalloc_x86_64", - match_all = [ - ":jemalloc_disabled", - ":linux_x86_64", - ], -) - -selects.config_setting_group( - name = "tcmalloc_aarch64", - match_all = [ - ":jemalloc_disabled", - ":linux_aarch64", - ], -) - config_setting( name = "disable_signal_trace", values = {"define": "signal_trace=disabled"}, diff --git a/bazel/deps.yaml b/bazel/deps.yaml index e29be8bce92f1..6fe50279172df 100644 --- a/bazel/deps.yaml +++ b/bazel/deps.yaml @@ -914,7 +914,7 @@ jemalloc: project_name: "jemalloc" project_desc: "General-purpose scalable concurrent memory allocator" project_url: "https://github.com/jemalloc/jemalloc" - release_date: "2022-11-06" + release_date: "2022-05-06" use_category: - dataplane_core - controlplane diff --git a/bazel/envoy_internal.bzl b/bazel/envoy_internal.bzl index 515099dcef832..3de0fc66e0eb2 100644 --- a/bazel/envoy_internal.bzl +++ b/bazel/envoy_internal.bzl @@ -94,8 +94,8 @@ def envoy_copts(repository, test = False): _repo("//bazel:gperftools_tcmalloc"): ["-DGPERFTOOLS_TCMALLOC"], _repo("//bazel:jemalloc_enabled"): ["-DJEMALLOC"], ( - _repo("//bazel:tcmalloc_x86_64"), - _repo("//bazel:tcmalloc_aarch64"), + "@platforms//cpu:x86_64", + "@platforms//cpu:aarch64", ): ["-DTCMALLOC"], "//conditions:default": ["-DGPERFTOOLS_TCMALLOC"], }) + select({ From 8cb983c2f4a8ac7dbdb3e9c4728d3d2a9c801aed Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 04:02:00 +0000 Subject: [PATCH 06/14] more Signed-off-by: Takeshi Yoneda --- bazel/foreign_cc/BUILD | 1 + tools/spelling/spelling_dictionary.txt | 3 +++ 2 files changed, 4 insertions(+) diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index bba09b65c3492..492c7838f8c39 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -453,6 +453,7 @@ configure_make( "--disable-shared", "--enable-static", "--disable-doc", + "--disable-cxx", ], lib_source = "@jemalloc//:all", out_static_libs = ["libjemalloc.a"], diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 7a8b3bcae11c1..ae8e7060c0e5a 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -987,6 +987,7 @@ iteratively javascript jitter jittered +jemalloc joinable js kafka @@ -1043,6 +1044,8 @@ luajit lyft maglev malloc +mallctl +MALLCTL marshaller matchable matcher From f9d450c7e8d16addf760c8b57f6b691173d79aae Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 04:14:38 +0000 Subject: [PATCH 07/14] ci Signed-off-by: Takeshi Yoneda --- ci/do_ci.sh | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/ci/do_ci.sh b/ci/do_ci.sh index da34f6531db6b..fe9f7e028956b 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -413,28 +413,22 @@ case $CI_TARGET in -c fastbuild \ "${TEST_TARGETS[@]}" fi - if [[ -z "$ENVOY_SKIP_CTO_JEMALLOC" ]]; then - echo "Building and testing with jemalloc: ${TEST_TARGETS[*]}" - bazel_with_collection \ - test "${BAZEL_BUILD_OPTIONS[@]}" \ - --@envoy//bazel:jemalloc=True \ - -c fastbuild \ - @envoy//test/common/memory/... - echo "Building binary with jemalloc..." - bazel build "${BAZEL_BUILD_OPTIONS[@]}" \ - --@envoy//bazel:jemalloc=True \ - -c fastbuild \ - @envoy//source/exe:envoy-static - fi if [[ -z "$ENVOY_SKIP_CTO_WASMTIME" ]]; then exit 0 fi echo "Building and testing with wasm=wasmtime: and admin_functionality and admin_html disabled ${TEST_TARGETS[*]}" + # --define tcmalloc=disabled is required here because --config=compile-time-options sets + # --define=tcmalloc=gperftools, which would conflict with --@envoy//bazel:jemalloc=True. + # Normally the jemalloc bool_flag alone is sufficient to select jemalloc (tcmalloc is + # disabled implicitly by the flag taking precedence in the select), but when gperftools is + # explicitly enabled via --define, both conditions become active and must be resolved manually. bazel_with_collection \ test "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ --define wasm=wasmtime \ --define admin_functionality=disabled \ + --define tcmalloc=disabled \ + --@envoy//bazel:jemalloc=True \ -c fastbuild \ "${TEST_TARGETS[@]}" # "--define log_debug_assert_in_release=enabled" must be tested with a release build, so run only From b0eb0022f8c8cf9947da365cd97112828d90815c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 04:21:19 +0000 Subject: [PATCH 08/14] more Signed-off-by: Takeshi Yoneda --- .bazelrc | 1 - ci/do_ci.sh | 12 +++++------- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/.bazelrc b/.bazelrc index f199441858119..31a635decae8d 100644 --- a/.bazelrc +++ b/.bazelrc @@ -208,7 +208,6 @@ build:compile-time-options --config=boringssl-fips build:compile-time-options --define=log_debug_assert_in_release=enabled build:compile-time-options --define=path_normalization_by_default=true build:compile-time-options --define=deprecated_features=disabled -build:compile-time-options --define=tcmalloc=gperftools build:compile-time-options --define=uhv=enabled # gRPC has a lot of deprecated-enum-enum-conversion warnings with C++20 build:compile-time-options --copt=-Wno-error=deprecated-enum-enum-conversion diff --git a/ci/do_ci.sh b/ci/do_ci.sh index fe9f7e028956b..bccdcc6b966d2 100755 --- a/ci/do_ci.sh +++ b/ci/do_ci.sh @@ -409,6 +409,7 @@ case $CI_TARGET in bazel_with_collection \ test "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ + --define tcmalloc=gperftools \ --define wasm=wamr \ -c fastbuild \ "${TEST_TARGETS[@]}" @@ -416,18 +417,12 @@ case $CI_TARGET in if [[ -z "$ENVOY_SKIP_CTO_WASMTIME" ]]; then exit 0 fi - echo "Building and testing with wasm=wasmtime: and admin_functionality and admin_html disabled ${TEST_TARGETS[*]}" - # --define tcmalloc=disabled is required here because --config=compile-time-options sets - # --define=tcmalloc=gperftools, which would conflict with --@envoy//bazel:jemalloc=True. - # Normally the jemalloc bool_flag alone is sufficient to select jemalloc (tcmalloc is - # disabled implicitly by the flag taking precedence in the select), but when gperftools is - # explicitly enabled via --define, both conditions become active and must be resolved manually. + echo "Building and testing with wasm=wasmtime and jemalloc: and admin_functionality and admin_html disabled ${TEST_TARGETS[*]}" bazel_with_collection \ test "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ --define wasm=wasmtime \ --define admin_functionality=disabled \ - --define tcmalloc=disabled \ --@envoy//bazel:jemalloc=True \ -c fastbuild \ "${TEST_TARGETS[@]}" @@ -436,6 +431,7 @@ case $CI_TARGET in bazel_with_collection \ test "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ + --define tcmalloc=gperftools \ --define wasm=wasmtime \ -c opt \ @envoy//test/common/common:assert_test \ @@ -444,6 +440,7 @@ case $CI_TARGET in bazel_with_collection \ test "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ + --define tcmalloc=gperftools \ --define wasm=wasmtime \ -c opt \ @envoy//test/common/common:assert_test \ @@ -452,6 +449,7 @@ case $CI_TARGET in echo "Building binary with wasm=wasmtime... and logging disabled" bazel build "${BAZEL_BUILD_OPTIONS[@]}" \ --config=compile-time-options \ + --define tcmalloc=gperftools \ --define wasm=wasmtime \ --define enable_logging=disabled \ -c fastbuild \ From e44c0c37dea205b7f5db2a06939df13b3f0fd22f Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 19:14:23 +0000 Subject: [PATCH 09/14] reviews Signed-off-by: Takeshi Yoneda --- bazel/foreign_cc/BUILD | 1 + source/common/memory/utils.cc | 2 +- tools/spelling/spelling_dictionary.txt | 3 --- 3 files changed, 2 insertions(+), 4 deletions(-) diff --git a/bazel/foreign_cc/BUILD b/bazel/foreign_cc/BUILD index 492c7838f8c39..f6b7b202afbba 100644 --- a/bazel/foreign_cc/BUILD +++ b/bazel/foreign_cc/BUILD @@ -454,6 +454,7 @@ configure_make( "--enable-static", "--disable-doc", "--disable-cxx", + "--disable-prof", ], lib_source = "@jemalloc//:all", out_static_libs = ["libjemalloc.a"], diff --git a/source/common/memory/utils.cc b/source/common/memory/utils.cc index be25d382034d0..cf7f5db505c06 100644 --- a/source/common/memory/utils.cc +++ b/source/common/memory/utils.cc @@ -26,7 +26,7 @@ void Utils::releaseFreeMemory(uint64_t max_unfreed_bytes) { #elif defined(JEMALLOC) UNREFERENCED_PARAMETER(max_unfreed_bytes); // Purge all arenas to release dirty pages back to the OS. - // MALLCTL_ARENAS_ALL is jemalloc's pseudo-index for addressing all arenas at once. + // `MALLCTL_ARENAS_ALL` is jemalloc's pseudo-index for addressing all arenas at once. char purge_cmd[32]; snprintf(purge_cmd, sizeof(purge_cmd), "arena.%u.purge", MALLCTL_ARENAS_ALL); mallctl(purge_cmd, nullptr, nullptr, nullptr, 0); diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index ae8e7060c0e5a..7a8b3bcae11c1 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -987,7 +987,6 @@ iteratively javascript jitter jittered -jemalloc joinable js kafka @@ -1044,8 +1043,6 @@ luajit lyft maglev malloc -mallctl -MALLCTL marshaller matchable matcher From 45373e2ceeebc56d172d1eef4f75b50a4352f59c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 19:49:04 +0000 Subject: [PATCH 10/14] spelling Signed-off-by: Takeshi Yoneda --- tools/spelling/spelling_dictionary.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/spelling/spelling_dictionary.txt b/tools/spelling/spelling_dictionary.txt index 7a8b3bcae11c1..813a6ab2aae4a 100644 --- a/tools/spelling/spelling_dictionary.txt +++ b/tools/spelling/spelling_dictionary.txt @@ -987,6 +987,7 @@ iteratively javascript jitter jittered +jemalloc joinable js kafka From 645e90855cb8afee2bc27309c0b7f68a3166eb22 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 20:15:09 -0700 Subject: [PATCH 11/14] Update source/common/memory/stats.cc Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Takeshi Yoneda --- source/common/memory/stats.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index 91a230635a816..75b0b690d1cd3 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -141,6 +141,7 @@ uint64_t Stats::totalPhysicalBytes() { MallocExtension::instance()->GetNumericProperty("generic.total_physical_bytes", &value); return value; #elif defined(JEMALLOC) + refreshJemallocEpoch(); size_t resident = 0; size_t sz = sizeof(resident); mallctl("stats.resident", &resident, &sz, nullptr, 0); From cee075312d6a38cc69a83b2a93d5f0cd2b88350b Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 20:15:24 -0700 Subject: [PATCH 12/14] Update source/common/memory/stats.cc Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Takeshi Yoneda --- source/common/memory/stats.cc | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index 75b0b690d1cd3..fe09dabb6a26b 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -71,10 +71,11 @@ uint64_t Stats::totalCurrentlyReserved() { MallocExtension::instance()->GetNumericProperty("generic.heap_size", &value); return value; #elif defined(JEMALLOC) - size_t resident = 0; - size_t sz = sizeof(resident); - mallctl("stats.resident", &resident, &sz, nullptr, 0); - return resident; + refreshJemallocEpoch(); + size_t mapped = 0; + size_t sz = sizeof(mapped); + mallctl("stats.mapped", &mapped, &sz, nullptr, 0); + return mapped; #else return 0; #endif From e3ba951f790c86f3cad0f6700e84088bd492185c Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 20:15:35 -0700 Subject: [PATCH 13/14] Update source/common/memory/stats.cc Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Takeshi Yoneda --- source/common/memory/stats.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index fe09dabb6a26b..6556ff504226d 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -125,6 +125,7 @@ uint64_t Stats::totalPageHeapUnmapped() { MallocExtension::instance()->GetNumericProperty("tcmalloc.pageheap_unmapped_bytes", &value); return value; #elif defined(JEMALLOC) + refreshJemallocEpoch(); size_t retained = 0; size_t sz = sizeof(retained); mallctl("stats.retained", &retained, &sz, nullptr, 0); From b0cff72598bda222483a61079ab33758ad515560 Mon Sep 17 00:00:00 2001 From: Takeshi Yoneda Date: Thu, 26 Mar 2026 20:15:45 -0700 Subject: [PATCH 14/14] Update source/common/memory/stats.cc Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Signed-off-by: Takeshi Yoneda --- source/common/memory/stats.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/source/common/memory/stats.cc b/source/common/memory/stats.cc index 6556ff504226d..37ebaa4dddfdc 100644 --- a/source/common/memory/stats.cc +++ b/source/common/memory/stats.cc @@ -106,6 +106,7 @@ uint64_t Stats::totalPageHeapFree() { MallocExtension::instance()->GetNumericProperty("tcmalloc.pageheap_free_bytes", &value); return value; #elif defined(JEMALLOC) + refreshJemallocEpoch(); size_t active = 0, allocated = 0; size_t sz = sizeof(size_t); mallctl("stats.active", &active, &sz, nullptr, 0);