From 9038f37ea280f4777b82ce2517ad2a432109342c Mon Sep 17 00:00:00 2001 From: clockwork-labs-bot Date: Thu, 9 Apr 2026 02:48:03 -0400 Subject: [PATCH 1/2] Avoid jemalloc crashes on Linux aarch64 --- crates/cli/src/main.rs | 8 ++++++-- crates/client-api/src/routes/internal.rs | 5 ++--- crates/core/src/worker_metrics/mod.rs | 6 +++--- crates/standalone/src/main.rs | 8 ++++++-- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 6f2e4d23f08..3bf2fe01836 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -7,10 +7,14 @@ use spacetimedb_paths::RootDir; // Note that the standalone server is invoked through standaline/src/main.rs, so you will // also want to set the allocator there. -#[cfg(not(target_env = "msvc"))] +// +// jemalloc aborts on some Linux/aarch64 systems with larger page sizes, including +// Fedora Asahi on Apple Silicon. Fall back to the system allocator there until we +// have a jemalloc configuration that is known to work on those targets. +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] use tikv_jemallocator::Jemalloc; -#[cfg(not(target_env = "msvc"))] +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; diff --git a/crates/client-api/src/routes/internal.rs b/crates/client-api/src/routes/internal.rs index b9faf10d391..a01ba9dee65 100644 --- a/crates/client-api/src/routes/internal.rs +++ b/crates/client-api/src/routes/internal.rs @@ -1,6 +1,6 @@ use crate::NodeDelegate; -#[cfg(not(target_env = "msvc"))] +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] mod jemalloc_profiling { use axum::body::Body; use axum::extract::Query; @@ -132,13 +132,12 @@ mod jemalloc_profiling { } } -#[cfg(target_env = "msvc")] +#[cfg(any(target_env = "msvc", all(target_os = "linux", target_arch = "aarch64")))] mod jemalloc_profiling { use axum::response::IntoResponse; use http::StatusCode; async fn jemalloc_unsupported() -> impl IntoResponse { - // Return an error for msvc environments ( StatusCode::INTERNAL_SERVER_ERROR, "jemalloc heap profiling is not supported on this platform.", diff --git a/crates/core/src/worker_metrics/mod.rs b/crates/core/src/worker_metrics/mod.rs index 7f5492a7057..75a26cb66b0 100644 --- a/crates/core/src/worker_metrics/mod.rs +++ b/crates/core/src/worker_metrics/mod.rs @@ -501,13 +501,13 @@ metrics_group!( pub static WORKER_METRICS: Lazy = Lazy::new(WorkerMetrics::new); -#[cfg(not(target_env = "msvc"))] +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] use tikv_jemalloc_ctl::{epoch, stats}; -#[cfg(not(target_env = "msvc"))] +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] static SPAWN_JEMALLOC_GUARD: Once = Once::new(); pub fn spawn_jemalloc_stats(_node_id: String) { - #[cfg(not(target_env = "msvc"))] + #[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] SPAWN_JEMALLOC_GUARD.call_once(|| { spawn(async move { let allocated_bytes = WORKER_METRICS.jemalloc_allocated_bytes.with_label_values(&_node_id); diff --git a/crates/standalone/src/main.rs b/crates/standalone/src/main.rs index 06114d63b8d..9d443dd2005 100644 --- a/crates/standalone/src/main.rs +++ b/crates/standalone/src/main.rs @@ -41,10 +41,13 @@ Example usage: ) } -#[cfg(not(target_env = "msvc"))] +// jemalloc aborts on some Linux/aarch64 systems with larger page sizes, including +// Fedora Asahi on Apple Silicon. Fall back to the system allocator there until we +// have a jemalloc configuration that is known to work on those targets. +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] use tikv_jemallocator::Jemalloc; -#[cfg(not(target_env = "msvc"))] +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; @@ -55,6 +58,7 @@ static GLOBAL: Jemalloc = Jemalloc; // This can be overridden by setting the `_RJEM_MALLOC_CONF` environment variable. // We export this symbol so that the jemalloc library can find it. // See https://github.com/polarsignals/rust-jemalloc-pprof?tab=readme-ov-file#usage +#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] #[allow(non_upper_case_globals)] #[unsafe(export_name = "_rjem_malloc_conf")] pub static _rjem_malloc_conf: &[u8] = b"prof:true,prof_active:false,lg_prof_sample:19\0"; From 186d66787a1620b535ece1865ea637bc0d53a774 Mon Sep 17 00:00:00 2001 From: clockwork-labs-bot Date: Thu, 9 Apr 2026 02:57:20 -0400 Subject: [PATCH 2/2] Build jemalloc with a larger page size --- .cargo/config.toml | 6 ++++++ crates/cli/src/main.rs | 8 ++------ crates/client-api/src/routes/internal.rs | 5 +++-- crates/core/src/worker_metrics/mod.rs | 6 +++--- crates/standalone/src/main.rs | 8 ++------ 5 files changed, 16 insertions(+), 17 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 949d1ed002f..64d64b73501 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -17,3 +17,9 @@ linker = "lld-link" # Without this, the linker complains that libc functions are undefined - # it probably signals to rustc and lld-link that libucrt should be included. rustflags = ["-Ctarget-feature=+crt-static"] + +[env] +# Build vendored jemalloc with a 64 KiB allocator page size so it works on +# Linux/aarch64 systems with larger kernel page sizes, including Fedora Asahi. +# This still allows local environment overrides when needed. +JEMALLOC_SYS_WITH_LG_PAGE = "16" diff --git a/crates/cli/src/main.rs b/crates/cli/src/main.rs index 3bf2fe01836..6f2e4d23f08 100644 --- a/crates/cli/src/main.rs +++ b/crates/cli/src/main.rs @@ -7,14 +7,10 @@ use spacetimedb_paths::RootDir; // Note that the standalone server is invoked through standaline/src/main.rs, so you will // also want to set the allocator there. -// -// jemalloc aborts on some Linux/aarch64 systems with larger page sizes, including -// Fedora Asahi on Apple Silicon. Fall back to the system allocator there until we -// have a jemalloc configuration that is known to work on those targets. -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; diff --git a/crates/client-api/src/routes/internal.rs b/crates/client-api/src/routes/internal.rs index a01ba9dee65..b9faf10d391 100644 --- a/crates/client-api/src/routes/internal.rs +++ b/crates/client-api/src/routes/internal.rs @@ -1,6 +1,6 @@ use crate::NodeDelegate; -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] mod jemalloc_profiling { use axum::body::Body; use axum::extract::Query; @@ -132,12 +132,13 @@ mod jemalloc_profiling { } } -#[cfg(any(target_env = "msvc", all(target_os = "linux", target_arch = "aarch64")))] +#[cfg(target_env = "msvc")] mod jemalloc_profiling { use axum::response::IntoResponse; use http::StatusCode; async fn jemalloc_unsupported() -> impl IntoResponse { + // Return an error for msvc environments ( StatusCode::INTERNAL_SERVER_ERROR, "jemalloc heap profiling is not supported on this platform.", diff --git a/crates/core/src/worker_metrics/mod.rs b/crates/core/src/worker_metrics/mod.rs index 75a26cb66b0..7f5492a7057 100644 --- a/crates/core/src/worker_metrics/mod.rs +++ b/crates/core/src/worker_metrics/mod.rs @@ -501,13 +501,13 @@ metrics_group!( pub static WORKER_METRICS: Lazy = Lazy::new(WorkerMetrics::new); -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] use tikv_jemalloc_ctl::{epoch, stats}; -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] static SPAWN_JEMALLOC_GUARD: Once = Once::new(); pub fn spawn_jemalloc_stats(_node_id: String) { - #[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] + #[cfg(not(target_env = "msvc"))] SPAWN_JEMALLOC_GUARD.call_once(|| { spawn(async move { let allocated_bytes = WORKER_METRICS.jemalloc_allocated_bytes.with_label_values(&_node_id); diff --git a/crates/standalone/src/main.rs b/crates/standalone/src/main.rs index 9d443dd2005..06114d63b8d 100644 --- a/crates/standalone/src/main.rs +++ b/crates/standalone/src/main.rs @@ -41,13 +41,10 @@ Example usage: ) } -// jemalloc aborts on some Linux/aarch64 systems with larger page sizes, including -// Fedora Asahi on Apple Silicon. Fall back to the system allocator there until we -// have a jemalloc configuration that is known to work on those targets. -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] use tikv_jemallocator::Jemalloc; -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] +#[cfg(not(target_env = "msvc"))] #[global_allocator] static GLOBAL: Jemalloc = Jemalloc; @@ -58,7 +55,6 @@ static GLOBAL: Jemalloc = Jemalloc; // This can be overridden by setting the `_RJEM_MALLOC_CONF` environment variable. // We export this symbol so that the jemalloc library can find it. // See https://github.com/polarsignals/rust-jemalloc-pprof?tab=readme-ov-file#usage -#[cfg(all(not(target_env = "msvc"), not(all(target_os = "linux", target_arch = "aarch64"))))] #[allow(non_upper_case_globals)] #[unsafe(export_name = "_rjem_malloc_conf")] pub static _rjem_malloc_conf: &[u8] = b"prof:true,prof_active:false,lg_prof_sample:19\0";