Skip to content
Closed
3 changes: 3 additions & 0 deletions tracing-subscriber/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ env-filter = ["matchers", "regex", "once_cell", "tracing", "std", "thread_local"
fmt = ["registry", "std"]
ansi = ["fmt", "nu-ansi-term"]
registry = ["sharded-slab", "thread_local", "std"]
# Raises the sharded-slab MAX_THREADS from 4 096 to 131 072, preventing panics
# on high-core machines where large numbers of native threads are spawned.
large-thread-count = []
json = ["tracing-serde", "serde", "serde_json"]
valuable = ["tracing-core/valuable", "valuable_crate", "valuable-serde", "tracing-serde/valuable"]
# Enables support for local time when using the `time` crate timestamp
Expand Down
39 changes: 34 additions & 5 deletions tracing-subscriber/src/registry/sharded.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use sharded_slab::{pool::Ref, Clear, Pool};
use sharded_slab::{pool::Ref, Clear, Config, Pool};
use thread_local::ThreadLocal;

use super::stack::SpanStack;
Expand All @@ -20,6 +20,24 @@ use tracing_core::{
Event, Interest, Metadata, Subscriber,
};

/// Custom [`sharded_slab::Config`] for the span registry pool.
///
/// When the `large-thread-count` feature is enabled, `MAX_THREADS` is raised
/// from the upstream default of 4 096 to 131 072, preventing panics on
/// high-core machines (e.g. HyDRA load-gen nodes) where large numbers of
/// native threads are spawned.
#[derive(Debug)]
struct SlabConfig;

impl Config for SlabConfig {
/// When the `large-thread-count` feature is enabled on a 64-bit target:
/// 131 072 threads = 2^17. On 32-bit targets (e.g. wasm32) the raised value
/// would overflow `sharded_slab`'s bit-packing arithmetic, so the default
/// of 4 096 is retained there regardless of the feature flag.
#[cfg(all(feature = "large-thread-count", target_pointer_width = "64"))]
const MAX_THREADS: usize = 131_072;
}

/// A shared, reusable store for spans.
///
/// A `Registry` is a [`Subscriber`] around which multiple [`Layer`]s
Expand Down Expand Up @@ -90,7 +108,7 @@ use tracing_core::{
#[cfg_attr(docsrs, doc(cfg(all(feature = "registry", feature = "std"))))]
#[derive(Debug)]
pub struct Registry {
spans: Pool<DataInner>,
spans: Pool<DataInner, SlabConfig>,
current_spans: ThreadLocal<RefCell<SpanStack>>,
next_filter_id: u8,
}
Expand All @@ -109,7 +127,7 @@ pub struct Registry {
#[derive(Debug)]
pub struct Data<'a> {
/// Immutable reference to the pooled `DataInner` entry.
inner: Ref<'a, DataInner>,
inner: Ref<'a, DataInner, SlabConfig>,
}

/// Stored data associated with a span.
Expand All @@ -135,7 +153,7 @@ struct DataInner {
impl Default for Registry {
fn default() -> Self {
Self {
spans: Pool::new(),
spans: Pool::new_with_config::<SlabConfig>(),
current_spans: ThreadLocal::new(),
next_filter_id: 0,
}
Expand Down Expand Up @@ -180,7 +198,7 @@ pub(crate) struct CloseGuard<'a> {
}

impl Registry {
fn get(&self, id: &Id) -> Option<Ref<'_, DataInner>> {
fn get(&self, id: &Id) -> Option<Ref<'_, DataInner, SlabConfig>> {
self.spans.get(id_to_idx(id))
}

Expand Down Expand Up @@ -905,4 +923,15 @@ mod tests {
state.assert_closed_in_order(["child", "parent", "grandparent"]);
});
}

#[test]
#[cfg(all(feature = "large-thread-count", target_pointer_width = "64"))]
fn slab_config_raises_max_threads() {
assert_eq!(SlabConfig::MAX_THREADS, 131_072);
// Confirm the Registry pool is actually parameterised on SlabConfig —
// this is a compile-time check: if `Registry::spans` ever changes to a
// different Config type, the type annotation below will fail to compile.
let registry = Registry::default();
let _: &Pool<DataInner, SlabConfig> = &registry.spans;
Comment on lines +931 to +935
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.

Nice, that should do the trick - thanks

}
}
Loading