Skip to content

Commit 5047817

Browse files
committed
Allow force enabling jemalloc on macOS
Twiddle our crates and Cargo configuration for activating jemalloc to achieve the following ideal developer experience: * --no-default-features unequivocally disables jemalloc, regardless of platform. * --features=jemalloc unequivocally enables jemalloc, regardless of platform. * --default-features chooses the best allocator for the platform: the system allocator on macOS and jemalloc on Linux. Since Cargo doesn't explicitly support target-specific features, the trick is to introduce a crate of indirection, as described in [0]. Here's how it works: * The `mz-prof`, `mz-prof-http`, and `mz-alloc` crates have a straightforward setup: they expose a `jemalloc` feature and conditionally enable or disable jemalloc features based on whether the `jemalloc` feature is provided or not. * The `mz-alloc-default` crate depends on the `mz-alloc` crate and enables the best features for the platform: `jemalloc` on Linux, and no additional features on macOS. You can think of this crate as unconditionally enabling the best allocator for the platform. * The `mz-environmentd` and `mz-clusterd` crates unlock the conditional behavior. Bothc crates: 1. depend on `mz-alloc-default` by default, and 2. expose a `jemalloc` feature that force enables the `mz-alloc/jemalloc` feature. The motivation for all of this is to allow macOS developers to enable jemalloc upon request, which is useful for certain kinds of testing. Alternative to #27041. Closes #27041. [0]: rust-lang/cargo#1197 (comment)
1 parent 6f4fccd commit 5047817

19 files changed

+205
-42
lines changed

.config/hakari.toml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,8 @@ platforms = [
66
"x86_64-apple-darwin",
77
]
88
exact-versions = true
9+
10+
[final-excludes]
11+
third-party = [
12+
{ "name" = "tikv-jemalloc-sys" }
13+
]

Cargo.lock

Lines changed: 10 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ members = [
33
"src/adapter",
44
"src/adapter-types",
55
"src/alloc",
6+
"src/alloc-default",
67
"src/arrow-util",
78
"src/audit-log",
89
"src/avro",

ci/test/lint-deps.sh

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,19 +24,27 @@ set -euo pipefail
2424

2525
. misc/shlib/shlib.bash
2626

27-
# Explicitly name targets to check dependencies. We support Apple on ARM64 and x86_64 and Linux on x86_64.
27+
# The crates whose dependency graphs we want to lint.
28+
entrypoints=(
29+
mz-clusterd
30+
mz-environmentd
31+
)
32+
33+
# Explicitly name targets to check dependencies. We support Apple and Linux on ARM64 and x86_64.
2834
targets=(
2935
aarch64-apple-darwin
3036
x86_64-apple-darwin
37+
aarch64-unknown-linux-gnu
3138
x86_64-unknown-linux-gnu
3239
)
3340

3441
# List of crates to include in the dependency lint, including an explanation why they're listed.
3542
crates=(
3643
# Checks that the default allocator is jemalloc on supported platforms, but can
37-
# be disabled using --no-default-features
44+
# be disabled using --no-default-features or explicitly enabled with --features=jemalloc
3845
tikv_jemalloc_ctl
3946
tikv_jemallocator
47+
tikv_jemalloc_sys
4048
)
4149

4250
rewrite=false
@@ -53,7 +61,9 @@ function deps() {
5361
# output if there is no dependency to any of the specified packages.
5462
for crate in "${crates[@]}"; do
5563
# Gather data for the current target, reverse lines, find the dependency hierarchy to the root, reverse lines.
56-
output=$(cargo tree --workspace --format ':{lib}:{f}' \
64+
output=$(cargo tree \
65+
$(printf -- "-p %s " "${entrypoints[@]}") \
66+
--format ':{lib}:{f}' \
5767
--prefix depth \
5868
--edges normal,build \
5969
--locked \
@@ -76,9 +86,11 @@ for target in "${targets[@]}"; do
7686
if $rewrite; then
7787
deps > "$resources/$target-default"
7888
deps --no-default-features > "$resources/$target-no-default-features"
89+
deps --features jemalloc > "$resources/$target-jemalloc"
7990
else
8091
try diff "$resources/$target-default" <(deps)
8192
try diff "$resources/$target-no-default-features" <(deps --no-default-features)
93+
try diff "$resources/$target-jemalloc" <(deps --features jemalloc)
8294
fi
8395
done
8496

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
2+
tikv_jemalloc_ctl
3+
0::default,jemalloc,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
7+
tikv_jemallocator
8+
0::default,jemalloc,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,jemalloc,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
2+
tikv_jemalloc_ctl
3+
0::default,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
7+
tikv_jemallocator
8+
0::default,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
2+
tikv_jemalloc_ctl
3+
0::default,jemalloc,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
7+
tikv_jemallocator
8+
0::default,jemalloc,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,jemalloc,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
2+
tikv_jemalloc_ctl
3+
0::default,jemalloc,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
7+
tikv_jemallocator
8+
0::default,jemalloc,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,jemalloc,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)
Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,18 @@
11
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
22
tikv_jemalloc_ctl
3-
0:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
4-
1:mz_prof:default,jemalloc,tikv-jemalloc-ctl,workspace-hack
5-
2:tikv_jemalloc_ctl:default,use_std
3+
0::default,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
67
tikv_jemallocator
7-
0:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
8-
1:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
8+
0::default,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# generated by ci/test/lint-deps.sh -- see ci/test/lint-deps/README.md for details
2+
tikv_jemalloc_ctl
3+
0::default,jemalloc,mz-alloc-default,tokio-console
4+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
5+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
6+
3:tikv_jemalloc_ctl:default,use_std
7+
tikv_jemallocator
8+
0::default,jemalloc,mz-alloc-default,tokio-console
9+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
10+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
11+
tikv_jemalloc_sys
12+
0::default,jemalloc,mz-alloc-default,tokio-console
13+
1:mz_alloc:default,jemalloc,tikv-jemallocator,workspace-hack
14+
2:mz_prof:jemalloc,tikv-jemalloc-ctl
15+
3:tikv_jemalloc_ctl:default,use_std
16+
4:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
17+
2:tikv_jemallocator:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms
18+
3:tikv_jemalloc_sys:background_threads,background_threads_runtime_support,default,profiling,stats,unprefixed_malloc_on_supported_platforms (*)

src/alloc-default/Cargo.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "mz-alloc-default"
3+
description = "Activates the best default global memory allocator for the platform."
4+
version = "0.0.0"
5+
edition.workspace = true
6+
rust-version.workspace = true
7+
publish = false
8+
9+
[lints]
10+
workspace = true
11+
12+
[dependencies]
13+
mz-alloc = { path = "../alloc", default-features = false }
14+
workspace-hack = { version = "0.0.0", path = "../workspace-hack", optional = true }
15+
16+
# We use jemalloc by default on non-macOS platforms, as benchmarks indicated it
17+
# outperforms the system allocator, while also providing heap profiles.
18+
#
19+
# However, on macOS, we default to the system allocator, as jemalloc is not well
20+
# supported on macOS [0][1][2]. The issues present as runaway latency on load
21+
# test workloads that are comfortably handled by the macOS system allocator.
22+
# Consider re-evaluating if jemalloc's macOS support improves.
23+
#
24+
# [0]: https://github.com/jemalloc/jemalloc/issues/26
25+
# [1]: https://github.com/jemalloc/jemalloc/issues/843
26+
# [2]: https://github.com/jemalloc/jemalloc/issues/1467
27+
#
28+
# Furthermore, as of August 2022, some engineers are using profiling tools, e.g.
29+
# `heaptrack`, that only work with the system allocator on macOS.
30+
[target.'cfg(not(target_os = "macos"))'.dependencies]
31+
mz-alloc = { path = "../alloc", features = ["jemalloc"] }
32+
33+
[features]
34+
default = ["workspace-hack"]
35+
36+
[package.metadata.cargo-udeps.ignore]
37+
normal = ["workspace-hack", "mz-alloc"]

src/alloc-default/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright Materialize, Inc. and contributors. All rights reserved.
2+
//
3+
// Use of this software is governed by the Business Source License
4+
// included in the LICENSE file.
5+
//
6+
// As of the Change Date specified in that file, in accordance with
7+
// the Business Source License, use of this software will be governed
8+
// by the Apache License, Version 2.0.
9+
10+
//! Activates the best default global memory allocator for the platform.

src/alloc/Cargo.toml

Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "mz-alloc"
3-
description = "Activates the best memory allocator for the target platform."
3+
description = "Chooses a global memory allocator based on Cargo features."
44
version = "0.0.0"
55
edition.workspace = true
66
rust-version.workspace = true
@@ -11,20 +11,6 @@ workspace = true
1111

1212
[dependencies]
1313
mz-ore = { path = "../ore", default-features = false }
14-
workspace-hack = { version = "0.0.0", path = "../workspace-hack", optional = true }
15-
16-
# Disable jemalloc on macOS, as it is not well supported [0][1][2]. The issues
17-
# present as runaway latency on load test workloads that are comfortably handled
18-
# by the macOS system allocator. Consider re-evaluating if jemalloc's macOS
19-
# support improves.
20-
#
21-
# [0]: https://github.com/jemalloc/jemalloc/issues/26
22-
# [1]: https://github.com/jemalloc/jemalloc/issues/843
23-
# [2]: https://github.com/jemalloc/jemalloc/issues/1467
24-
#
25-
# Furthermore, as of August 2022, some engineers are using profiling tools, e.g.
26-
# `heaptrack`, that only work with the system allocator.
27-
[target.'cfg(not(target_os = "macos"))'.dependencies]
2814
mz-prof = { path = "../prof", default-features = false }
2915
mz-prof-http = { path = "../prof-http", default-features = false }
3016
# According to jemalloc developers, `background_threads` should always be
@@ -34,16 +20,16 @@ mz-prof-http = { path = "../prof-http", default-features = false }
3420
#
3521
# See: https://github.com/jemalloc/jemalloc/issues/956#issuecomment-316224733
3622
tikv-jemallocator = { version = "0.5.0", features = ["profiling", "stats", "unprefixed_malloc_on_supported_platforms", "background_threads"], optional = true }
23+
workspace-hack = { version = "0.0.0", path = "../workspace-hack", optional = true }
3724

3825
[features]
3926
default = ["workspace-hack"]
40-
# Whether to enable the use of jemalloc on platforms that support it.
41-
jemalloc = ["tikv-jemallocator", "mz-prof/jemalloc", "mz-prof-http/jemalloc"]
27+
# Whether to use jemalloc instead of the system allocator.
28+
jemalloc = ["tikv-jemallocator", "mz-prof-http/jemalloc"]
4229

4330
[package.metadata.cargo-udeps.ignore]
44-
# The only reason we depend on mz-prof-http
45-
# from this package is so that we can force its `jemalloc`
46-
# option to be enabled when this package's is, which
47-
# makes all the Materialize binaries correctly
48-
# serve heap profiling tools at the `/prof` endpoints.
31+
# The only reason we depend on mz-prof-http from this package is so that we can
32+
# force its `jemalloc` option to be enabled when this package's is, which makes
33+
# all the Materialize binaries correctly serve heap profiling tools at the
34+
# `/prof` endpoints.
4935
normal = ["workspace-hack", "mz-prof-http"]

src/alloc/src/lib.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
// the Business Source License, use of this software will be governed
88
// by the Apache License, Version 2.0.
99

10+
//! Chooses a global memory allocator based on Cargo features.
11+
1012
use mz_ore::metrics::MetricsRegistry;
1113

12-
#[cfg(all(not(target_os = "macos"), feature = "jemalloc", not(miri)))]
14+
#[cfg(all(feature = "jemalloc", not(miri)))]
1315
#[global_allocator]
1416
static ALLOC: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc;
1517

1618
/// Registers metrics for the global allocator into the provided registry.
1719
///
1820
/// What metrics are registered varies by platform. Not all platforms use
1921
/// allocators that support metrics.
20-
#[cfg(any(target_os = "macos", not(feature = "jemalloc"), miri))]
22+
#[cfg(any(not(feature = "jemalloc"), miri))]
2123
#[allow(clippy::unused_async)]
2224
pub async fn register_metrics_into(_: &MetricsRegistry) {
2325
// No-op on platforms that don't use jemalloc.
@@ -27,7 +29,7 @@ pub async fn register_metrics_into(_: &MetricsRegistry) {
2729
///
2830
/// What metrics are registered varies by platform. Not all platforms use
2931
/// allocators that support metrics.
30-
#[cfg(all(not(target_os = "macos"), feature = "jemalloc", not(miri)))]
32+
#[cfg(all(feature = "jemalloc", not(miri)))]
3133
pub async fn register_metrics_into(registry: &MetricsRegistry) {
3234
mz_prof::jemalloc::JemallocMetrics::register_into(registry).await;
3335
}

src/clusterd/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ clap = { version = "3.2.24", features = ["derive", "env"] }
1616
fail = { version = "0.5.1", features = ["failpoints"] }
1717
futures = "0.3.25"
1818
mz-alloc = { path = "../alloc" }
19+
mz-alloc-default = { path = "../alloc-default", optional = true }
1920
mz-build-info = { path = "../build-info" }
2021
mz-cloud-resources = { path = "../cloud-resources" }
2122
mz-compute = { path = "../compute" }
@@ -42,7 +43,7 @@ tracing = "0.1.37"
4243
workspace-hack = { version = "0.0.0", path = "../workspace-hack" }
4344

4445
[features]
45-
default = ["tokio-console", "jemalloc"]
46+
default = ["tokio-console", "mz-alloc-default"]
4647
jemalloc = ["mz-alloc/jemalloc"]
4748
tokio-console = ["mz-ore/tokio-console"]
4849

src/environmentd/Cargo.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ once_cell = "1.16.0"
4141
libc = "0.2.138"
4242
mime = "0.3.16"
4343
mz-alloc = { path = "../alloc" }
44+
mz-alloc-default = { path = "../alloc-default", optional = true }
4445
mz-aws-secrets-controller = { path = "../aws-secrets-controller" }
4546
mz-build-info = { path = "../build-info" }
4647
mz-adapter = { path = "../adapter" }
@@ -159,7 +160,7 @@ cc = "1.0.78"
159160
mz-npm = { path = "../npm" }
160161

161162
[features]
162-
default = ["tokio-console", "jemalloc"]
163+
default = ["tokio-console", "mz-alloc-default"]
163164
# When enabled, static assets for the web UI are loaded from disk on every HTTP
164165
# request rather than compiled into the binary. This vastly speeds up the
165166
# iteration cycle when developing the web UI.

0 commit comments

Comments
 (0)