Skip to content

Commit 5723d7c

Browse files
committed
perf(context): split context into flags and inner context
1 parent dd2cfa3 commit 5723d7c

File tree

3 files changed

+117
-33
lines changed

3 files changed

+117
-33
lines changed

opentelemetry/src/context.rs

Lines changed: 112 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -93,11 +93,18 @@ thread_local! {
9393
/// assert_eq!(current.get::<ValueB>(), None);
9494
/// ```
9595
#[derive(Clone, Default)]
96+
#[cfg_attr(target_pointer_width = "64", repr(align(16)))]
97+
#[cfg_attr(target_pointer_width = "32", repr(align(8)))]
9698
pub struct Context {
99+
pub(crate) inner: Option<Arc<InnerContext>>,
100+
flags: ContextFlags,
101+
}
102+
103+
#[derive(Default)]
104+
pub(crate) struct InnerContext {
97105
#[cfg(feature = "trace")]
98106
pub(crate) span: Option<Arc<SynchronizedSpan>>,
99107
entries: Option<Arc<EntryMap>>,
100-
suppress_telemetry: bool,
101108
}
102109

103110
type EntryMap = HashMap<TypeId, Arc<dyn Any + Sync + Send>, BuildHasherDefault<IdHasher>>;
@@ -198,7 +205,9 @@ impl Context {
198205
/// assert_eq!(cx.get::<MyUser>(), None);
199206
/// ```
200207
pub fn get<T: 'static>(&self) -> Option<&T> {
201-
self.entries
208+
self.inner
209+
.as_ref()?
210+
.entries
202211
.as_ref()?
203212
.get(&TypeId::of::<T>())?
204213
.downcast_ref()
@@ -232,20 +241,29 @@ impl Context {
232241
/// assert_eq!(cx_with_a_and_b.get::<ValueB>(), Some(&ValueB(42)));
233242
/// ```
234243
pub fn with_value<T: 'static + Send + Sync>(&self, value: T) -> Self {
235-
let entries = if let Some(current_entries) = &self.entries {
236-
let mut inner_entries = (**current_entries).clone();
237-
inner_entries.insert(TypeId::of::<T>(), Arc::new(value));
238-
Some(Arc::new(inner_entries))
239-
} else {
244+
fn new_entries<T: 'static + Send + Sync>(value: T) -> Option<Arc<EntryMap>> {
240245
let mut entries = EntryMap::default();
241246
entries.insert(TypeId::of::<T>(), Arc::new(value));
242247
Some(Arc::new(entries))
248+
}
249+
let (entries, span) = if let Some(inner) = &self.inner {
250+
if let Some(current_entries) = &inner.entries {
251+
let mut inner_entries = (**current_entries).clone();
252+
inner_entries.insert(TypeId::of::<T>(), Arc::new(value));
253+
(Some(Arc::new(inner_entries)), &inner.span)
254+
} else {
255+
(new_entries(value), &inner.span)
256+
}
257+
} else {
258+
(new_entries(value), &None)
243259
};
244260
Context {
245-
entries,
246-
#[cfg(feature = "trace")]
247-
span: self.span.clone(),
248-
suppress_telemetry: self.suppress_telemetry,
261+
inner: Some(Arc::new(InnerContext {
262+
entries,
263+
#[cfg(feature = "trace")]
264+
span: span.clone(),
265+
})),
266+
flags: self.flags,
249267
}
250268
}
251269

@@ -335,16 +353,14 @@ impl Context {
335353
/// Returns whether telemetry is suppressed in this context.
336354
#[inline]
337355
pub fn is_telemetry_suppressed(&self) -> bool {
338-
self.suppress_telemetry
356+
self.flags.is_telemetry_suppressed()
339357
}
340358

341359
/// Returns a new context with telemetry suppression enabled.
342360
pub fn with_telemetry_suppressed(&self) -> Self {
343361
Context {
344-
entries: self.entries.clone(),
345-
#[cfg(feature = "trace")]
346-
span: self.span.clone(),
347-
suppress_telemetry: true,
362+
inner: self.inner.clone(),
363+
flags: self.flags.with_telemetry_suppressed(),
348364
}
349365
}
350366

@@ -410,19 +426,45 @@ impl Context {
410426

411427
#[cfg(feature = "trace")]
412428
pub(crate) fn current_with_synchronized_span(value: SynchronizedSpan) -> Self {
413-
Self::map_current(|cx| Context {
414-
span: Some(Arc::new(value)),
415-
entries: cx.entries.clone(),
416-
suppress_telemetry: cx.suppress_telemetry,
429+
Self::map_current(|cx| {
430+
if let Some(inner) = &cx.inner {
431+
Context {
432+
inner: Some(Arc::new(InnerContext {
433+
span: Some(Arc::new(value)),
434+
entries: inner.entries.clone(),
435+
})),
436+
flags: cx.flags,
437+
}
438+
} else {
439+
Context {
440+
inner: Some(Arc::new(InnerContext {
441+
span: Some(Arc::new(value)),
442+
entries: None,
443+
})),
444+
flags: ContextFlags::new(),
445+
}
446+
}
417447
})
418448
}
419449

420450
#[cfg(feature = "trace")]
421451
pub(crate) fn with_synchronized_span(&self, value: SynchronizedSpan) -> Self {
422-
Context {
423-
span: Some(Arc::new(value)),
424-
entries: self.entries.clone(),
425-
suppress_telemetry: self.suppress_telemetry,
452+
if let Some(inner) = &self.inner {
453+
Context {
454+
inner: Some(Arc::new(InnerContext {
455+
span: Some(Arc::new(value)),
456+
entries: inner.entries.clone(),
457+
})),
458+
flags: self.flags,
459+
}
460+
} else {
461+
Context {
462+
inner: Some(Arc::new(InnerContext {
463+
span: Some(Arc::new(value)),
464+
entries: None,
465+
})),
466+
flags: ContextFlags::new(),
467+
}
426468
}
427469
}
428470
}
@@ -432,25 +474,67 @@ impl fmt::Debug for Context {
432474
let mut dbg = f.debug_struct("Context");
433475

434476
#[cfg(feature = "trace")]
435-
let mut entries = self.entries.as_ref().map_or(0, |e| e.len());
477+
let mut entries = self
478+
.inner
479+
.as_ref()
480+
.map_or(0, |i| i.entries.as_ref().map_or(0, |e| e.len()));
436481
#[cfg(feature = "trace")]
437482
{
438-
if let Some(span) = &self.span {
483+
if let Some(Some(span)) = self.inner.as_ref().map(|i| i.span.as_ref()) {
439484
dbg.field("span", &span.span_context());
440485
entries += 1;
441486
} else {
442487
dbg.field("span", &"None");
443488
}
444489
}
445490
#[cfg(not(feature = "trace"))]
446-
let entries = self.entries.as_ref().map_or(0, |e| e.len());
491+
let entries = self
492+
.inner
493+
.as_ref()
494+
.map_or(0, |i| i.entries.as_ref().map_or(0, |e| e.len()));
447495

448496
dbg.field("entries count", &entries)
449-
.field("suppress_telemetry", &self.suppress_telemetry)
497+
.field("flags", &self.flags)
450498
.finish()
451499
}
452500
}
453501

502+
/// Bit flags for context state.
503+
#[derive(Clone, Copy, Default)]
504+
struct ContextFlags(u16);
505+
506+
impl ContextFlags {
507+
const SUPPRESS_TELEMETRY: u16 = 1 << 0;
508+
509+
/// Creates a new ContextFlags with all flags cleared.
510+
#[inline(always)]
511+
const fn new() -> Self {
512+
ContextFlags(0)
513+
}
514+
515+
/// Returns true if telemetry suppression is enabled.
516+
#[inline(always)]
517+
const fn is_telemetry_suppressed(self) -> bool {
518+
(self.0 & Self::SUPPRESS_TELEMETRY) != 0
519+
}
520+
521+
/// Returns a new ContextFlags with telemetry suppression enabled.
522+
#[inline(always)]
523+
const fn with_telemetry_suppressed(self) -> Self {
524+
ContextFlags(self.0 | Self::SUPPRESS_TELEMETRY)
525+
}
526+
}
527+
528+
impl fmt::Debug for ContextFlags {
529+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
530+
f.write_str("ContextFlags(")?;
531+
if self.is_telemetry_suppressed() {
532+
f.write_str("TELEMETRY_SUPPRESSED")?;
533+
}
534+
f.write_str(")")
535+
}
536+
}
537+
454538
/// A guard that resets the current context to the prior context when dropped.
455539
#[derive(Debug)]
456540
pub struct ContextGuard {

opentelemetry/src/trace/context.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,15 +308,15 @@ impl TraceContextExt for Context {
308308
}
309309

310310
fn span(&self) -> SpanRef<'_> {
311-
if let Some(span) = self.span.as_ref() {
311+
if let Some(Some(span)) = self.inner.as_ref().map(|i| i.span.as_ref()) {
312312
SpanRef(span)
313313
} else {
314314
SpanRef(&NOOP_SPAN)
315315
}
316316
}
317317

318318
fn has_active_span(&self) -> bool {
319-
self.span.is_some()
319+
self.inner.as_ref().map_or(false, |i| i.span.is_some())
320320
}
321321

322322
fn with_remote_span_context(&self, span_context: crate::trace::SpanContext) -> Self {

opentelemetry/src/trace/span_context.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -444,9 +444,9 @@ mod tests {
444444
let cx = Context::current();
445445
assert_eq!(
446446
format!("{cx:?}"),
447-
"Context { span: \"None\", entries count: 0, suppress_telemetry: false }"
447+
"Context { span: \"None\", entries count: 0, flags: ContextFlags() }"
448448
);
449-
let cx = Context::current().with_remote_span_context(SpanContext::NONE);
449+
let cx = Context::current().with_remote_span_context(SpanContext::NONE).with_telemetry_suppressed();
450450
assert_eq!(
451451
format!("{cx:?}"),
452452
"Context { \
@@ -457,7 +457,7 @@ mod tests {
457457
is_remote: false, \
458458
trace_state: TraceState(None) \
459459
}, \
460-
entries count: 1, suppress_telemetry: false \
460+
entries count: 1, flags: ContextFlags(TELEMETRY_SUPPRESSED) \
461461
}"
462462
);
463463
}

0 commit comments

Comments
 (0)