Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .bazelrc
Original file line number Diff line number Diff line change
Expand Up @@ -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
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is to be able to run jemalloc enabled tests since gperftools will conflict with jemalloc. Instead, added gperftools option explicitly in the CI script

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
Expand Down
10 changes: 10 additions & 0 deletions bazel/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,16 @@ config_setting(
values = {"define": "tcmalloc=gperftools"},
)

bool_flag(
name = "jemalloc",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should it be tcmalloc=jemalloc instead for consistency with gperftools?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i did that initially, and thought it's just weird. Either works for me but will leave it to @phlax for the final call

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can use a string_flag similar to how the define works - ie something like --//bazel:alloc=jemalloc/tcmalloc

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i would rather keep the bool flag as is for this PR, then refactor the flags in a follow. wdyt?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sgtm

build_setting_default = False,
)

config_setting(
name = "jemalloc_enabled",
flag_values = {":jemalloc": "True"},
)

config_setting(
name = "disable_signal_trace",
values = {"define": "signal_trace=disabled"},
Expand Down
12 changes: 12 additions & 0 deletions bazel/deps.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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-05-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"
Expand Down
2 changes: 2 additions & 0 deletions bazel/envoy_internal.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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"),
})

Expand Down
1 change: 1 addition & 0 deletions bazel/envoy_library.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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")],
})

Expand Down
16 changes: 16 additions & 0 deletions bazel/foreign_cc/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,22 @@ envoy_cc_library(
}),
)

configure_make(
name = "jemalloc",
configure_options = [
"--with-jemalloc-prefix=",
"--disable-shared",
"--enable-static",
"--disable-doc",
"--disable-cxx",
Comment thread
mathetake marked this conversation as resolved.
"--disable-prof",
],
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"],
Expand Down
7 changes: 7 additions & 0 deletions bazel/repositories.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,7 @@ def envoy_dependencies(skip_targets = []):
_libsxg()
_tcmalloc()
_gperftools()
_jemalloc()
_com_github_grpc_grpc()
_rules_proto_grpc()
_icu()
Expand Down Expand Up @@ -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",
Expand Down
6 changes: 6 additions & 0 deletions bazel/repository_locations.bzl
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
7 changes: 6 additions & 1 deletion ci/do_ci.sh
Original file line number Diff line number Diff line change
Expand Up @@ -409,26 +409,29 @@ 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[@]}"
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[*]}"
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 \
--@envoy//bazel:jemalloc=True \
Comment thread
mathetake marked this conversation as resolved.
-c fastbuild \
"${TEST_TARGETS[@]}"
# "--define log_debug_assert_in_release=enabled" must be tested with a release build, so run only
# these tests under "-c opt" to save time in CI.
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 \
Expand All @@ -437,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 \
Expand All @@ -445,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 \
Expand Down
59 changes: 59 additions & 0 deletions source/common/memory/stats.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include "tcmalloc/malloc_extension.h"
#elif defined(GPERFTOOLS_TCMALLOC)
#include "gperftools/malloc_extension.h"
#elif defined(JEMALLOC)
#include <jemalloc/jemalloc.h>
#endif

namespace Envoy {
Expand All @@ -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")
Expand All @@ -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
Expand All @@ -51,6 +70,12 @@ uint64_t Stats::totalCurrentlyReserved() {
size_t value = 0;
MallocExtension::instance()->GetNumericProperty("generic.heap_size", &value);
return value;
#elif defined(JEMALLOC)
refreshJemallocEpoch();
size_t mapped = 0;
size_t sz = sizeof(mapped);
mallctl("stats.mapped", &mapped, &sz, nullptr, 0);
return mapped;
#else
return 0;
#endif
Expand All @@ -65,6 +90,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
Expand All @@ -77,6 +105,13 @@ uint64_t Stats::totalPageHeapFree() {
size_t value = 0;
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);
mallctl("stats.allocated", &allocated, &sz, nullptr, 0);
return active > allocated ? active - allocated : 0;
Comment thread
mathetake marked this conversation as resolved.
#else
return 0;
#endif
Expand All @@ -90,6 +125,12 @@ uint64_t Stats::totalPageHeapUnmapped() {
size_t value = 0;
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);
return retained;
Comment thread
mathetake marked this conversation as resolved.
#else
return 0;
#endif
Expand All @@ -102,6 +143,12 @@ uint64_t Stats::totalPhysicalBytes() {
size_t value = 0;
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);
return resident;
Comment thread
mathetake marked this conversation as resolved.
#else
return 0;
#endif
Expand All @@ -115,6 +162,12 @@ void Stats::dumpStatsToLog() {
auto buffer = std::make_unique<char[]>(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<std::string*>(opaque)->append(msg); },
&output, nullptr);
ENVOY_LOG_MISC(debug, "jemalloc stats:\n{}", output);
#else
return;
#endif
Expand All @@ -129,6 +182,12 @@ absl::optional<std::string> 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<std::string*>(opaque)->append(msg); },
&output, nullptr);
return output;
#else
return absl::nullopt;
#endif
Expand Down
13 changes: 12 additions & 1 deletion source/common/memory/utils.cc
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
#include "tcmalloc/malloc_extension.h"
#elif defined(GPERFTOOLS_TCMALLOC)
#include "gperftools/malloc_extension.h"
#elif defined(JEMALLOC)
#include <jemalloc/jemalloc.h>

#include <cstdio>
#endif

namespace Envoy {
Expand All @@ -19,6 +23,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);
Comment on lines +28 to +32
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only place I need to learn things more about jemalloc, but it looks correct too me

#else
UNREFERENCED_PARAMETER(max_unfreed_bytes);
#endif
Expand All @@ -31,7 +42,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();
Expand Down
1 change: 1 addition & 0 deletions tools/spelling/spelling_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -987,6 +987,7 @@ iteratively
javascript
jitter
jittered
jemalloc
joinable
js
kafka
Expand Down
Loading