From 17262211a58ff6db027f24844327b235c9db3cef Mon Sep 17 00:00:00 2001 From: Igor Unanua Date: Tue, 23 Sep 2025 13:56:36 +0200 Subject: [PATCH 1/2] Extraction benchmark --- dd-trace-propagation/Cargo.toml | 4 + .../benches/extract_benchmark.rs | 226 ++++++++++++++++++ 2 files changed, 230 insertions(+) create mode 100644 dd-trace-propagation/benches/extract_benchmark.rs diff --git a/dd-trace-propagation/Cargo.toml b/dd-trace-propagation/Cargo.toml index 351bde6..71f8c03 100644 --- a/dd-trace-propagation/Cargo.toml +++ b/dd-trace-propagation/Cargo.toml @@ -39,6 +39,10 @@ dd-trace-propagation = { path = ".", features = ["test-utils"] } name = "inject_benchmark" harness = false +[[bench]] +name = "extract_benchmark" +harness = false + [features] default = ["opentelemetry"] serde_config = ["serde", "serde_json"] diff --git a/dd-trace-propagation/benches/extract_benchmark.rs b/dd-trace-propagation/benches/extract_benchmark.rs new file mode 100644 index 0000000..0631e91 --- /dev/null +++ b/dd-trace-propagation/benches/extract_benchmark.rs @@ -0,0 +1,226 @@ +// Copyright 2025-Present Datadog, Inc. https://www.datadoghq.com/ +// SPDX-License-Identifier: Apache-2.0 + +use criterion::{black_box, criterion_group, criterion_main, BatchSize, Criterion}; +use dd_trace::{ + configuration::TracePropagationStyle, + test_utils::benchmarks::{memory_allocated_measurement, MeasurementName, ReportingAllocator}, + Config, +}; +use dd_trace_propagation::{carrier::Extractor, DatadogCompositePropagator}; +use std::{collections::HashMap, sync::Arc}; + +#[global_allocator] +static GLOBAL: ReportingAllocator = ReportingAllocator::new(std::alloc::System); + +struct BenchExtractor { + headers: HashMap, +} + +impl BenchExtractor { + fn with_headers(headers: HashMap) -> Self { + Self { headers } + } +} + +impl Extractor for BenchExtractor { + fn get(&self, key: &str) -> Option<&str> { + self.headers.get(&key.to_lowercase()).map(String::as_str) + } + + fn keys(&self) -> Vec<&str> { + self.headers.keys().map(String::as_str).collect() + } +} + +fn create_simple_datadog_headers() -> HashMap { + let mut headers = HashMap::new(); + headers.insert( + "x-datadog-trace-id".to_string(), + "1234567890123456789".to_string(), + ); + headers.insert( + "x-datadog-parent-id".to_string(), + "9876543210987654321".to_string(), + ); + headers.insert("x-datadog-sampling-priority".to_string(), "1".to_string()); + headers.insert("x-datadog-origin".to_string(), "synthetics".to_string()); + headers.insert( + "x-datadog-tags".to_string(), + "_dd.p.upstream_services=service1,_dd.p.dm=-1,user.id=12345".to_string(), + ); + headers +} + +fn create_complex_datadog_headers() -> HashMap { + let mut headers = HashMap::new(); + headers.insert( + "x-datadog-trace-id".to_string(), + "1234567890123456789".to_string(), + ); + headers.insert( + "x-datadog-parent-id".to_string(), + "9876543210987654321".to_string(), + ); + headers.insert("x-datadog-sampling-priority".to_string(), "2".to_string()); + headers.insert("x-datadog-origin".to_string(), "lambda".to_string()); + + // Build complex tags with many propagation tags + let mut tags = Vec::new(); + tags.push("_dd.p.upstream_services=service1,service2,service3".to_string()); + tags.push("_dd.p.dm=-1".to_string()); + tags.push("_dd.p.tid=1234567890abcdef".to_string()); + + // Add many custom propagation tags + for i in 0..20 { + tags.push(format!("_dd.p.custom_tag_{i}=value_with_some_content_{i}")); + } + + headers.insert("x-datadog-tags".to_string(), tags.join(",")); + headers +} + +fn create_simple_tracecontext_headers() -> HashMap { + let mut headers = HashMap::new(); + headers.insert( + "traceparent".to_string(), + "00-1234567890abcdef1234567890abcdef-9876543210987654-01".to_string(), + ); + headers.insert("tracestate".to_string(), "dd=s:1;o:synthetics;p:9876543210987654321;t._dd.p.upstream_services:service1;t.user.id:12345".to_string()); + headers +} + +fn create_complex_tracecontext_headers() -> HashMap { + let mut headers = HashMap::new(); + headers.insert( + "traceparent".to_string(), + "00-1234567890abcdef1234567890abcdef-9876543210987654-01".to_string(), + ); + + // Build complex tracestate with many values + let mut tracestate_parts = Vec::new(); + tracestate_parts.push("s:2".to_string()); + tracestate_parts.push("o:lambda".to_string()); + tracestate_parts.push("p:9876543210987654321".to_string()); + + // Add many propagation tags + for i in 0..15 { + tracestate_parts.push(format!("t._dd.p.custom_tag_{i}:value_with_content_{i}")); + } + + headers.insert( + "tracestate".to_string(), + format!("dd={}", tracestate_parts.join(";")), + ); + headers +} + +fn create_both_propagation_headers() -> HashMap { + let mut headers = create_simple_datadog_headers(); + let tracecontext_headers = create_simple_tracecontext_headers(); + headers.extend(tracecontext_headers); + headers +} + +fn bench_datadog_only_extract< + M: criterion::measurement::Measurement + MeasurementName + 'static, +>( + c: &mut Criterion, +) { + let config = Config::builder() + .set_trace_propagation_style_extract(vec![TracePropagationStyle::Datadog]) + .build(); + let propagator = DatadogCompositePropagator::new(Arc::new(config)); + + c.bench_function(&format!("extract_datadog_only_simple/{}", M::name()), |b| { + b.iter_batched( + || BenchExtractor::with_headers(create_simple_datadog_headers()), + |carrier| black_box(propagator.extract(black_box(&carrier))), + BatchSize::LargeInput, + ) + }); + + c.bench_function( + &format!("extract_datadog_only_complex/{}", M::name()), + |b| { + b.iter_batched( + || BenchExtractor::with_headers(create_complex_datadog_headers()), + |carrier| black_box(propagator.extract(black_box(&carrier))), + BatchSize::LargeInput, + ) + }, + ); +} + +fn bench_tracecontext_only_extract< + M: criterion::measurement::Measurement + MeasurementName + 'static, +>( + c: &mut Criterion, +) { + let config = Config::builder() + .set_trace_propagation_style_extract(vec![TracePropagationStyle::TraceContext]) + .build(); + let propagator = DatadogCompositePropagator::new(Arc::new(config)); + + c.bench_function( + &format!("extract_tracecontext_only_simple/{}", M::name()), + |b| { + b.iter_batched( + || BenchExtractor::with_headers(create_simple_tracecontext_headers()), + |carrier| black_box(propagator.extract(black_box(&carrier))), + BatchSize::LargeInput, + ) + }, + ); + + c.bench_function( + &format!("extract_tracecontext_only_complex/{}", M::name()), + |b| { + b.iter_batched( + || BenchExtractor::with_headers(create_complex_tracecontext_headers()), + |carrier| black_box(propagator.extract(black_box(&carrier))), + BatchSize::LargeInput, + ) + }, + ); +} + +fn bench_both_propagation_extract< + M: criterion::measurement::Measurement + MeasurementName + 'static, +>( + c: &mut Criterion, +) { + let config = Config::builder() + .set_trace_propagation_style_extract(vec![ + TracePropagationStyle::Datadog, + TracePropagationStyle::TraceContext, + ]) + .build(); + let propagator = DatadogCompositePropagator::new(Arc::new(config)); + + c.bench_function(&format!("extract_both_propagation/{}", M::name()), |b| { + b.iter_batched( + || BenchExtractor::with_headers(create_both_propagation_headers()), + |carrier| black_box(propagator.extract(black_box(&carrier))), + BatchSize::LargeInput, + ) + }); +} + +criterion_group! { + name = memory_benches; + config = memory_allocated_measurement(&GLOBAL); + targets = bench_datadog_only_extract, + bench_tracecontext_only_extract, + bench_both_propagation_extract +} + +criterion_group! { + name = wall_time_benches; + config = Criterion::default(); + targets = bench_datadog_only_extract, + bench_tracecontext_only_extract, + bench_both_propagation_extract +} + +criterion_main!(memory_benches, wall_time_benches); From 6ba5311cec46f3a7ce1eed6b52874ce89d80ecd4 Mon Sep 17 00:00:00 2001 From: Igor Unanua Date: Fri, 10 Oct 2025 15:11:20 +0200 Subject: [PATCH 2/2] uppercase check --- dd-trace-propagation/benches/extract_benchmark.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/dd-trace-propagation/benches/extract_benchmark.rs b/dd-trace-propagation/benches/extract_benchmark.rs index 0631e91..a4e1ef8 100644 --- a/dd-trace-propagation/benches/extract_benchmark.rs +++ b/dd-trace-propagation/benches/extract_benchmark.rs @@ -25,7 +25,12 @@ impl BenchExtractor { impl Extractor for BenchExtractor { fn get(&self, key: &str) -> Option<&str> { - self.headers.get(&key.to_lowercase()).map(String::as_str) + let k = if key.chars().any(char::is_uppercase) { + &key.to_lowercase() + } else { + key + }; + self.headers.get(k).map(String::as_str) } fn keys(&self) -> Vec<&str> {