From 27c18fd4ee88dfa16b1f420ccf2112fce7f1fa02 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 20:35:20 -0400 Subject: [PATCH 01/17] Add tracer benchmark and record baseline --- sdk/test/trace/BUILD | 16 +++ sdk/test/trace/CMakeLists.txt | 10 ++ sdk/test/trace/sampler_benchmark.cc | 51 ++++++++ sdk/test/trace/tracer_benchmark.cc | 195 ++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 sdk/test/trace/tracer_benchmark.cc diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index 3e4393345a..468e1400dc 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -221,3 +221,19 @@ otel_cc_benchmark( "//test_common:headers", ], ) + +otel_cc_benchmark( + name = "tracer_benchmark", + srcs = ["tracer_benchmark.cc"], + tags = [ + "benchmark", + "test", + "trace", + ], + deps = [ + "//exporters/memory:in_memory_span_exporter", + "//sdk/src/resource", + "//sdk/src/trace", + "//test_common:headers", + ], +) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index e299deb502..59a77b95b2 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -46,4 +46,14 @@ if(WITH_BENCHMARK) opentelemetry_resources opentelemetry_exporter_in_memory opentelemetry_test_common) + + add_executable(tracer_benchmark tracer_benchmark.cc) + target_link_libraries( + tracer_benchmark + benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_trace + opentelemetry_resources + opentelemetry_exporter_in_memory + opentelemetry_test_common) endif() diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index aff81aef8c..b6177f39ce 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -1,6 +1,57 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 +// clang-format off +// +// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-15T00:31:56+00:00 +// Running /home/devuser/build/sdk/test/trace/sampler_benchmark +// Run on (32 X 5700 MHz CPU s) +// CPU Caches: +// L1 Data 48 KiB (x16) +// L1 Instruction 32 KiB (x16) +// L2 Unified 2048 KiB (x16) +// L3 Unified 36864 KiB (x1) +// Load Average: 7.64, 4.23, 2.79 +// ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. +// ----------------------------------------------------------------------------------------- +// Benchmark Time CPU Iterations +// ----------------------------------------------------------------------------------------- +// BM_AlwaysOffSamplerConstruction_mean 0.339 ns 0.338 ns 5 +// BM_AlwaysOffSamplerConstruction_median 0.338 ns 0.338 ns 5 +// BM_AlwaysOffSamplerConstruction_stddev 0.002 ns 0.002 ns 5 +// BM_AlwaysOffSamplerConstruction_cv 0.53 % 0.53 % 5 +// BM_AlwaysOnSamplerConstruction_mean 0.337 ns 0.337 ns 5 +// BM_AlwaysOnSamplerConstruction_median 0.337 ns 0.337 ns 5 +// BM_AlwaysOnSamplerConstruction_stddev 0.002 ns 0.002 ns 5 +// BM_AlwaysOnSamplerConstruction_cv 0.46 % 0.47 % 5 +// BM_AlwaysOffSamplerShouldSample_mean 4.18 ns 4.18 ns 5 +// BM_AlwaysOffSamplerShouldSample_median 4.17 ns 4.17 ns 5 +// BM_AlwaysOffSamplerShouldSample_stddev 0.031 ns 0.031 ns 5 +// BM_AlwaysOffSamplerShouldSample_cv 0.73 % 0.73 % 5 +// BM_AlwaysOnSamplerShouldSample_mean 4.33 ns 4.33 ns 5 +// BM_AlwaysOnSamplerShouldSample_median 4.33 ns 4.33 ns 5 +// BM_AlwaysOnSamplerShouldSample_stddev 0.049 ns 0.049 ns 5 +// BM_AlwaysOnSamplerShouldSample_cv 1.13 % 1.13 % 5 +// BM_ParentBasedSamplerShouldSample_mean 7.07 ns 7.07 ns 5 +// BM_ParentBasedSamplerShouldSample_median 7.06 ns 7.06 ns 5 +// BM_ParentBasedSamplerShouldSample_stddev 0.022 ns 0.022 ns 5 +// BM_ParentBasedSamplerShouldSample_cv 0.32 % 0.32 % 5 +// BM_TraceIdRatioBasedSamplerShouldSample_mean 3.94 ns 3.94 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_median 3.94 ns 3.94 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.012 ns 0.012 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.31 % 0.31 % 5 +// BM_SpanCreation_mean 235 ns 235 ns 5 +// BM_SpanCreation_median 235 ns 235 ns 5 +// BM_SpanCreation_stddev 0.616 ns 0.607 ns 5 +// BM_SpanCreation_cv 0.26 % 0.26 % 5 +// BM_NoopSpanCreation_mean 59.3 ns 59.3 ns 5 +// BM_NoopSpanCreation_median 59.2 ns 59.2 ns 5 +// BM_NoopSpanCreation_stddev 0.421 ns 0.422 ns 5 +// BM_NoopSpanCreation_cv 0.71 % 0.71 % 5 +// +// clang-format on + #include #include #include diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc new file mode 100644 index 0000000000..b1f6a95c5c --- /dev/null +++ b/sdk/test/trace/tracer_benchmark.cc @@ -0,0 +1,195 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +// clang-format off +// +// ~/build/sdk/test/trace/tracer_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-15T00:33:53+00:00 +// Running /home/devuser/build/sdk/test/trace/tracer_benchmark +// Run on (32 X 5700 MHz CPU s) +// CPU Caches: +// L1 Data 48 KiB (x16) +// L1 Instruction 32 KiB (x16) +// L2 Unified 2048 KiB (x16) +// L3 Unified 36864 KiB (x1) +// Load Average: 2.44, 3.34, 2.63 +// ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. +// --------------------------------------------------------------------------------------- +// Benchmark Time CPU Iterations +// --------------------------------------------------------------------------------------- +// BM_StartSpanTracerDisabled_mean 6.85 ns 6.85 ns 5 +// BM_StartSpanTracerDisabled_median 6.84 ns 6.84 ns 5 +// BM_StartSpanTracerDisabled_stddev 0.025 ns 0.023 ns 5 +// BM_StartSpanTracerDisabled_cv 0.36 % 0.34 % 5 +// BM_StartSpan_mean 187 ns 187 ns 5 +// BM_StartSpan_median 187 ns 187 ns 5 +// BM_StartSpan_stddev 1.22 ns 1.23 ns 5 +// BM_StartSpan_cv 0.65 % 0.66 % 5 +// BM_StartSpanWithScope_mean 255 ns 255 ns 5 +// BM_StartSpanWithScope_median 255 ns 255 ns 5 +// BM_StartSpanWithScope_stddev 1.09 ns 1.11 ns 5 +// BM_StartSpanWithScope_cv 0.43 % 0.44 % 5 +// BM_StartSpanWithImplicitParent_mean 172 ns 172 ns 5 +// BM_StartSpanWithImplicitParent_median 172 ns 172 ns 5 +// BM_StartSpanWithImplicitParent_stddev 0.447 ns 0.447 ns 5 +// BM_StartSpanWithImplicitParent_cv 0.26 % 0.26 % 5 +// BM_StartSpanWithExplicitParentContext_mean 173 ns 173 ns 5 +// BM_StartSpanWithExplicitParentContext_median 173 ns 173 ns 5 +// BM_StartSpanWithExplicitParentContext_stddev 0.343 ns 0.337 ns 5 +// BM_StartSpanWithExplicitParentContext_cv 0.20 % 0.20 % 5 +// BM_StartSpanWithExplicitRootContext_mean 187 ns 187 ns 5 +// BM_StartSpanWithExplicitRootContext_median 187 ns 187 ns 5 +// BM_StartSpanWithExplicitRootContext_stddev 0.679 ns 0.666 ns 5 +// BM_StartSpanWithExplicitRootContext_cv 0.36 % 0.36 % 5 +// +// clang-format on + +#include +#include + +#include "opentelemetry/context/context.h" +#include "opentelemetry/context/runtime_context.h" +#include "opentelemetry/exporters/memory/in_memory_span_exporter.h" +#include "opentelemetry/nostd/shared_ptr.h" +#include "opentelemetry/nostd/span.h" +#include "opentelemetry/nostd/string_view.h" +#include "opentelemetry/nostd/variant.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/tracer.h" +#include "opentelemetry/sdk/trace/tracer_context.h" +#include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/default_span.h" +#include "opentelemetry/trace/noop.h" +#include "opentelemetry/trace/scope.h" +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/span_startoptions.h" +#include "opentelemetry/trace/trace_flags.h" +#include "opentelemetry/trace/trace_id.h" +#include "opentelemetry/trace/tracer.h" + +namespace trace_api = opentelemetry::trace; +namespace trace_sdk = opentelemetry::sdk::trace; +namespace scope_sdk = opentelemetry::sdk::instrumentationscope; +namespace nostd = opentelemetry::nostd; +namespace context = opentelemetry::context; +using opentelemetry::exporter::memory::InMemorySpanExporter; + +namespace +{ + +constexpr std::size_t kStartSpanBatchSize = 2048; + +std::shared_ptr CreateTracer(bool is_enabled = true) +{ + auto exporter = std::make_unique(kStartSpanBatchSize); + auto processor = std::make_unique(std::move(exporter)); + std::vector> processors; + processors.push_back(std::move(processor)); + auto resource = opentelemetry::sdk::resource::Resource::Create({}); + auto context = std::make_shared(std::move(processors), resource); + + if (!is_enabled) + { + auto disabled_config = std::make_unique>( + scope_sdk::ScopeConfigurator::Builder( + trace_sdk::TracerConfig::Disabled()) + .Build()); + context->SetTracerConfigurator(std::move(disabled_config)); + } + auto tracer = std::make_shared(context); + + return tracer; +} + +// Test to measure performance for span creation +void BM_StartSpanTracerDisabled(benchmark::State &state) +{ + auto tracer = CreateTracer(false); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + span->End(); + } +} +BENCHMARK(BM_StartSpanTracerDisabled); + +// Test to measure performance for span creation +void BM_StartSpan(benchmark::State &state) +{ + auto tracer = CreateTracer(); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + span->End(); + } +} +BENCHMARK(BM_StartSpan); + +// Test to measure performance for single span creation with scope +void BM_StartSpanWithScope(benchmark::State &state) +{ + auto tracer = CreateTracer(); + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + trace_api::Scope scope{span}; + span->End(); + } +} +BENCHMARK(BM_StartSpanWithScope); + +// Test to measure performance for nested span creation with scope +void BM_StartSpanWithImplicitParent(benchmark::State &state) +{ + auto tracer = CreateTracer(); + auto parent_span = tracer->StartSpan("parent"); + trace_api::Scope parent_scope{parent_span}; + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + span->End(); + } +} + +BENCHMARK(BM_StartSpanWithImplicitParent); + +// Test to measure performance for nested span creation with manual span context management +void BM_StartSpanWithExplicitParentContext(benchmark::State &state) +{ + auto tracer = CreateTracer(); + + auto parent_span = tracer->StartSpan("parent"); + + auto init_context = context::Context{}; + auto parent_context = trace_api::SetSpan(init_context, parent_span); + + while (state.KeepRunning()) + { + trace_api::StartSpanOptions options; + options.parent = parent_context; + auto span = tracer->StartSpan("span", options); + span->End(); + } +} +BENCHMARK(BM_StartSpanWithExplicitParentContext); + +void BM_StartSpanWithExplicitRootContext(benchmark::State &state) +{ + auto tracer = CreateTracer(); + + auto root_context = context::Context{trace_api::kIsRootSpanKey, true}; + + while (state.KeepRunning()) + { + trace_api::StartSpanOptions options; + options.parent = root_context; + auto span = tracer->StartSpan("span", options); + span->End(); + } +} +BENCHMARK(BM_StartSpanWithExplicitRootContext); + +} // namespace +BENCHMARK_MAIN(); From 9746077ea226751d5d8813ad2bd5d4c07ca5dc5f Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 20:43:07 -0400 Subject: [PATCH 02/17] Performance optimizations for SDK Tracer::StartSpan --- .../opentelemetry/trace/span_startoptions.h | 2 +- sdk/include/opentelemetry/sdk/trace/sampler.h | 4 +- sdk/include/opentelemetry/sdk/trace/tracer.h | 1 + sdk/src/trace/span.cc | 10 +- sdk/src/trace/span.h | 9 +- sdk/src/trace/tracer.cc | 242 ++++++++++++------ sdk/test/trace/sampler_benchmark.cc | 72 +++--- sdk/test/trace/tracer_benchmark.cc | 52 ++-- sdk/test/trace/tracer_test.cc | 31 +-- 9 files changed, 239 insertions(+), 184 deletions(-) diff --git a/api/include/opentelemetry/trace/span_startoptions.h b/api/include/opentelemetry/trace/span_startoptions.h index 8a2165b0f0..ca4d73128a 100644 --- a/api/include/opentelemetry/trace/span_startoptions.h +++ b/api/include/opentelemetry/trace/span_startoptions.h @@ -59,7 +59,7 @@ struct StartSpanOptions // - If the `parent` field is not set, the newly created Span will inherit the // parent of the currently active Span (if any) in the current context. // - nostd::variant parent = SpanContext::GetInvalid(); + nostd::variant parent = context::Context{}; // TODO: // SpanContext remote_parent; diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 888a44383b..6aabeac0e6 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -58,11 +58,11 @@ struct SamplingResult // The tracestate used by the span. nostd::shared_ptr trace_state; - inline bool IsRecording() + inline bool IsRecording() const { return decision == Decision::RECORD_ONLY || decision == Decision::RECORD_AND_SAMPLE; } - inline bool IsSampled() { return decision == Decision::RECORD_AND_SAMPLE; } + inline bool IsSampled() const { return decision == Decision::RECORD_AND_SAMPLE; } }; /** diff --git a/sdk/include/opentelemetry/sdk/trace/tracer.h b/sdk/include/opentelemetry/sdk/trace/tracer.h index dcaf683395..b782e15c5d 100644 --- a/sdk/include/opentelemetry/sdk/trace/tracer.h +++ b/sdk/include/opentelemetry/sdk/trace/tracer.h @@ -137,6 +137,7 @@ class Tracer final : public opentelemetry::trace::Tracer, #if OPENTELEMETRY_ABI_VERSION_NO < 2 std::atomic is_enabled_{false}; #endif + nostd::shared_ptr noop_span_; }; } // namespace trace } // namespace sdk diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index d764540875..e971442af3 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -56,7 +56,7 @@ Span::Span(std::shared_ptr &&tracer, const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, const opentelemetry::trace::SpanContext &parent_span_context, - std::unique_ptr span_context) noexcept + opentelemetry::trace::SpanContext span_context) noexcept : tracer_{std::move(tracer)}, recordable_{tracer_->GetProcessor().MakeRecordable()}, start_steady_time{options.start_steady_time}, @@ -68,11 +68,11 @@ Span::Span(std::shared_ptr &&tracer, } recordable_->SetName(name); recordable_->SetInstrumentationScope(tracer_->GetInstrumentationScope()); - recordable_->SetIdentity(*span_context_, parent_span_context.IsValid() - ? parent_span_context.span_id() - : opentelemetry::trace::SpanId()); + recordable_->SetIdentity(span_context_, parent_span_context.IsValid() + ? parent_span_context.span_id() + : opentelemetry::trace::SpanId()); - recordable_->SetTraceFlags(span_context_->trace_flags()); + recordable_->SetTraceFlags(span_context_.trace_flags()); attributes.ForEachKeyValue([&](nostd::string_view key, common::AttributeValue value) noexcept { recordable_->SetAttribute(key, value); diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index 2a5614821d..772d12feb0 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -32,7 +32,7 @@ class Span final : public opentelemetry::trace::Span const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, const opentelemetry::trace::SpanContext &parent_span_context, - std::unique_ptr span_context) noexcept; + opentelemetry::trace::SpanContext span_context) noexcept; Span(const Span &) = delete; Span(Span &&) = delete; @@ -73,17 +73,14 @@ class Span final : public opentelemetry::trace::Span bool IsRecording() const noexcept override; - opentelemetry::trace::SpanContext GetContext() const noexcept override - { - return *span_context_.get(); - } + opentelemetry::trace::SpanContext GetContext() const noexcept override { return span_context_; } private: std::shared_ptr tracer_; mutable std::mutex mu_; std::unique_ptr recordable_; opentelemetry::common::SteadyTimestamp start_steady_time; - std::unique_ptr span_context_; + opentelemetry::trace::SpanContext span_context_; bool has_ended_{false}; }; } // namespace trace diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index b0f0e593e8..e5e49f25fb 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -30,6 +30,7 @@ #include "opentelemetry/trace/trace_state.h" #include "opentelemetry/version.h" +#include "src/trace/non_recording_span.h" #include "src/trace/span.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -37,11 +38,82 @@ namespace sdk { namespace trace { + +namespace +{ + +nostd::shared_ptr MakeNonRecordingSpan( + opentelemetry::trace::SpanContext &&span_context) +{ +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + return {std::make_shared(std::move(span_context))}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (const std::bad_alloc &) + { + return {}; + } +#else + return nostd::shared_ptr{ + new (std::nothrow) NonRecordingSpan{std::move(span_context)}}; +#endif +} + +nostd::shared_ptr MakeSpan(std::shared_ptr &&tracer, + nostd::string_view name, + const opentelemetry::common::KeyValueIterable &attributes, + const opentelemetry::trace::SpanContextKeyValueIterable &links, + const opentelemetry::trace::StartSpanOptions &options, + const opentelemetry::trace::SpanContext &parent_context, + opentelemetry::trace::SpanContext &&span_context) +{ +#if OPENTELEMETRY_HAVE_EXCEPTIONS + try + { +#endif + return {std::make_shared(std::move(tracer), name, attributes, links, options, + parent_context, std::move(span_context))}; +#if OPENTELEMETRY_HAVE_EXCEPTIONS + } + catch (const std::bad_alloc &) + { + return {}; + } +#else + return nostd::shared_ptr{ + new (std::nothrow) Span{std::move(tracer), name, attributes, links, options, parent_context, + std::move(span_context)}}; +#endif +} + +opentelemetry::trace::SpanContext GetSpanContext(const context::Context &context) noexcept +{ + const context::ContextValue span_value = context.GetValue(opentelemetry::trace::kSpanKey); + if (const nostd::shared_ptr *span = + nostd::get_if>(&span_value)) + { + return (*span)->GetContext(); + } + else if (const nostd::shared_ptr *span_context = + nostd::get_if>(&span_value)) + { + return *(*span_context); + } + return opentelemetry::trace::SpanContext::GetInvalid(); +}; + +} // namespace + Tracer::Tracer(std::shared_ptr context, std::unique_ptr instrumentation_scope) noexcept : instrumentation_scope_{std::move(instrumentation_scope)}, context_{std::move(context)}, - tracer_config_(context_->GetTracerConfigurator().ComputeConfig(*instrumentation_scope_)) + tracer_config_(context_->GetTracerConfigurator().ComputeConfig(*instrumentation_scope_)), + noop_span_{ + std::make_shared(opentelemetry::trace::SpanContext::GetInvalid())} { UpdateEnabled(tracer_config_.IsEnabled()); } @@ -55,77 +127,66 @@ nostd::shared_ptr Tracer::StartSpan( // Check if the tracer is enabled using the API Tracer::Enabled() accessor if available. if (!Enabled()) { - static const std::shared_ptr kNoopTracer = - std::make_shared(); - return kNoopTracer->StartSpan(name, attributes, links, options); + return noop_span_; } - // make sure to always overwrite this parent_context - bool get_current_context = true; - opentelemetry::trace::SpanContext parent_context(false, false); - if (const opentelemetry::trace::SpanContext *span_context = - nostd::get_if(&options.parent)) - { - if (span_context->IsValid()) + // Resolve parent span context from options or fall back to the current runtime context. + const auto parent_context = [&options]() noexcept -> opentelemetry::trace::SpanContext { + // 1. If the parent is a valid SpanContext, use it directly. + // 2. If the parent is a Context with a span, extract the SpanContext. + // 3. If the parent is a Context with the `is_root_span` flag set, return an invalid + // SpanContext. + // 4. If the parent is not provided, use the current runtime context to get the SpanContext. + if (const auto *span_context = + nostd::get_if(&options.parent)) { - parent_context = *span_context; - get_current_context = false; - } - } - else if (const context::Context *context = nostd::get_if(&options.parent)) - { - // fetch span context from parent span stored in the context - auto parent_span_context = opentelemetry::trace::GetSpan(*context)->GetContext(); - if (parent_span_context.IsValid()) - { - parent_context = parent_span_context; - get_current_context = false; + if (span_context->IsValid()) + { + return *span_context; + } } - else + else if (const auto *context = nostd::get_if(&options.parent)) { - if (opentelemetry::trace::IsRootSpan(*context)) + if (context->HasKey(opentelemetry::trace::kSpanKey)) { - get_current_context = false; + return GetSpanContext(*context); + } + else if (opentelemetry::trace::IsRootSpan(*context)) + { + return opentelemetry::trace::SpanContext::GetInvalid(); } } - } + return GetSpanContext(opentelemetry::context::RuntimeContext::GetCurrent()); + }(); - if (get_current_context) - { - parent_context = GetCurrentSpan()->GetContext(); - } + IdGenerator &generator = GetIdGenerator(); + const opentelemetry::trace::SpanId span_id = generator.GenerateSpanId(); + const opentelemetry::trace::TraceId trace_id = + parent_context.IsValid() ? parent_context.trace_id() : generator.GenerateTraceId(); - IdGenerator &generator = GetIdGenerator(); - opentelemetry::trace::TraceId trace_id; - opentelemetry::trace::SpanId span_id = generator.GenerateSpanId(); - bool is_parent_span_valid = false; - uint8_t flags = 0; + const auto sampling_result = context_->GetSampler().ShouldSample(parent_context, trace_id, name, + options.kind, attributes, links); - if (parent_context.IsValid()) - { - trace_id = parent_context.trace_id(); - flags = parent_context.trace_flags().flags(); - is_parent_span_valid = true; - } - else - { - trace_id = generator.GenerateTraceId(); - if (generator.IsRandom()) + const opentelemetry::trace::TraceFlags trace_flags = + [&]() noexcept -> opentelemetry::trace::TraceFlags { + uint8_t flags = 0; + if (parent_context.IsValid()) + { + flags = parent_context.trace_flags().flags(); + } + else if (generator.IsRandom()) { flags = opentelemetry::trace::TraceFlags::kIsRandom; } - } - auto sampling_result = context_->GetSampler().ShouldSample(parent_context, trace_id, name, - options.kind, attributes, links); - if (sampling_result.IsSampled()) - { - flags |= opentelemetry::trace::TraceFlags::kIsSampled; - } - else - { - flags &= ~opentelemetry::trace::TraceFlags::kIsSampled; - } + if (sampling_result.IsSampled()) + { + flags |= opentelemetry::trace::TraceFlags::kIsSampled; + } + else + { + flags &= ~opentelemetry::trace::TraceFlags::kIsSampled; + } #if 0 /* https://github.com/open-telemetry/opentelemetry-specification as of v1.29.0 */ @@ -134,47 +195,58 @@ nostd::shared_ptr Tracer::StartSpan( #endif #if 1 - /* Waiting for https://github.com/open-telemetry/opentelemetry-specification/issues/3411 */ - /* Support W3C Trace Context version 2. */ - flags &= opentelemetry::trace::TraceFlags::kAllW3CTraceContext2Flags; + /* Waiting for https://github.com/open-telemetry/opentelemetry-specification/issues/3411 */ + /* Support W3C Trace Context version 2. */ + flags &= opentelemetry::trace::TraceFlags::kAllW3CTraceContext2Flags; #endif - opentelemetry::trace::TraceFlags trace_flags(flags); + return opentelemetry::trace::TraceFlags(flags); + }(); - auto span_context = - std::unique_ptr(new opentelemetry::trace::SpanContext( - trace_id, span_id, trace_flags, false, - sampling_result.trace_state ? sampling_result.trace_state - : is_parent_span_valid ? parent_context.trace_state() - : opentelemetry::trace::TraceState::GetDefault())); + const auto get_trace_state = + [&sampling_result, &parent_context]() -> nostd::shared_ptr { + if (sampling_result.trace_state) + { + return sampling_result.trace_state; + } + if (parent_context.IsValid()) + { + return parent_context.trace_state(); + } + return opentelemetry::trace::TraceState::GetDefault(); + }; + + opentelemetry::trace::SpanContext span_context(trace_id, span_id, trace_flags, false, + get_trace_state()); if (!sampling_result.IsRecording()) { - // create no-op span with valid span-context. + auto non_recording_span = MakeNonRecordingSpan(std::move(span_context)); - auto noop_span = nostd::shared_ptr{ - new (std::nothrow) - opentelemetry::trace::NoopSpan(this->shared_from_this(), std::move(span_context))}; - return noop_span; + if (non_recording_span) + { + return non_recording_span; + } + return noop_span_; } - else - { - auto span = nostd::shared_ptr{ - new (std::nothrow) Span{this->shared_from_this(), name, attributes, links, options, - parent_context, std::move(span_context)}}; + auto span = MakeSpan(shared_from_this(), name, attributes, links, options, parent_context, + std::move(span_context)); + if (!span) + { + return noop_span_; + } - // if the attributes is not nullptr, add attributes to the span. - if (sampling_result.attributes) + // if the attributes is not nullptr, add attributes to the span. + if (sampling_result.attributes) + { + for (auto &kv : *sampling_result.attributes) { - for (auto &kv : *sampling_result.attributes) - { - span->SetAttribute(kv.first, kv.second); - } + span->SetAttribute(kv.first, kv.second); } - - return span; } + + return span; } void Tracer::ForceFlushWithMicroseconds(uint64_t timeout) noexcept diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index b6177f39ce..d88c5c30a9 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -3,52 +3,52 @@ // clang-format off // -// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-15T00:31:56+00:00 +// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-15T00:38:10+00:00 // Running /home/devuser/build/sdk/test/trace/sampler_benchmark -// Run on (32 X 5700 MHz CPU s) +// Run on (32 X 800 MHz CPU s) // CPU Caches: // L1 Data 48 KiB (x16) // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 7.64, 4.23, 2.79 +// Load Average: 3.12, 3.63, 2.94 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. // ----------------------------------------------------------------------------------------- // Benchmark Time CPU Iterations // ----------------------------------------------------------------------------------------- -// BM_AlwaysOffSamplerConstruction_mean 0.339 ns 0.338 ns 5 -// BM_AlwaysOffSamplerConstruction_median 0.338 ns 0.338 ns 5 -// BM_AlwaysOffSamplerConstruction_stddev 0.002 ns 0.002 ns 5 -// BM_AlwaysOffSamplerConstruction_cv 0.53 % 0.53 % 5 -// BM_AlwaysOnSamplerConstruction_mean 0.337 ns 0.337 ns 5 -// BM_AlwaysOnSamplerConstruction_median 0.337 ns 0.337 ns 5 -// BM_AlwaysOnSamplerConstruction_stddev 0.002 ns 0.002 ns 5 -// BM_AlwaysOnSamplerConstruction_cv 0.46 % 0.47 % 5 -// BM_AlwaysOffSamplerShouldSample_mean 4.18 ns 4.18 ns 5 -// BM_AlwaysOffSamplerShouldSample_median 4.17 ns 4.17 ns 5 -// BM_AlwaysOffSamplerShouldSample_stddev 0.031 ns 0.031 ns 5 -// BM_AlwaysOffSamplerShouldSample_cv 0.73 % 0.73 % 5 -// BM_AlwaysOnSamplerShouldSample_mean 4.33 ns 4.33 ns 5 -// BM_AlwaysOnSamplerShouldSample_median 4.33 ns 4.33 ns 5 -// BM_AlwaysOnSamplerShouldSample_stddev 0.049 ns 0.049 ns 5 -// BM_AlwaysOnSamplerShouldSample_cv 1.13 % 1.13 % 5 -// BM_ParentBasedSamplerShouldSample_mean 7.07 ns 7.07 ns 5 -// BM_ParentBasedSamplerShouldSample_median 7.06 ns 7.06 ns 5 -// BM_ParentBasedSamplerShouldSample_stddev 0.022 ns 0.022 ns 5 -// BM_ParentBasedSamplerShouldSample_cv 0.32 % 0.32 % 5 -// BM_TraceIdRatioBasedSamplerShouldSample_mean 3.94 ns 3.94 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_median 3.94 ns 3.94 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.012 ns 0.012 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.31 % 0.31 % 5 -// BM_SpanCreation_mean 235 ns 235 ns 5 -// BM_SpanCreation_median 235 ns 235 ns 5 -// BM_SpanCreation_stddev 0.616 ns 0.607 ns 5 -// BM_SpanCreation_cv 0.26 % 0.26 % 5 -// BM_NoopSpanCreation_mean 59.3 ns 59.3 ns 5 -// BM_NoopSpanCreation_median 59.2 ns 59.2 ns 5 -// BM_NoopSpanCreation_stddev 0.421 ns 0.422 ns 5 -// BM_NoopSpanCreation_cv 0.71 % 0.71 % 5 +// BM_AlwaysOffSamplerConstruction_mean 0.340 ns 0.340 ns 5 +// BM_AlwaysOffSamplerConstruction_median 0.340 ns 0.340 ns 5 +// BM_AlwaysOffSamplerConstruction_stddev 0.001 ns 0.001 ns 5 +// BM_AlwaysOffSamplerConstruction_cv 0.36 % 0.36 % 5 +// BM_AlwaysOnSamplerConstruction_mean 0.343 ns 0.343 ns 5 +// BM_AlwaysOnSamplerConstruction_median 0.342 ns 0.342 ns 5 +// BM_AlwaysOnSamplerConstruction_stddev 0.006 ns 0.006 ns 5 +// BM_AlwaysOnSamplerConstruction_cv 1.78 % 1.78 % 5 +// BM_AlwaysOffSamplerShouldSample_mean 4.12 ns 4.12 ns 5 +// BM_AlwaysOffSamplerShouldSample_median 4.12 ns 4.12 ns 5 +// BM_AlwaysOffSamplerShouldSample_stddev 0.015 ns 0.015 ns 5 +// BM_AlwaysOffSamplerShouldSample_cv 0.37 % 0.37 % 5 +// BM_AlwaysOnSamplerShouldSample_mean 4.28 ns 4.28 ns 5 +// BM_AlwaysOnSamplerShouldSample_median 4.28 ns 4.27 ns 5 +// BM_AlwaysOnSamplerShouldSample_stddev 0.022 ns 0.022 ns 5 +// BM_AlwaysOnSamplerShouldSample_cv 0.52 % 0.51 % 5 +// BM_ParentBasedSamplerShouldSample_mean 7.11 ns 7.10 ns 5 +// BM_ParentBasedSamplerShouldSample_median 7.08 ns 7.08 ns 5 +// BM_ParentBasedSamplerShouldSample_stddev 0.086 ns 0.087 ns 5 +// BM_ParentBasedSamplerShouldSample_cv 1.22 % 1.22 % 5 +// BM_TraceIdRatioBasedSamplerShouldSample_mean 4.01 ns 4.00 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_median 4.00 ns 4.00 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.032 ns 0.032 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.80 % 0.80 % 5 +// BM_SpanCreation_mean 205 ns 205 ns 5 +// BM_SpanCreation_median 205 ns 205 ns 5 +// BM_SpanCreation_stddev 0.998 ns 0.993 ns 5 +// BM_SpanCreation_cv 0.49 % 0.48 % 5 +// BM_NoopSpanCreation_mean 27.7 ns 27.7 ns 5 +// BM_NoopSpanCreation_median 27.7 ns 27.7 ns 5 +// BM_NoopSpanCreation_stddev 0.136 ns 0.137 ns 5 +// BM_NoopSpanCreation_cv 0.49 % 0.49 % 5 // // clang-format on diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc index b1f6a95c5c..f2bd565986 100644 --- a/sdk/test/trace/tracer_benchmark.cc +++ b/sdk/test/trace/tracer_benchmark.cc @@ -4,7 +4,7 @@ // clang-format off // // ~/build/sdk/test/trace/tracer_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-15T00:33:53+00:00 +// 2026-07-15T00:37:18+00:00 // Running /home/devuser/build/sdk/test/trace/tracer_benchmark // Run on (32 X 5700 MHz CPU s) // CPU Caches: @@ -12,35 +12,35 @@ // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 2.44, 3.34, 2.63 +// Load Average: 3.34, 3.81, 2.96 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. // --------------------------------------------------------------------------------------- // Benchmark Time CPU Iterations // --------------------------------------------------------------------------------------- -// BM_StartSpanTracerDisabled_mean 6.85 ns 6.85 ns 5 -// BM_StartSpanTracerDisabled_median 6.84 ns 6.84 ns 5 -// BM_StartSpanTracerDisabled_stddev 0.025 ns 0.023 ns 5 -// BM_StartSpanTracerDisabled_cv 0.36 % 0.34 % 5 -// BM_StartSpan_mean 187 ns 187 ns 5 -// BM_StartSpan_median 187 ns 187 ns 5 -// BM_StartSpan_stddev 1.22 ns 1.23 ns 5 -// BM_StartSpan_cv 0.65 % 0.66 % 5 -// BM_StartSpanWithScope_mean 255 ns 255 ns 5 -// BM_StartSpanWithScope_median 255 ns 255 ns 5 -// BM_StartSpanWithScope_stddev 1.09 ns 1.11 ns 5 -// BM_StartSpanWithScope_cv 0.43 % 0.44 % 5 -// BM_StartSpanWithImplicitParent_mean 172 ns 172 ns 5 -// BM_StartSpanWithImplicitParent_median 172 ns 172 ns 5 -// BM_StartSpanWithImplicitParent_stddev 0.447 ns 0.447 ns 5 -// BM_StartSpanWithImplicitParent_cv 0.26 % 0.26 % 5 -// BM_StartSpanWithExplicitParentContext_mean 173 ns 173 ns 5 -// BM_StartSpanWithExplicitParentContext_median 173 ns 173 ns 5 -// BM_StartSpanWithExplicitParentContext_stddev 0.343 ns 0.337 ns 5 -// BM_StartSpanWithExplicitParentContext_cv 0.20 % 0.20 % 5 -// BM_StartSpanWithExplicitRootContext_mean 187 ns 187 ns 5 -// BM_StartSpanWithExplicitRootContext_median 187 ns 187 ns 5 -// BM_StartSpanWithExplicitRootContext_stddev 0.679 ns 0.666 ns 5 -// BM_StartSpanWithExplicitRootContext_cv 0.36 % 0.36 % 5 +// BM_StartSpanTracerDisabled_mean 5.24 ns 5.24 ns 5 +// BM_StartSpanTracerDisabled_median 5.24 ns 5.24 ns 5 +// BM_StartSpanTracerDisabled_stddev 0.046 ns 0.047 ns 5 +// BM_StartSpanTracerDisabled_cv 0.89 % 0.89 % 5 +// BM_StartSpan_mean 152 ns 152 ns 5 +// BM_StartSpan_median 152 ns 152 ns 5 +// BM_StartSpan_stddev 2.74 ns 2.74 ns 5 +// BM_StartSpan_cv 1.80 % 1.80 % 5 +// BM_StartSpanWithScope_mean 218 ns 218 ns 5 +// BM_StartSpanWithScope_median 217 ns 217 ns 5 +// BM_StartSpanWithScope_stddev 1.75 ns 1.75 ns 5 +// BM_StartSpanWithScope_cv 0.80 % 0.81 % 5 +// BM_StartSpanWithImplicitParent_mean 153 ns 153 ns 5 +// BM_StartSpanWithImplicitParent_median 153 ns 153 ns 5 +// BM_StartSpanWithImplicitParent_stddev 0.802 ns 0.800 ns 5 +// BM_StartSpanWithImplicitParent_cv 0.52 % 0.52 % 5 +// BM_StartSpanWithExplicitParentContext_mean 154 ns 154 ns 5 +// BM_StartSpanWithExplicitParentContext_median 154 ns 154 ns 5 +// BM_StartSpanWithExplicitParentContext_stddev 0.898 ns 0.899 ns 5 +// BM_StartSpanWithExplicitParentContext_cv 0.58 % 0.58 % 5 +// BM_StartSpanWithExplicitRootContext_mean 148 ns 148 ns 5 +// BM_StartSpanWithExplicitRootContext_median 148 ns 148 ns 5 +// BM_StartSpanWithExplicitRootContext_stddev 0.686 ns 0.688 ns 5 +// BM_StartSpanWithExplicitRootContext_cv 0.46 % 0.47 % 5 // // clang-format on diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 8a2fbcd5fd..c73ac30276 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -589,13 +589,9 @@ TEST(Tracer, StartSpanWithDisabledConfig) new RandomIdGenerator(), disable_tracer); auto span = tracer->StartSpan("span 1"); - std::shared_ptr noop_tracer = - std::make_shared(); - auto noop_span = noop_tracer->StartSpan("noop"); - EXPECT_TRUE(span.get() == noop_span.get()); + EXPECT_FALSE(span->IsRecording()); #if OPENTELEMETRY_ABI_VERSION_NO >= 2 - EXPECT_FALSE(noop_tracer->Enabled()); EXPECT_FALSE(tracer->Enabled()); #endif } @@ -610,22 +606,15 @@ TEST(Tracer, StartSpanWithEnabledConfig) new RandomIdGenerator(), enable_tracer); auto span = tracer->StartSpan("span 1"); - std::shared_ptr noop_tracer = - std::make_shared(); - auto noop_span = noop_tracer->StartSpan("noop"); - EXPECT_FALSE(span.get() == noop_span.get()); + EXPECT_TRUE(span->IsRecording()); #if OPENTELEMETRY_ABI_VERSION_NO >= 2 - EXPECT_FALSE(noop_tracer->Enabled()); EXPECT_TRUE(tracer->Enabled()); #endif } TEST(Tracer, StartSpanWithCustomConfig) { - std::shared_ptr noop_tracer = - std::make_shared(); - auto noop_span = noop_tracer->StartSpan("noop"); auto check_if_version_present = [](const InstrumentationScope &scope_info) { return !scope_info.GetVersion().empty(); }; @@ -640,31 +629,30 @@ TEST(Tracer, StartSpanWithCustomConfig) initTracer(std::unique_ptr{new InMemorySpanExporter()}, new AlwaysOnSampler(), new RandomIdGenerator(), custom_configurator); const auto span_default_scope = tracer_default_scope->StartSpan("span 1"); - EXPECT_TRUE(span_default_scope == noop_span); + EXPECT_FALSE(span_default_scope->IsRecording()); auto foo_scope = InstrumentationScope::Create("foo_library"); const auto tracer_foo_scope = initTracer(std::unique_ptr{new InMemorySpanExporter()}, new AlwaysOnSampler(), new RandomIdGenerator(), custom_configurator, std::move(foo_scope)); const auto span_foo_scope = tracer_foo_scope->StartSpan("span 1"); - EXPECT_TRUE(span_foo_scope == noop_span); + EXPECT_FALSE(span_foo_scope->IsRecording()); auto foo_scope_with_version = InstrumentationScope::Create("foo_library", "1.0.0"); const auto tracer_foo_scope_with_version = initTracer(std::unique_ptr{new InMemorySpanExporter()}, new AlwaysOnSampler(), new RandomIdGenerator(), custom_configurator, std::move(foo_scope_with_version)); const auto span_foo_scope_with_version = tracer_foo_scope_with_version->StartSpan("span 1"); - EXPECT_FALSE(span_foo_scope_with_version == noop_span); + EXPECT_TRUE(span_foo_scope_with_version->IsRecording()); auto bar_scope = InstrumentationScope::Create("bar_library"); auto tracer_bar_scope = initTracer(std::unique_ptr{new InMemorySpanExporter()}, new AlwaysOnSampler(), new RandomIdGenerator(), custom_configurator, std::move(bar_scope)); auto span_bar_scope = tracer_bar_scope->StartSpan("span 1"); - EXPECT_FALSE(span_bar_scope == noop_span); + EXPECT_TRUE(span_bar_scope->IsRecording()); #if OPENTELEMETRY_ABI_VERSION_NO >= 2 - EXPECT_FALSE(noop_tracer->Enabled()); EXPECT_FALSE(tracer_default_scope->Enabled()); EXPECT_FALSE(tracer_foo_scope->Enabled()); EXPECT_TRUE(tracer_foo_scope_with_version->Enabled()); @@ -674,9 +662,6 @@ TEST(Tracer, StartSpanWithCustomConfig) TEST(Tracer, StartSpanWithCustomConfigDifferingConditionOrder) { - std::shared_ptr noop_tracer = - std::make_shared(); - auto noop_span = noop_tracer->StartSpan("noop"); auto check_if_version_present = [](const InstrumentationScope &scope_info) { return !scope_info.GetVersion().empty(); }; @@ -705,12 +690,12 @@ TEST(Tracer, StartSpanWithCustomConfigDifferingConditionOrder) // Custom configurator 1 evaluates version first and enables the tracer const auto span_foo_scope_with_version_1 = tracer_foo_scope_with_version_1->StartSpan("span 1"); - EXPECT_FALSE(span_foo_scope_with_version_1 == noop_span); + EXPECT_TRUE(span_foo_scope_with_version_1->IsRecording()); // Custom configurator 2 evaluates the name first and therefore disables the tracer without // evaluating other condition const auto span_foo_scope_with_version_2 = tracer_foo_scope_with_version_2->StartSpan("span 1"); - EXPECT_TRUE(span_foo_scope_with_version_2 == noop_span); + EXPECT_FALSE(span_foo_scope_with_version_2->IsRecording()); #if OPENTELEMETRY_ABI_VERSION_NO >= 2 EXPECT_TRUE(tracer_foo_scope_with_version_1->Enabled()); From e472646cf74af894541260c3cf47669f956b3fb9 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 20:51:55 -0400 Subject: [PATCH 03/17] fix iwyu warnings and cleanup --- sdk/src/trace/tracer.cc | 8 ++++++-- sdk/test/trace/tracer_benchmark.cc | 17 +++++++++-------- sdk/test/trace/tracer_test.cc | 1 - 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index e5e49f25fb..c496086f42 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -8,7 +8,10 @@ #include #include +#include "opentelemetry/common/key_value_iterable.h" #include "opentelemetry/context/context.h" +#include "opentelemetry/context/context_value.h" +#include "opentelemetry/context/runtime_context.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/variant.h" @@ -20,10 +23,11 @@ #include "opentelemetry/sdk/trace/tracer_config.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/trace/context.h" -#include "opentelemetry/trace/noop.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_context_kv_iterable.h" #include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/span_metadata.h" #include "opentelemetry/trace/span_startoptions.h" #include "opentelemetry/trace/trace_flags.h" #include "opentelemetry/trace/trace_id.h" @@ -169,7 +173,7 @@ nostd::shared_ptr Tracer::StartSpan( const opentelemetry::trace::TraceFlags trace_flags = [&]() noexcept -> opentelemetry::trace::TraceFlags { - uint8_t flags = 0; + std::uint8_t flags = 0; if (parent_context.IsValid()) { flags = parent_context.trace_flags().flags(); diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc index f2bd565986..8194647699 100644 --- a/sdk/test/trace/tracer_benchmark.cc +++ b/sdk/test/trace/tracer_benchmark.cc @@ -45,28 +45,29 @@ // clang-format on #include -#include + +#include +#include +#include #include "opentelemetry/context/context.h" -#include "opentelemetry/context/runtime_context.h" #include "opentelemetry/exporters/memory/in_memory_span_exporter.h" #include "opentelemetry/nostd/shared_ptr.h" -#include "opentelemetry/nostd/span.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/nostd/variant.h" +#include "opentelemetry/sdk/instrumentationscope/scope_configurator.h" +#include "opentelemetry/sdk/resource/resource.h" +#include "opentelemetry/sdk/trace/processor.h" #include "opentelemetry/sdk/trace/simple_processor.h" #include "opentelemetry/sdk/trace/tracer.h" +#include "opentelemetry/sdk/trace/tracer_config.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/trace/context.h" -#include "opentelemetry/trace/default_span.h" -#include "opentelemetry/trace/noop.h" #include "opentelemetry/trace/scope.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" -#include "opentelemetry/trace/span_id.h" +#include "opentelemetry/trace/span_metadata.h" #include "opentelemetry/trace/span_startoptions.h" -#include "opentelemetry/trace/trace_flags.h" -#include "opentelemetry/trace/trace_id.h" #include "opentelemetry/trace/tracer.h" namespace trace_api = opentelemetry::trace; diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index c73ac30276..6497c6b006 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -42,7 +42,6 @@ #include "opentelemetry/sdk/trace/tracer_config.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/trace/context.h" -#include "opentelemetry/trace/noop.h" #include "opentelemetry/trace/scope.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" From 21926797ca413acca13b578f122f0b77a33ec0ca Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 21:09:47 -0400 Subject: [PATCH 04/17] fix clang-tidy warnings and clean up --- sdk/include/opentelemetry/sdk/trace/sampler.h | 4 ++-- sdk/src/trace/tracer.cc | 4 ++-- sdk/test/trace/tracer_benchmark.cc | 1 - sdk/test/trace/tracer_test.cc | 4 ++-- 4 files changed, 6 insertions(+), 7 deletions(-) diff --git a/sdk/include/opentelemetry/sdk/trace/sampler.h b/sdk/include/opentelemetry/sdk/trace/sampler.h index 6aabeac0e6..b9afc00024 100644 --- a/sdk/include/opentelemetry/sdk/trace/sampler.h +++ b/sdk/include/opentelemetry/sdk/trace/sampler.h @@ -58,11 +58,11 @@ struct SamplingResult // The tracestate used by the span. nostd::shared_ptr trace_state; - inline bool IsRecording() const + inline bool IsRecording() const noexcept { return decision == Decision::RECORD_ONLY || decision == Decision::RECORD_AND_SAMPLE; } - inline bool IsSampled() const { return decision == Decision::RECORD_AND_SAMPLE; } + inline bool IsSampled() const noexcept { return decision == Decision::RECORD_AND_SAMPLE; } }; /** diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index c496086f42..5be816b0ef 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -47,7 +47,7 @@ namespace { nostd::shared_ptr MakeNonRecordingSpan( - opentelemetry::trace::SpanContext &&span_context) + opentelemetry::trace::SpanContext &&span_context) noexcept { #if OPENTELEMETRY_HAVE_EXCEPTIONS try @@ -72,7 +72,7 @@ nostd::shared_ptr MakeSpan(std::shared_ptr &&tracer, const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, const opentelemetry::trace::SpanContext &parent_context, - opentelemetry::trace::SpanContext &&span_context) + opentelemetry::trace::SpanContext &&span_context) noexcept { #if OPENTELEMETRY_HAVE_EXCEPTIONS try diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc index 8194647699..13a88c4088 100644 --- a/sdk/test/trace/tracer_benchmark.cc +++ b/sdk/test/trace/tracer_benchmark.cc @@ -73,7 +73,6 @@ namespace trace_api = opentelemetry::trace; namespace trace_sdk = opentelemetry::sdk::trace; namespace scope_sdk = opentelemetry::sdk::instrumentationscope; -namespace nostd = opentelemetry::nostd; namespace context = opentelemetry::context; using opentelemetry::exporter::memory::InMemorySpanExporter; diff --git a/sdk/test/trace/tracer_test.cc b/sdk/test/trace/tracer_test.cc index 6497c6b006..5725fbd63b 100644 --- a/sdk/test/trace/tracer_test.cc +++ b/sdk/test/trace/tracer_test.cc @@ -65,6 +65,8 @@ using opentelemetry::exporter::memory::InMemorySpanData; using opentelemetry::exporter::memory::InMemorySpanExporter; using opentelemetry::trace::SpanContext; +namespace +{ /** * A mock sampler with ShouldSample returning: * Decision::RECORD_AND_SAMPLE if trace_id is valid @@ -169,8 +171,6 @@ class MockIdGenerator : public IdGenerator uint8_t buf_trace[16] = {1, 2, 3, 4, 5, 6, 7, 8, 8, 7, 6, 5, 4, 3, 2, 1}; }; -namespace -{ std::shared_ptr initTracer(std::unique_ptr &&exporter) { auto processor = std::unique_ptr(new SimpleSpanProcessor(std::move(exporter))); From f3f6d01b056a8bfd5388c0c26935028c0c7401f5 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 21:26:15 -0400 Subject: [PATCH 05/17] fix noexcept build --- sdk/src/trace/tracer.cc | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 5be816b0ef..5c63920301 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -46,7 +46,7 @@ namespace trace namespace { -nostd::shared_ptr MakeNonRecordingSpan( +nostd::shared_ptr MakeNonRecordingSpan( opentelemetry::trace::SpanContext &&span_context) noexcept { #if OPENTELEMETRY_HAVE_EXCEPTIONS @@ -62,17 +62,18 @@ nostd::shared_ptr MakeNonRecordingSpan( } #else return nostd::shared_ptr{ - new (std::nothrow) NonRecordingSpan{std::move(span_context)}}; + new (std::nothrow) NonRecordingSpan(std::move(span_context))}; #endif } -nostd::shared_ptr MakeSpan(std::shared_ptr &&tracer, - nostd::string_view name, - const opentelemetry::common::KeyValueIterable &attributes, - const opentelemetry::trace::SpanContextKeyValueIterable &links, - const opentelemetry::trace::StartSpanOptions &options, - const opentelemetry::trace::SpanContext &parent_context, - opentelemetry::trace::SpanContext &&span_context) noexcept +nostd::shared_ptr MakeSpan( + std::shared_ptr &&tracer, + nostd::string_view name, + const opentelemetry::common::KeyValueIterable &attributes, + const opentelemetry::trace::SpanContextKeyValueIterable &links, + const opentelemetry::trace::StartSpanOptions &options, + const opentelemetry::trace::SpanContext &parent_context, + opentelemetry::trace::SpanContext &&span_context) noexcept { #if OPENTELEMETRY_HAVE_EXCEPTIONS try From 84cab3c26cb2bc50fb98ee605e600f341309b79b Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 21:38:33 -0400 Subject: [PATCH 06/17] add missing file --- sdk/src/trace/non_recording_span.h | 80 ++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 sdk/src/trace/non_recording_span.h diff --git a/sdk/src/trace/non_recording_span.h b/sdk/src/trace/non_recording_span.h new file mode 100644 index 0000000000..755afef1e9 --- /dev/null +++ b/sdk/src/trace/non_recording_span.h @@ -0,0 +1,80 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "opentelemetry/trace/span.h" +#include "opentelemetry/trace/span_context.h" +#include "opentelemetry/version.h" + +OPENTELEMETRY_BEGIN_NAMESPACE +namespace sdk +{ +namespace trace +{ + +/** + * A non-recording span used when a span is not sampled. + */ +class NonRecordingSpan final : public opentelemetry::trace::Span +{ +public: + explicit NonRecordingSpan(opentelemetry::trace::SpanContext context) noexcept + : context_(std::move(context)) + {} + + NonRecordingSpan(const NonRecordingSpan &) = delete; + NonRecordingSpan(NonRecordingSpan &&) = delete; + NonRecordingSpan &operator=(const NonRecordingSpan &) = delete; + NonRecordingSpan &operator=(NonRecordingSpan &&) = delete; + + ~NonRecordingSpan() override = default; + + void SetAttribute(opentelemetry::nostd::string_view /*key*/, + const opentelemetry::common::AttributeValue & /*value*/) noexcept override + {} + + void AddEvent(opentelemetry::nostd::string_view /*name*/) noexcept override {} + + void AddEvent(opentelemetry::nostd::string_view /*name*/, + opentelemetry::common::SystemTimestamp /*timestamp*/) noexcept override + {} + + void AddEvent(opentelemetry::nostd::string_view /*name*/, + const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept override + {} + + void AddEvent(opentelemetry::nostd::string_view /*name*/, + opentelemetry::common::SystemTimestamp /*timestamp*/, + const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept override + {} + +#if OPENTELEMETRY_ABI_VERSION_NO >= 2 + void AddLink(const opentelemetry::trace::SpanContext & /*target*/, + const opentelemetry::common::KeyValueIterable & /*attrs*/) noexcept override + {} + + void AddLinks( + const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override + {} +#endif + + void SetStatus(opentelemetry::trace::StatusCode /*code*/, + opentelemetry::nostd::string_view /*description*/) noexcept override + {} + + void UpdateName(opentelemetry::nostd::string_view /*name*/) noexcept override {} + + void End(const opentelemetry::trace::EndSpanOptions & /*options*/ = {}) noexcept override {} + + bool IsRecording() const noexcept override { return false; } + + opentelemetry::trace::SpanContext GetContext() const noexcept override { return context_; } + +private: + opentelemetry::trace::SpanContext context_; +}; + +} // namespace trace +} // namespace sdk +OPENTELEMETRY_END_NAMESPACE From 9caf2806e46936e8189d1f1ab2cc2f860593a796 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Tue, 14 Jul 2026 21:57:12 -0400 Subject: [PATCH 07/17] fix opentracing shim test after default value of the parent context in span start options changed --- opentracing-shim/test/shim_utils_test.cc | 8 ++++---- sdk/src/trace/tracer.cc | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/opentracing-shim/test/shim_utils_test.cc b/opentracing-shim/test/shim_utils_test.cc index 84a76b906d..4db8fd7727 100644 --- a/opentracing-shim/test/shim_utils_test.cc +++ b/opentracing-shim/test/shim_utils_test.cc @@ -41,6 +41,7 @@ namespace trace_api = opentelemetry::trace; namespace baggage = opentelemetry::baggage; namespace common = opentelemetry::common; +namespace context = opentelemetry::context; namespace nostd = opentelemetry::nostd; namespace shim = opentelemetry::opentracingshim; @@ -138,8 +139,7 @@ TEST(ShimUtilsTest, MakeOptionsShim_EmptyRefs) common::SystemTimestamp{options.start_system_timestamp}); ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); - ASSERT_EQ(nostd::get(options_shim.parent), - trace_api::SpanContext::GetInvalid()); + ASSERT_FALSE(nostd::get(options_shim.parent).HasKey(trace_api::kSpanKey)); } TEST(ShimUtilsTest, MakeOptionsShim_InvalidSpanContext) @@ -154,8 +154,8 @@ TEST(ShimUtilsTest, MakeOptionsShim_InvalidSpanContext) common::SystemTimestamp{options.start_system_timestamp}); ASSERT_EQ(options_shim.start_steady_time, common::SteadyTimestamp{options.start_steady_timestamp}); - ASSERT_EQ(nostd::get(options_shim.parent), - trace_api::SpanContext::GetInvalid()); + + ASSERT_FALSE(nostd::get(options_shim.parent).HasKey(trace_api::kSpanKey)); } TEST(ShimUtilsTest, MakeOptionsShim_FirstChildOf) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 5c63920301..a72250b32e 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -108,7 +108,7 @@ opentelemetry::trace::SpanContext GetSpanContext(const context::Context &context return *(*span_context); } return opentelemetry::trace::SpanContext::GetInvalid(); -}; +} } // namespace From b0140b21d12efec75642719557efe2ae3af9e2a1 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Wed, 15 Jul 2026 09:39:33 -0400 Subject: [PATCH 08/17] The DefaultSpan is a non-recording span, use it in tracer.cc and delete the NonRecordingSpan. Fix iwyu warnings. Cleanup --- .../opentelemetry/trace/default_span.h | 3 +- opentracing-shim/test/shim_utils_test.cc | 4 +- sdk/src/trace/non_recording_span.h | 80 ------------------- sdk/src/trace/tracer.cc | 20 ++--- 4 files changed, 10 insertions(+), 97 deletions(-) delete mode 100644 sdk/src/trace/non_recording_span.h diff --git a/api/include/opentelemetry/trace/default_span.h b/api/include/opentelemetry/trace/default_span.h index a6e7b1d6b8..3eb909ca5a 100644 --- a/api/include/opentelemetry/trace/default_span.h +++ b/api/include/opentelemetry/trace/default_span.h @@ -14,7 +14,7 @@ namespace trace { /** - * DefaultSpan provides a non-operational Span that propagates + * DefaultSpan provides a non-recording Span that propagates * the tracer context by wrapping it inside the Span object. */ @@ -28,6 +28,7 @@ class DefaultSpan : public Span trace::SpanContext GetContext() const noexcept override { return span_context_; } + // Returns false, as DefaultSpan is a non-recording span. bool IsRecording() const noexcept override { return false; } void SetAttribute(nostd::string_view /* key */, diff --git a/opentracing-shim/test/shim_utils_test.cc b/opentracing-shim/test/shim_utils_test.cc index 4db8fd7727..cd53ff48b5 100644 --- a/opentracing-shim/test/shim_utils_test.cc +++ b/opentracing-shim/test/shim_utils_test.cc @@ -26,6 +26,7 @@ #include "opentelemetry/common/attribute_value.h" #include "opentelemetry/common/key_value_iterable.h" #include "opentelemetry/common/timestamp.h" +#include "opentelemetry/context/context.h" #include "opentelemetry/context/runtime_context.h" #include "opentelemetry/nostd/function_ref.h" #include "opentelemetry/nostd/shared_ptr.h" @@ -34,10 +35,9 @@ #include "opentelemetry/opentracingshim/shim_utils.h" #include "opentelemetry/opentracingshim/span_context_shim.h" #include "opentelemetry/trace/span_context.h" +#include "opentelemetry/trace/span_metadata.h" #include "opentelemetry/trace/span_startoptions.h" -#include "shim_mocks.h" - namespace trace_api = opentelemetry::trace; namespace baggage = opentelemetry::baggage; namespace common = opentelemetry::common; diff --git a/sdk/src/trace/non_recording_span.h b/sdk/src/trace/non_recording_span.h deleted file mode 100644 index 755afef1e9..0000000000 --- a/sdk/src/trace/non_recording_span.h +++ /dev/null @@ -1,80 +0,0 @@ -// Copyright The OpenTelemetry Authors -// SPDX-License-Identifier: Apache-2.0 - -#pragma once - -#include "opentelemetry/trace/span.h" -#include "opentelemetry/trace/span_context.h" -#include "opentelemetry/version.h" - -OPENTELEMETRY_BEGIN_NAMESPACE -namespace sdk -{ -namespace trace -{ - -/** - * A non-recording span used when a span is not sampled. - */ -class NonRecordingSpan final : public opentelemetry::trace::Span -{ -public: - explicit NonRecordingSpan(opentelemetry::trace::SpanContext context) noexcept - : context_(std::move(context)) - {} - - NonRecordingSpan(const NonRecordingSpan &) = delete; - NonRecordingSpan(NonRecordingSpan &&) = delete; - NonRecordingSpan &operator=(const NonRecordingSpan &) = delete; - NonRecordingSpan &operator=(NonRecordingSpan &&) = delete; - - ~NonRecordingSpan() override = default; - - void SetAttribute(opentelemetry::nostd::string_view /*key*/, - const opentelemetry::common::AttributeValue & /*value*/) noexcept override - {} - - void AddEvent(opentelemetry::nostd::string_view /*name*/) noexcept override {} - - void AddEvent(opentelemetry::nostd::string_view /*name*/, - opentelemetry::common::SystemTimestamp /*timestamp*/) noexcept override - {} - - void AddEvent(opentelemetry::nostd::string_view /*name*/, - const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept override - {} - - void AddEvent(opentelemetry::nostd::string_view /*name*/, - opentelemetry::common::SystemTimestamp /*timestamp*/, - const opentelemetry::common::KeyValueIterable & /*attributes*/) noexcept override - {} - -#if OPENTELEMETRY_ABI_VERSION_NO >= 2 - void AddLink(const opentelemetry::trace::SpanContext & /*target*/, - const opentelemetry::common::KeyValueIterable & /*attrs*/) noexcept override - {} - - void AddLinks( - const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override - {} -#endif - - void SetStatus(opentelemetry::trace::StatusCode /*code*/, - opentelemetry::nostd::string_view /*description*/) noexcept override - {} - - void UpdateName(opentelemetry::nostd::string_view /*name*/) noexcept override {} - - void End(const opentelemetry::trace::EndSpanOptions & /*options*/ = {}) noexcept override {} - - bool IsRecording() const noexcept override { return false; } - - opentelemetry::trace::SpanContext GetContext() const noexcept override { return context_; } - -private: - opentelemetry::trace::SpanContext context_; -}; - -} // namespace trace -} // namespace sdk -OPENTELEMETRY_END_NAMESPACE diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index a72250b32e..2112bc5980 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -1,8 +1,8 @@ // Copyright The OpenTelemetry Authors // SPDX-License-Identifier: Apache-2.0 -#include #include +#include #include #include #include @@ -23,6 +23,7 @@ #include "opentelemetry/sdk/trace/tracer_config.h" #include "opentelemetry/sdk/trace/tracer_context.h" #include "opentelemetry/trace/context.h" +#include "opentelemetry/trace/default_span.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_context_kv_iterable.h" @@ -34,7 +35,6 @@ #include "opentelemetry/trace/trace_state.h" #include "opentelemetry/version.h" -#include "src/trace/non_recording_span.h" #include "src/trace/span.h" OPENTELEMETRY_BEGIN_NAMESPACE @@ -53,7 +53,7 @@ nostd::shared_ptr MakeNonRecordingSpan( try { #endif - return {std::make_shared(std::move(span_context))}; + return {std::make_shared(std::move(span_context))}; #if OPENTELEMETRY_HAVE_EXCEPTIONS } catch (const std::bad_alloc &) @@ -62,7 +62,7 @@ nostd::shared_ptr MakeNonRecordingSpan( } #else return nostd::shared_ptr{ - new (std::nothrow) NonRecordingSpan(std::move(span_context))}; + new (std::nothrow) opentelemetry::trace::DefaultSpan(std::move(span_context))}; #endif } @@ -117,8 +117,8 @@ Tracer::Tracer(std::shared_ptr context, : instrumentation_scope_{std::move(instrumentation_scope)}, context_{std::move(context)}, tracer_config_(context_->GetTracerConfigurator().ComputeConfig(*instrumentation_scope_)), - noop_span_{ - std::make_shared(opentelemetry::trace::SpanContext::GetInvalid())} + noop_span_{std::make_shared( + opentelemetry::trace::SpanContext::GetInvalid())} { UpdateEnabled(tracer_config_.IsEnabled()); } @@ -193,17 +193,9 @@ nostd::shared_ptr Tracer::StartSpan( flags &= ~opentelemetry::trace::TraceFlags::kIsSampled; } -#if 0 - /* https://github.com/open-telemetry/opentelemetry-specification as of v1.29.0 */ - /* Support W3C Trace Context version 1. */ - flags &= opentelemetry::trace::TraceFlags::kAllW3CTraceContext1Flags; -#endif - -#if 1 /* Waiting for https://github.com/open-telemetry/opentelemetry-specification/issues/3411 */ /* Support W3C Trace Context version 2. */ flags &= opentelemetry::trace::TraceFlags::kAllW3CTraceContext2Flags; -#endif return opentelemetry::trace::TraceFlags(flags); }(); From 38a0f603f31849f0052aa7e1bd228af178fc33bb Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Wed, 15 Jul 2026 11:17:41 -0400 Subject: [PATCH 09/17] Set the in memory span exporter buffer to 0 for the tracer benchmark for more consistent results --- sdk/test/trace/tracer_benchmark.cc | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc index 13a88c4088..7277811863 100644 --- a/sdk/test/trace/tracer_benchmark.cc +++ b/sdk/test/trace/tracer_benchmark.cc @@ -79,11 +79,14 @@ using opentelemetry::exporter::memory::InMemorySpanExporter; namespace { -constexpr std::size_t kStartSpanBatchSize = 2048; - std::shared_ptr CreateTracer(bool is_enabled = true) { - auto exporter = std::make_unique(kStartSpanBatchSize); + // Set the batch size to 0 so the InMemorySpanExporter's circular buffer has a capcity of 1 and + // rejects the span from the first iteration. This will force destruction of the span in the + // timing loop consistently. + constexpr std::size_t kExporterBufferSize = 0; + + auto exporter = std::make_unique(kExporterBufferSize); auto processor = std::make_unique(std::move(exporter)); std::vector> processors; processors.push_back(std::move(processor)); From 4bde64c4de6f35886ace408ad8c3b07ceef241eb Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Wed, 15 Jul 2026 12:55:07 -0400 Subject: [PATCH 10/17] add changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3c57ff6451..02e52c1d7f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,9 @@ Increment the: ## [Unreleased] +* [SDK] Add Tracer::StartSpan benchmark and optimizations + [#4248](https://github.com/open-telemetry/opentelemetry-cpp/pull/4248) + * [SDK] Apply metric cardinality limits to non-overflow attribute sets and reserve the overflow point separately. [#4236](https://github.com/open-telemetry/opentelemetry-cpp/pull/4236) From 067c2b38515a1036508df57a0e490f2a6a43fd77 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Fri, 17 Jul 2026 13:33:17 -0400 Subject: [PATCH 11/17] use the api GetSpanContext in StartSpan. Get only one ContextValue per call of GetSpanContext by removing the call to HasKey since it gets a context value anyways --- api/include/opentelemetry/trace/context.h | 7 ++++--- sdk/src/trace/tracer.cc | 25 ++++++----------------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/api/include/opentelemetry/trace/context.h b/api/include/opentelemetry/trace/context.h index 90ef5adc41..a55b63b515 100644 --- a/api/include/opentelemetry/trace/context.h +++ b/api/include/opentelemetry/trace/context.h @@ -27,13 +27,14 @@ inline nostd::shared_ptr GetSpan(const context::Context &context) noexcept // stored directly in the context, and returns an invalid SpanContext if neither is present. inline SpanContext GetSpanContext(const context::Context &context) noexcept { - if (!context.HasKey(kSpanKey)) + const context::ContextValue context_value = context.GetValue(kSpanKey); + + if (nostd::holds_alternative(context_value)) { + // The context does not have a span or span context return SpanContext::GetInvalid(); } - const context::ContextValue context_value = context.GetValue(kSpanKey); - // Get the span metadata from the active span in the context. if (const nostd::shared_ptr *maybe_span = nostd::get_if>(&context_value)) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 2112bc5980..fd141de17d 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -94,22 +94,6 @@ nostd::shared_ptr MakeSpan( #endif } -opentelemetry::trace::SpanContext GetSpanContext(const context::Context &context) noexcept -{ - const context::ContextValue span_value = context.GetValue(opentelemetry::trace::kSpanKey); - if (const nostd::shared_ptr *span = - nostd::get_if>(&span_value)) - { - return (*span)->GetContext(); - } - else if (const nostd::shared_ptr *span_context = - nostd::get_if>(&span_value)) - { - return *(*span_context); - } - return opentelemetry::trace::SpanContext::GetInvalid(); -} - } // namespace Tracer::Tracer(std::shared_ptr context, @@ -152,16 +136,19 @@ nostd::shared_ptr Tracer::StartSpan( } else if (const auto *context = nostd::get_if(&options.parent)) { - if (context->HasKey(opentelemetry::trace::kSpanKey)) + const auto ctx_span_context = opentelemetry::trace::GetSpanContext(*context); + if (ctx_span_context.IsValid()) { - return GetSpanContext(*context); + return ctx_span_context; } else if (opentelemetry::trace::IsRootSpan(*context)) { return opentelemetry::trace::SpanContext::GetInvalid(); } } - return GetSpanContext(opentelemetry::context::RuntimeContext::GetCurrent()); + + return opentelemetry::trace::GetSpanContext( + opentelemetry::context::RuntimeContext::GetCurrent()); }(); IdGenerator &generator = GetIdGenerator(); From ddb176b6ba55d8341760b504448ff8f2d9d6f7d6 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Fri, 17 Jul 2026 13:34:52 -0400 Subject: [PATCH 12/17] update results for the tracer and sampler benchmarks after merging in main --- sdk/test/trace/sampler_benchmark.cc | 70 ++++++++++++++--------------- sdk/test/trace/tracer_benchmark.cc | 50 ++++++++++----------- 2 files changed, 60 insertions(+), 60 deletions(-) diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index d88c5c30a9..4394e935e4 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -4,51 +4,51 @@ // clang-format off // // ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-15T00:38:10+00:00 +// 2026-07-17T17:28:24+00:00 // Running /home/devuser/build/sdk/test/trace/sampler_benchmark -// Run on (32 X 800 MHz CPU s) +// Run on (32 X 5700 MHz CPU s) // CPU Caches: // L1 Data 48 KiB (x16) // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 3.12, 3.63, 2.94 +// Load Average: 1.38, 4.38, 4.67 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. // ----------------------------------------------------------------------------------------- // Benchmark Time CPU Iterations // ----------------------------------------------------------------------------------------- -// BM_AlwaysOffSamplerConstruction_mean 0.340 ns 0.340 ns 5 -// BM_AlwaysOffSamplerConstruction_median 0.340 ns 0.340 ns 5 -// BM_AlwaysOffSamplerConstruction_stddev 0.001 ns 0.001 ns 5 -// BM_AlwaysOffSamplerConstruction_cv 0.36 % 0.36 % 5 -// BM_AlwaysOnSamplerConstruction_mean 0.343 ns 0.343 ns 5 -// BM_AlwaysOnSamplerConstruction_median 0.342 ns 0.342 ns 5 -// BM_AlwaysOnSamplerConstruction_stddev 0.006 ns 0.006 ns 5 -// BM_AlwaysOnSamplerConstruction_cv 1.78 % 1.78 % 5 -// BM_AlwaysOffSamplerShouldSample_mean 4.12 ns 4.12 ns 5 -// BM_AlwaysOffSamplerShouldSample_median 4.12 ns 4.12 ns 5 -// BM_AlwaysOffSamplerShouldSample_stddev 0.015 ns 0.015 ns 5 -// BM_AlwaysOffSamplerShouldSample_cv 0.37 % 0.37 % 5 -// BM_AlwaysOnSamplerShouldSample_mean 4.28 ns 4.28 ns 5 -// BM_AlwaysOnSamplerShouldSample_median 4.28 ns 4.27 ns 5 -// BM_AlwaysOnSamplerShouldSample_stddev 0.022 ns 0.022 ns 5 -// BM_AlwaysOnSamplerShouldSample_cv 0.52 % 0.51 % 5 -// BM_ParentBasedSamplerShouldSample_mean 7.11 ns 7.10 ns 5 -// BM_ParentBasedSamplerShouldSample_median 7.08 ns 7.08 ns 5 -// BM_ParentBasedSamplerShouldSample_stddev 0.086 ns 0.087 ns 5 -// BM_ParentBasedSamplerShouldSample_cv 1.22 % 1.22 % 5 -// BM_TraceIdRatioBasedSamplerShouldSample_mean 4.01 ns 4.00 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_median 4.00 ns 4.00 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.032 ns 0.032 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.80 % 0.80 % 5 -// BM_SpanCreation_mean 205 ns 205 ns 5 -// BM_SpanCreation_median 205 ns 205 ns 5 -// BM_SpanCreation_stddev 0.998 ns 0.993 ns 5 -// BM_SpanCreation_cv 0.49 % 0.48 % 5 -// BM_NoopSpanCreation_mean 27.7 ns 27.7 ns 5 -// BM_NoopSpanCreation_median 27.7 ns 27.7 ns 5 -// BM_NoopSpanCreation_stddev 0.136 ns 0.137 ns 5 -// BM_NoopSpanCreation_cv 0.49 % 0.49 % 5 +// BM_AlwaysOffSamplerConstruction_mean 0.351 ns 0.351 ns 5 +// BM_AlwaysOffSamplerConstruction_median 0.353 ns 0.353 ns 5 +// BM_AlwaysOffSamplerConstruction_stddev 0.005 ns 0.005 ns 5 +// BM_AlwaysOffSamplerConstruction_cv 1.55 % 1.55 % 5 +// BM_AlwaysOnSamplerConstruction_mean 0.338 ns 0.338 ns 5 +// BM_AlwaysOnSamplerConstruction_median 0.337 ns 0.337 ns 5 +// BM_AlwaysOnSamplerConstruction_stddev 0.003 ns 0.003 ns 5 +// BM_AlwaysOnSamplerConstruction_cv 0.76 % 0.76 % 5 +// BM_AlwaysOffSamplerShouldSample_mean 4.14 ns 4.14 ns 5 +// BM_AlwaysOffSamplerShouldSample_median 4.13 ns 4.13 ns 5 +// BM_AlwaysOffSamplerShouldSample_stddev 0.018 ns 0.018 ns 5 +// BM_AlwaysOffSamplerShouldSample_cv 0.43 % 0.42 % 5 +// BM_AlwaysOnSamplerShouldSample_mean 4.32 ns 4.31 ns 5 +// BM_AlwaysOnSamplerShouldSample_median 4.31 ns 4.31 ns 5 +// BM_AlwaysOnSamplerShouldSample_stddev 0.052 ns 0.052 ns 5 +// BM_AlwaysOnSamplerShouldSample_cv 1.20 % 1.20 % 5 +// BM_ParentBasedSamplerShouldSample_mean 7.13 ns 7.13 ns 5 +// BM_ParentBasedSamplerShouldSample_median 7.16 ns 7.16 ns 5 +// BM_ParentBasedSamplerShouldSample_stddev 0.061 ns 0.061 ns 5 +// BM_ParentBasedSamplerShouldSample_cv 0.86 % 0.85 % 5 +// BM_TraceIdRatioBasedSamplerShouldSample_mean 3.96 ns 3.96 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_median 3.97 ns 3.97 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.012 ns 0.012 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.30 % 0.31 % 5 +// BM_SpanCreation_mean 213 ns 213 ns 5 +// BM_SpanCreation_median 214 ns 214 ns 5 +// BM_SpanCreation_stddev 1.54 ns 1.54 ns 5 +// BM_SpanCreation_cv 0.72 % 0.72 % 5 +// BM_NoopSpanCreation_mean 30.7 ns 30.7 ns 5 +// BM_NoopSpanCreation_median 30.7 ns 30.7 ns 5 +// BM_NoopSpanCreation_stddev 0.206 ns 0.207 ns 5 +// BM_NoopSpanCreation_cv 0.67 % 0.67 % 5 // // clang-format on diff --git a/sdk/test/trace/tracer_benchmark.cc b/sdk/test/trace/tracer_benchmark.cc index 7277811863..3fafb7ce6e 100644 --- a/sdk/test/trace/tracer_benchmark.cc +++ b/sdk/test/trace/tracer_benchmark.cc @@ -3,8 +3,8 @@ // clang-format off // -// ~/build/sdk/test/trace/tracer_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-15T00:37:18+00:00 +// ~/build/sdk/test/trace/tracer_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-17T17:30:15+00:00 // Running /home/devuser/build/sdk/test/trace/tracer_benchmark // Run on (32 X 5700 MHz CPU s) // CPU Caches: @@ -12,35 +12,35 @@ // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 3.34, 3.81, 2.96 +// Load Average: 1.06, 3.28, 4.23 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. // --------------------------------------------------------------------------------------- // Benchmark Time CPU Iterations // --------------------------------------------------------------------------------------- -// BM_StartSpanTracerDisabled_mean 5.24 ns 5.24 ns 5 -// BM_StartSpanTracerDisabled_median 5.24 ns 5.24 ns 5 -// BM_StartSpanTracerDisabled_stddev 0.046 ns 0.047 ns 5 -// BM_StartSpanTracerDisabled_cv 0.89 % 0.89 % 5 -// BM_StartSpan_mean 152 ns 152 ns 5 -// BM_StartSpan_median 152 ns 152 ns 5 -// BM_StartSpan_stddev 2.74 ns 2.74 ns 5 -// BM_StartSpan_cv 1.80 % 1.80 % 5 -// BM_StartSpanWithScope_mean 218 ns 218 ns 5 -// BM_StartSpanWithScope_median 217 ns 217 ns 5 -// BM_StartSpanWithScope_stddev 1.75 ns 1.75 ns 5 -// BM_StartSpanWithScope_cv 0.80 % 0.81 % 5 -// BM_StartSpanWithImplicitParent_mean 153 ns 153 ns 5 -// BM_StartSpanWithImplicitParent_median 153 ns 153 ns 5 -// BM_StartSpanWithImplicitParent_stddev 0.802 ns 0.800 ns 5 -// BM_StartSpanWithImplicitParent_cv 0.52 % 0.52 % 5 +// BM_StartSpanTracerDisabled_mean 5.29 ns 5.29 ns 5 +// BM_StartSpanTracerDisabled_median 5.30 ns 5.30 ns 5 +// BM_StartSpanTracerDisabled_stddev 0.030 ns 0.030 ns 5 +// BM_StartSpanTracerDisabled_cv 0.58 % 0.57 % 5 +// BM_StartSpan_mean 158 ns 158 ns 5 +// BM_StartSpan_median 158 ns 158 ns 5 +// BM_StartSpan_stddev 1.56 ns 1.55 ns 5 +// BM_StartSpan_cv 0.99 % 0.98 % 5 +// BM_StartSpanWithScope_mean 225 ns 225 ns 5 +// BM_StartSpanWithScope_median 224 ns 224 ns 5 +// BM_StartSpanWithScope_stddev 2.61 ns 2.60 ns 5 +// BM_StartSpanWithScope_cv 1.16 % 1.16 % 5 +// BM_StartSpanWithImplicitParent_mean 160 ns 160 ns 5 +// BM_StartSpanWithImplicitParent_median 161 ns 161 ns 5 +// BM_StartSpanWithImplicitParent_stddev 1.93 ns 1.93 ns 5 +// BM_StartSpanWithImplicitParent_cv 1.20 % 1.20 % 5 // BM_StartSpanWithExplicitParentContext_mean 154 ns 154 ns 5 // BM_StartSpanWithExplicitParentContext_median 154 ns 154 ns 5 -// BM_StartSpanWithExplicitParentContext_stddev 0.898 ns 0.899 ns 5 -// BM_StartSpanWithExplicitParentContext_cv 0.58 % 0.58 % 5 -// BM_StartSpanWithExplicitRootContext_mean 148 ns 148 ns 5 -// BM_StartSpanWithExplicitRootContext_median 148 ns 148 ns 5 -// BM_StartSpanWithExplicitRootContext_stddev 0.686 ns 0.688 ns 5 -// BM_StartSpanWithExplicitRootContext_cv 0.46 % 0.47 % 5 +// BM_StartSpanWithExplicitParentContext_stddev 2.25 ns 2.25 ns 5 +// BM_StartSpanWithExplicitParentContext_cv 1.46 % 1.46 % 5 +// BM_StartSpanWithExplicitRootContext_mean 157 ns 157 ns 5 +// BM_StartSpanWithExplicitRootContext_median 157 ns 157 ns 5 +// BM_StartSpanWithExplicitRootContext_stddev 0.310 ns 0.301 ns 5 +// BM_StartSpanWithExplicitRootContext_cv 0.20 % 0.19 % 5 // // clang-format on From 2852840f1b42694b5f79fa091a88bcef41d91073 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Fri, 17 Jul 2026 13:39:07 -0400 Subject: [PATCH 13/17] fix iwyu warning --- sdk/src/trace/tracer.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index fd141de17d..348a0530b0 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -10,7 +10,6 @@ #include "opentelemetry/common/key_value_iterable.h" #include "opentelemetry/context/context.h" -#include "opentelemetry/context/context_value.h" #include "opentelemetry/context/runtime_context.h" #include "opentelemetry/nostd/shared_ptr.h" #include "opentelemetry/nostd/string_view.h" @@ -28,7 +27,6 @@ #include "opentelemetry/trace/span_context.h" #include "opentelemetry/trace/span_context_kv_iterable.h" #include "opentelemetry/trace/span_id.h" -#include "opentelemetry/trace/span_metadata.h" #include "opentelemetry/trace/span_startoptions.h" #include "opentelemetry/trace/trace_flags.h" #include "opentelemetry/trace/trace_id.h" From 3c6e1d0101425d8c23dee35f750fd46749b90fee Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Sat, 18 Jul 2026 10:48:24 -0400 Subject: [PATCH 14/17] add sampler benchmark to cover samplers that add attributes to the span --- sdk/test/trace/sampler_benchmark.cc | 147 +++++++++++++++++++++------- 1 file changed, 109 insertions(+), 38 deletions(-) diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index 4394e935e4..f1484af353 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -3,8 +3,8 @@ // clang-format off // -// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-17T17:28:24+00:00 +// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-18T13:33:22+00:00 // Running /home/devuser/build/sdk/test/trace/sampler_benchmark // Run on (32 X 5700 MHz CPU s) // CPU Caches: @@ -12,43 +12,59 @@ // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 1.38, 4.38, 4.67 +// Load Average: 0.93, 2.55, 2.62 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. -// ----------------------------------------------------------------------------------------- -// Benchmark Time CPU Iterations -// ----------------------------------------------------------------------------------------- -// BM_AlwaysOffSamplerConstruction_mean 0.351 ns 0.351 ns 5 -// BM_AlwaysOffSamplerConstruction_median 0.353 ns 0.353 ns 5 -// BM_AlwaysOffSamplerConstruction_stddev 0.005 ns 0.005 ns 5 -// BM_AlwaysOffSamplerConstruction_cv 1.55 % 1.55 % 5 -// BM_AlwaysOnSamplerConstruction_mean 0.338 ns 0.338 ns 5 -// BM_AlwaysOnSamplerConstruction_median 0.337 ns 0.337 ns 5 -// BM_AlwaysOnSamplerConstruction_stddev 0.003 ns 0.003 ns 5 -// BM_AlwaysOnSamplerConstruction_cv 0.76 % 0.76 % 5 -// BM_AlwaysOffSamplerShouldSample_mean 4.14 ns 4.14 ns 5 -// BM_AlwaysOffSamplerShouldSample_median 4.13 ns 4.13 ns 5 -// BM_AlwaysOffSamplerShouldSample_stddev 0.018 ns 0.018 ns 5 -// BM_AlwaysOffSamplerShouldSample_cv 0.43 % 0.42 % 5 -// BM_AlwaysOnSamplerShouldSample_mean 4.32 ns 4.31 ns 5 -// BM_AlwaysOnSamplerShouldSample_median 4.31 ns 4.31 ns 5 -// BM_AlwaysOnSamplerShouldSample_stddev 0.052 ns 0.052 ns 5 -// BM_AlwaysOnSamplerShouldSample_cv 1.20 % 1.20 % 5 -// BM_ParentBasedSamplerShouldSample_mean 7.13 ns 7.13 ns 5 -// BM_ParentBasedSamplerShouldSample_median 7.16 ns 7.16 ns 5 -// BM_ParentBasedSamplerShouldSample_stddev 0.061 ns 0.061 ns 5 -// BM_ParentBasedSamplerShouldSample_cv 0.86 % 0.85 % 5 -// BM_TraceIdRatioBasedSamplerShouldSample_mean 3.96 ns 3.96 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_median 3.97 ns 3.97 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.012 ns 0.012 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.30 % 0.31 % 5 -// BM_SpanCreation_mean 213 ns 213 ns 5 -// BM_SpanCreation_median 214 ns 214 ns 5 -// BM_SpanCreation_stddev 1.54 ns 1.54 ns 5 -// BM_SpanCreation_cv 0.72 % 0.72 % 5 -// BM_NoopSpanCreation_mean 30.7 ns 30.7 ns 5 -// BM_NoopSpanCreation_median 30.7 ns 30.7 ns 5 -// BM_NoopSpanCreation_stddev 0.206 ns 0.207 ns 5 -// BM_NoopSpanCreation_cv 0.67 % 0.67 % 5 +// ------------------------------------------------------------------------------------------------- +// Benchmark Time CPU Iterations +// ------------------------------------------------------------------------------------------------- +// BM_AlwaysOffSamplerConstruction_mean 0.345 ns 0.345 ns 5 +// BM_AlwaysOffSamplerConstruction_median 0.345 ns 0.345 ns 5 +// BM_AlwaysOffSamplerConstruction_stddev 0.003 ns 0.003 ns 5 +// BM_AlwaysOffSamplerConstruction_cv 0.78 % 0.77 % 5 +// BM_AlwaysOnSamplerConstruction_mean 0.339 ns 0.339 ns 5 +// BM_AlwaysOnSamplerConstruction_median 0.336 ns 0.336 ns 5 +// BM_AlwaysOnSamplerConstruction_stddev 0.008 ns 0.008 ns 5 +// BM_AlwaysOnSamplerConstruction_cv 2.33 % 2.32 % 5 +// BM_AlwaysOffSamplerShouldSample_mean 4.14 ns 4.14 ns 5 +// BM_AlwaysOffSamplerShouldSample_median 4.12 ns 4.12 ns 5 +// BM_AlwaysOffSamplerShouldSample_stddev 0.053 ns 0.053 ns 5 +// BM_AlwaysOffSamplerShouldSample_cv 1.29 % 1.28 % 5 +// BM_AlwaysOnSamplerShouldSample_mean 4.51 ns 4.51 ns 5 +// BM_AlwaysOnSamplerShouldSample_median 4.52 ns 4.52 ns 5 +// BM_AlwaysOnSamplerShouldSample_stddev 0.052 ns 0.052 ns 5 +// BM_AlwaysOnSamplerShouldSample_cv 1.16 % 1.15 % 5 +// BM_ParentBasedSamplerShouldSample_mean 7.42 ns 7.42 ns 5 +// BM_ParentBasedSamplerShouldSample_median 7.42 ns 7.41 ns 5 +// BM_ParentBasedSamplerShouldSample_stddev 0.011 ns 0.011 ns 5 +// BM_ParentBasedSamplerShouldSample_cv 0.15 % 0.15 % 5 +// BM_TraceIdRatioBasedSamplerShouldSample_mean 4.03 ns 4.03 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_median 4.03 ns 4.03 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.007 ns 0.007 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.18 % 0.19 % 5 +// BM_SpanCreation_mean 208 ns 208 ns 5 +// BM_SpanCreation_median 207 ns 207 ns 5 +// BM_SpanCreation_stddev 1.17 ns 1.18 ns 5 +// BM_SpanCreation_cv 0.57 % 0.57 % 5 +// BM_NoopSpanCreation_mean 30.0 ns 30.0 ns 5 +// BM_NoopSpanCreation_median 30.0 ns 30.0 ns 5 +// BM_NoopSpanCreation_stddev 0.048 ns 0.046 ns 5 +// BM_NoopSpanCreation_cv 0.16 % 0.15 % 5 +// BM_SpanCreationWithSamplingResultAttributes/0_mean 217 ns 217 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/0_median 216 ns 216 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/0_stddev 0.843 ns 0.850 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/0_cv 0.39 % 0.39 % 5 +// BM_SpanCreationWithSamplingResultAttributes/1_mean 257 ns 257 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_median 257 ns 257 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_stddev 0.649 ns 0.641 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_cv 0.25 % 0.25 % 5 +// BM_SpanCreationWithSamplingResultAttributes/10_mean 634 ns 633 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_median 628 ns 628 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_stddev 12.0 ns 12.0 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_cv 1.89 % 1.89 % 5 +// BM_SpanCreationWithSamplingResultAttributes/128_mean 8954 ns 8953 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_median 9197 ns 9196 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_stddev 381 ns 381 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_cv 4.26 % 4.25 % 5 // // clang-format on @@ -86,6 +102,8 @@ using namespace opentelemetry::sdk::trace; using opentelemetry::exporter::memory::InMemorySpanExporter; using opentelemetry::trace::SpanContext; +namespace nostd = opentelemetry::nostd; + namespace { // Sampler constructor used as a baseline to compare with other samplers @@ -229,5 +247,58 @@ void BM_NoopSpanCreation(benchmark::State &state) } BENCHMARK(BM_NoopSpanCreation); +namespace +{ +class AttributeContributingSampler : public Sampler +{ +public: + AttributeContributingSampler(std::size_t num_attributes) + : attributes_(CreateAttributes(num_attributes)) + {} + + static std::map CreateAttributes( + std::size_t num_attributes) + { + auto attributes_map = std::map(); + for (std::size_t i = 0; i < num_attributes; ++i) + { + attributes_map.emplace("attr" + std::to_string(i), static_cast(i)); + } + return attributes_map; + } + + SamplingResult ShouldSample( + const opentelemetry::trace::SpanContext & /*parent_context*/, + opentelemetry::trace::TraceId /*trace_id*/, + nostd::string_view /*name*/, + opentelemetry::trace::SpanKind /*span_kind*/, + const opentelemetry::common::KeyValueIterable & /*attributes*/, + const opentelemetry::trace::SpanContextKeyValueIterable & /*links*/) noexcept override + { + return SamplingResult{ + Decision::RECORD_AND_SAMPLE, + std::make_unique>(attributes_), + {}}; + } + + nostd::string_view GetDescription() const noexcept override + { + return "AttributeContributingSampler"; + } + +private: + std::map attributes_; +}; +} // namespace + +// Test to measure performance for a sampler that adds attributes to the span +void BM_SpanCreationWithSamplingResultAttributes(benchmark::State &state) +{ + std::size_t num_attributes = static_cast(state.range(0)); + std::unique_ptr sampler(new AttributeContributingSampler(num_attributes)); + BenchmarkSpanCreation(std::move(sampler), state); +} +BENCHMARK(BM_SpanCreationWithSamplingResultAttributes)->Arg(1)->Arg(10)->Arg(128); + } // namespace BENCHMARK_MAIN(); From 2e4263481c2d0a709e808860f015ddc821b3a52e Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Sat, 18 Jul 2026 11:03:26 -0400 Subject: [PATCH 15/17] pass sampling result to the SDK Span constructor in order to add attributes from the sampler. cleanup --- sdk/src/trace/span.cc | 9 +++ sdk/src/trace/span.h | 1 + sdk/src/trace/tracer.cc | 24 +++----- sdk/test/trace/sampler_benchmark.cc | 96 ++++++++++++++--------------- 4 files changed, 63 insertions(+), 67 deletions(-) diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index ef1295e0e8..6f2ba790d4 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -55,6 +55,7 @@ Span::Span(std::shared_ptr &&tracer, const common::KeyValueIterable &attributes, const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, + const opentelemetry::sdk::trace::SamplingResult &sampling_result, const opentelemetry::trace::SpanContext &parent_span_context, opentelemetry::trace::SpanContext span_context) noexcept : tracer_{std::move(tracer)}, @@ -86,6 +87,14 @@ Span::Span(std::shared_ptr &&tracer, return true; }); + if (sampling_result.attributes != nullptr) + { + for (const auto &kv : *sampling_result.attributes) + { + recordable_->SetAttribute(kv.first, kv.second); + } + } + recordable_->SetSpanKind(options.kind); recordable_->SetStartTime(NowOr(options.start_system_time)); start_steady_time = NowOr(options.start_steady_time); diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index 772d12feb0..ea071c1274 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -31,6 +31,7 @@ class Span final : public opentelemetry::trace::Span const opentelemetry::common::KeyValueIterable &attributes, const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, + const opentelemetry::sdk::trace::SamplingResult &sampling_result, const opentelemetry::trace::SpanContext &parent_span_context, opentelemetry::trace::SpanContext span_context) noexcept; diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 348a0530b0..f6b3f6ba6b 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -70,6 +70,7 @@ nostd::shared_ptr MakeSpan( const opentelemetry::common::KeyValueIterable &attributes, const opentelemetry::trace::SpanContextKeyValueIterable &links, const opentelemetry::trace::StartSpanOptions &options, + const opentelemetry::sdk::trace::SamplingResult &sampling_result, const opentelemetry::trace::SpanContext &parent_context, opentelemetry::trace::SpanContext &&span_context) noexcept { @@ -78,7 +79,7 @@ nostd::shared_ptr MakeSpan( { #endif return {std::make_shared(std::move(tracer), name, attributes, links, options, - parent_context, std::move(span_context))}; + sampling_result, parent_context, std::move(span_context))}; #if OPENTELEMETRY_HAVE_EXCEPTIONS } catch (const std::bad_alloc &) @@ -178,7 +179,6 @@ nostd::shared_ptr Tracer::StartSpan( flags &= ~opentelemetry::trace::TraceFlags::kIsSampled; } - /* Waiting for https://github.com/open-telemetry/opentelemetry-specification/issues/3411 */ /* Support W3C Trace Context version 2. */ flags &= opentelemetry::trace::TraceFlags::kAllW3CTraceContext2Flags; @@ -205,29 +205,19 @@ nostd::shared_ptr Tracer::StartSpan( { auto non_recording_span = MakeNonRecordingSpan(std::move(span_context)); - if (non_recording_span) + if (!non_recording_span) { - return non_recording_span; + return noop_span_; } - return noop_span_; + return non_recording_span; } - auto span = MakeSpan(shared_from_this(), name, attributes, links, options, parent_context, - std::move(span_context)); + auto span = MakeSpan(shared_from_this(), name, attributes, links, options, sampling_result, + parent_context, std::move(span_context)); if (!span) { return noop_span_; } - - // if the attributes is not nullptr, add attributes to the span. - if (sampling_result.attributes) - { - for (auto &kv : *sampling_result.attributes) - { - span->SetAttribute(kv.first, kv.second); - } - } - return span; } diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index f1484af353..9d89d56c01 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -3,8 +3,8 @@ // clang-format off // -// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true -// 2026-07-18T13:33:22+00:00 +// ~/build/sdk/test/trace/sampler_benchmark --benchmark_repetitions=5 --benchmark_display_aggregates_only=true +// 2026-07-18T14:58:59+00:00 // Running /home/devuser/build/sdk/test/trace/sampler_benchmark // Run on (32 X 5700 MHz CPU s) // CPU Caches: @@ -12,59 +12,55 @@ // L1 Instruction 32 KiB (x16) // L2 Unified 2048 KiB (x16) // L3 Unified 36864 KiB (x1) -// Load Average: 0.93, 2.55, 2.62 +// Load Average: 0.76, 1.44, 1.40 // ***WARNING*** ASLR is enabled, the results may have unreproducible noise in them. // ------------------------------------------------------------------------------------------------- // Benchmark Time CPU Iterations // ------------------------------------------------------------------------------------------------- -// BM_AlwaysOffSamplerConstruction_mean 0.345 ns 0.345 ns 5 -// BM_AlwaysOffSamplerConstruction_median 0.345 ns 0.345 ns 5 -// BM_AlwaysOffSamplerConstruction_stddev 0.003 ns 0.003 ns 5 -// BM_AlwaysOffSamplerConstruction_cv 0.78 % 0.77 % 5 -// BM_AlwaysOnSamplerConstruction_mean 0.339 ns 0.339 ns 5 -// BM_AlwaysOnSamplerConstruction_median 0.336 ns 0.336 ns 5 -// BM_AlwaysOnSamplerConstruction_stddev 0.008 ns 0.008 ns 5 -// BM_AlwaysOnSamplerConstruction_cv 2.33 % 2.32 % 5 +// BM_AlwaysOffSamplerConstruction_mean 0.336 ns 0.336 ns 5 +// BM_AlwaysOffSamplerConstruction_median 0.335 ns 0.335 ns 5 +// BM_AlwaysOffSamplerConstruction_stddev 0.001 ns 0.001 ns 5 +// BM_AlwaysOffSamplerConstruction_cv 0.32 % 0.32 % 5 +// BM_AlwaysOnSamplerConstruction_mean 0.335 ns 0.335 ns 5 +// BM_AlwaysOnSamplerConstruction_median 0.335 ns 0.335 ns 5 +// BM_AlwaysOnSamplerConstruction_stddev 0.001 ns 0.001 ns 5 +// BM_AlwaysOnSamplerConstruction_cv 0.20 % 0.20 % 5 // BM_AlwaysOffSamplerShouldSample_mean 4.14 ns 4.14 ns 5 -// BM_AlwaysOffSamplerShouldSample_median 4.12 ns 4.12 ns 5 -// BM_AlwaysOffSamplerShouldSample_stddev 0.053 ns 0.053 ns 5 -// BM_AlwaysOffSamplerShouldSample_cv 1.29 % 1.28 % 5 -// BM_AlwaysOnSamplerShouldSample_mean 4.51 ns 4.51 ns 5 -// BM_AlwaysOnSamplerShouldSample_median 4.52 ns 4.52 ns 5 -// BM_AlwaysOnSamplerShouldSample_stddev 0.052 ns 0.052 ns 5 -// BM_AlwaysOnSamplerShouldSample_cv 1.16 % 1.15 % 5 -// BM_ParentBasedSamplerShouldSample_mean 7.42 ns 7.42 ns 5 -// BM_ParentBasedSamplerShouldSample_median 7.42 ns 7.41 ns 5 -// BM_ParentBasedSamplerShouldSample_stddev 0.011 ns 0.011 ns 5 -// BM_ParentBasedSamplerShouldSample_cv 0.15 % 0.15 % 5 -// BM_TraceIdRatioBasedSamplerShouldSample_mean 4.03 ns 4.03 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_median 4.03 ns 4.03 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.007 ns 0.007 ns 5 -// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.18 % 0.19 % 5 -// BM_SpanCreation_mean 208 ns 208 ns 5 -// BM_SpanCreation_median 207 ns 207 ns 5 -// BM_SpanCreation_stddev 1.17 ns 1.18 ns 5 -// BM_SpanCreation_cv 0.57 % 0.57 % 5 -// BM_NoopSpanCreation_mean 30.0 ns 30.0 ns 5 -// BM_NoopSpanCreation_median 30.0 ns 30.0 ns 5 -// BM_NoopSpanCreation_stddev 0.048 ns 0.046 ns 5 -// BM_NoopSpanCreation_cv 0.16 % 0.15 % 5 -// BM_SpanCreationWithSamplingResultAttributes/0_mean 217 ns 217 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/0_median 216 ns 216 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/0_stddev 0.843 ns 0.850 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/0_cv 0.39 % 0.39 % 5 -// BM_SpanCreationWithSamplingResultAttributes/1_mean 257 ns 257 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/1_median 257 ns 257 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/1_stddev 0.649 ns 0.641 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/1_cv 0.25 % 0.25 % 5 -// BM_SpanCreationWithSamplingResultAttributes/10_mean 634 ns 633 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/10_median 628 ns 628 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/10_stddev 12.0 ns 12.0 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/10_cv 1.89 % 1.89 % 5 -// BM_SpanCreationWithSamplingResultAttributes/128_mean 8954 ns 8953 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/128_median 9197 ns 9196 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/128_stddev 381 ns 381 ns 5 -// BM_SpanCreationWithSamplingResultAttributes/128_cv 4.26 % 4.25 % 5 +// BM_AlwaysOffSamplerShouldSample_median 4.09 ns 4.09 ns 5 +// BM_AlwaysOffSamplerShouldSample_stddev 0.071 ns 0.071 ns 5 +// BM_AlwaysOffSamplerShouldSample_cv 1.72 % 1.72 % 5 +// BM_AlwaysOnSamplerShouldSample_mean 4.45 ns 4.45 ns 5 +// BM_AlwaysOnSamplerShouldSample_median 4.45 ns 4.45 ns 5 +// BM_AlwaysOnSamplerShouldSample_stddev 0.013 ns 0.013 ns 5 +// BM_AlwaysOnSamplerShouldSample_cv 0.30 % 0.30 % 5 +// BM_ParentBasedSamplerShouldSample_mean 7.37 ns 7.36 ns 5 +// BM_ParentBasedSamplerShouldSample_median 7.36 ns 7.36 ns 5 +// BM_ParentBasedSamplerShouldSample_stddev 0.010 ns 0.009 ns 5 +// BM_ParentBasedSamplerShouldSample_cv 0.14 % 0.12 % 5 +// BM_TraceIdRatioBasedSamplerShouldSample_mean 3.97 ns 3.97 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_median 3.97 ns 3.97 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_stddev 0.010 ns 0.010 ns 5 +// BM_TraceIdRatioBasedSamplerShouldSample_cv 0.25 % 0.25 % 5 +// BM_SpanCreation_mean 215 ns 215 ns 5 +// BM_SpanCreation_median 214 ns 214 ns 5 +// BM_SpanCreation_stddev 4.74 ns 4.74 ns 5 +// BM_SpanCreation_cv 2.21 % 2.21 % 5 +// BM_NoopSpanCreation_mean 31.1 ns 31.1 ns 5 +// BM_NoopSpanCreation_median 31.1 ns 31.1 ns 5 +// BM_NoopSpanCreation_stddev 0.028 ns 0.027 ns 5 +// BM_NoopSpanCreation_cv 0.09 % 0.09 % 5 +// BM_SpanCreationWithSamplingResultAttributes/1_mean 253 ns 253 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_median 251 ns 251 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_stddev 4.27 ns 4.27 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/1_cv 1.69 % 1.69 % 5 +// BM_SpanCreationWithSamplingResultAttributes/10_mean 588 ns 588 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_median 589 ns 589 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_stddev 3.18 ns 3.17 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/10_cv 0.54 % 0.54 % 5 +// BM_SpanCreationWithSamplingResultAttributes/128_mean 8602 ns 8600 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_median 8702 ns 8701 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_stddev 299 ns 299 ns 5 +// BM_SpanCreationWithSamplingResultAttributes/128_cv 3.48 % 3.48 % 5 // // clang-format on From 02d63943d050a03a17dced71adbf46f34d3f07d2 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Sat, 18 Jul 2026 11:08:14 -0400 Subject: [PATCH 16/17] fix iwyu warnings --- sdk/src/trace/span.cc | 1 + sdk/src/trace/span.h | 1 + sdk/src/trace/tracer.cc | 1 - sdk/test/trace/sampler_benchmark.cc | 2 ++ 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/sdk/src/trace/span.cc b/sdk/src/trace/span.cc index 6f2ba790d4..84877eb9aa 100644 --- a/sdk/src/trace/span.cc +++ b/sdk/src/trace/span.cc @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 #include +#include #include #include "opentelemetry/nostd/function_ref.h" diff --git a/sdk/src/trace/span.h b/sdk/src/trace/span.h index ea071c1274..a780b5df03 100644 --- a/sdk/src/trace/span.h +++ b/sdk/src/trace/span.h @@ -11,6 +11,7 @@ #include "opentelemetry/common/timestamp.h" #include "opentelemetry/nostd/string_view.h" #include "opentelemetry/sdk/trace/recordable.h" +#include "opentelemetry/sdk/trace/sampler.h" #include "opentelemetry/sdk/trace/tracer.h" #include "opentelemetry/trace/span.h" #include "opentelemetry/trace/span_context.h" diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index f6b3f6ba6b..8d805b4b17 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -3,7 +3,6 @@ #include #include -#include #include #include #include diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc index 9d89d56c01..1fbd3583fe 100644 --- a/sdk/test/trace/sampler_benchmark.cc +++ b/sdk/test/trace/sampler_benchmark.cc @@ -65,11 +65,13 @@ // clang-format on #include +#include #include #include #include #include +#include "opentelemetry/common/attribute_value.h" #include "opentelemetry/common/key_value_iterable_view.h" #include "opentelemetry/context/context_value.h" // IWYU pragma: keep #include "opentelemetry/exporters/memory/in_memory_span_exporter.h" From b2081799215dbdf15dbc15cddfe05d5b178d6e85 Mon Sep 17 00:00:00 2001 From: Douglas Barker Date: Sat, 18 Jul 2026 12:09:45 -0400 Subject: [PATCH 17/17] fix bazel.noexcept build --- sdk/src/trace/tracer.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/src/trace/tracer.cc b/sdk/src/trace/tracer.cc index 8d805b4b17..0aa2e415ab 100644 --- a/sdk/src/trace/tracer.cc +++ b/sdk/src/trace/tracer.cc @@ -87,8 +87,8 @@ nostd::shared_ptr MakeSpan( } #else return nostd::shared_ptr{ - new (std::nothrow) Span{std::move(tracer), name, attributes, links, options, parent_context, - std::move(span_context)}}; + new (std::nothrow) Span{std::move(tracer), name, attributes, links, options, sampling_result, + parent_context, std::move(span_context)}}; #endif }