diff --git a/sdk/test/trace/BUILD b/sdk/test/trace/BUILD index 280acc4fe3..b9253befcb 100644 --- a/sdk/test/trace/BUILD +++ b/sdk/test/trace/BUILD @@ -1,3 +1,5 @@ +load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark") + cc_test( name = "tracer_provider_test", srcs = [ @@ -81,8 +83,14 @@ cc_test( "probability_sampler_test.cc", ], deps = [ - "//sdk/src/trace", "//sdk/src/common:random", + "//sdk/src/trace", "@com_google_googletest//:gtest_main", ], ) + +otel_cc_benchmark( + name = "sampler_benchmark", + srcs = ["sampler_benchmark.cc"], + deps = ["//sdk/src/trace"], +) diff --git a/sdk/test/trace/CMakeLists.txt b/sdk/test/trace/CMakeLists.txt index 8326d62a7b..6f7ce66fca 100644 --- a/sdk/test/trace/CMakeLists.txt +++ b/sdk/test/trace/CMakeLists.txt @@ -1,8 +1,20 @@ -foreach(testname tracer_provider_test span_data_test simple_processor_test - tracer_test always_off_sampler_test always_on_sampler_test - parent_or_else_sampler_test probability_sampler_test) +foreach( + testname + tracer_provider_test + span_data_test + simple_processor_test + tracer_test + always_off_sampler_test + always_on_sampler_test + parent_or_else_sampler_test + probability_sampler_test) add_executable(${testname} "${testname}.cc") - target_link_libraries(${testname} ${GTEST_BOTH_LIBRARIES} - ${CMAKE_THREAD_LIBS_INIT} opentelemetry_common opentelemetry_trace) + target_link_libraries( + ${testname} ${GTEST_BOTH_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} + opentelemetry_common opentelemetry_trace) gtest_add_tests(TARGET ${testname} TEST_PREFIX trace. TEST_LIST ${testname}) endforeach() + +add_executable(sampler_benchmark sampler_benchmark.cc) +target_link_libraries(sampler_benchmark benchmark::benchmark + ${CMAKE_THREAD_LIBS_INIT} opentelemetry_trace) diff --git a/sdk/test/trace/sampler_benchmark.cc b/sdk/test/trace/sampler_benchmark.cc new file mode 100644 index 0000000000..2dad8c8128 --- /dev/null +++ b/sdk/test/trace/sampler_benchmark.cc @@ -0,0 +1,180 @@ +#include "opentelemetry/sdk/trace/sampler.h" +#include "opentelemetry/sdk/trace/samplers/always_off.h" +#include "opentelemetry/sdk/trace/samplers/always_on.h" +#include "opentelemetry/sdk/trace/samplers/parent_or_else.h" +#include "opentelemetry/sdk/trace/samplers/probability.h" +#include "opentelemetry/sdk/trace/simple_processor.h" +#include "opentelemetry/sdk/trace/span_data.h" +#include "opentelemetry/sdk/trace/tracer.h" + +#include + +#include + +using namespace opentelemetry::sdk::trace; +namespace nostd = opentelemetry::nostd; +namespace common = opentelemetry::common; +using opentelemetry::trace::SpanContext; + +/** + * A mock exporter that switches a flag once a valid recordable was received. + */ +class MockSpanExporter final : public SpanExporter +{ +public: + MockSpanExporter(std::shared_ptr>> spans_received) noexcept + : spans_received_(spans_received) + {} + + std::unique_ptr MakeRecordable() noexcept override + { + return std::unique_ptr(new SpanData); + } + + ExportResult Export(const nostd::span> &recordables) noexcept override + { + for (auto &recordable : recordables) + { + auto span = std::unique_ptr(static_cast(recordable.release())); + if (span != nullptr) + { + spans_received_->push_back(std::move(span)); + } + } + + return ExportResult::kSuccess; + } + + void Shutdown(std::chrono::microseconds timeout = std::chrono::microseconds(0)) noexcept override + {} + +private: + std::shared_ptr>> spans_received_; +}; + +namespace +{ +// Sampler constructor used as a baseline to compare with other samplers +void BM_AlwaysOffSamplerConstruction(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(AlwaysOffSampler()); + } +} +BENCHMARK(BM_AlwaysOffSamplerConstruction); + +// Sampler constructor used as a baseline to compare with other samplers +void BM_AlwaysOnSamplerConstruction(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(AlwaysOnSampler()); + } +} +BENCHMARK(BM_AlwaysOnSamplerConstruction); + +void BM_ParentOrElseSamplerConstruction(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(ParentOrElseSampler(std::make_shared())); + } +} +BENCHMARK(BM_ParentOrElseSamplerConstruction); + +void BM_ProbabilitySamplerConstruction(benchmark::State &state) +{ + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(ProbabilitySampler(0.01)); + } +} +BENCHMARK(BM_ProbabilitySamplerConstruction); + +// Sampler Helper Function +void BenchmarkShouldSampler(Sampler &sampler, benchmark::State &state) +{ + opentelemetry::trace::TraceId trace_id; + opentelemetry::trace::SpanKind span_kind = opentelemetry::trace::SpanKind::kInternal; + + using M = std::map; + M m1 = {{}}; + opentelemetry::trace::KeyValueIterableView view{m1}; + + while (state.KeepRunning()) + { + benchmark::DoNotOptimize(sampler.ShouldSample(nullptr, trace_id, "", span_kind, view)); + } +} + +// Sampler used as a baseline to compare with other samplers +void BM_AlwaysOffSamplerShouldSample(benchmark::State &state) +{ + AlwaysOffSampler sampler; + + BenchmarkShouldSampler(sampler, state); +} +BENCHMARK(BM_AlwaysOffSamplerShouldSample); + +// Sampler used as a baseline to compare with other samplers +void BM_AlwaysOnSamplerShouldSample(benchmark::State &state) +{ + AlwaysOnSampler sampler; + + BenchmarkShouldSampler(sampler, state); +} +BENCHMARK(BM_AlwaysOnSamplerShouldSample); + +void BM_ParentOrElseSamplerShouldSample(benchmark::State &state) +{ + ParentOrElseSampler sampler(std::make_shared()); + + BenchmarkShouldSampler(sampler, state); +} +BENCHMARK(BM_ParentOrElseSamplerShouldSample); + +void BM_ProbabilitySamplerShouldSample(benchmark::State &state) +{ + ProbabilitySampler sampler(0.01); + + BenchmarkShouldSampler(sampler, state); +} +BENCHMARK(BM_ProbabilitySamplerShouldSample); + +// Sampler Helper Function +void BenchmarkSpanCreation(std::shared_ptr sampler, benchmark::State &state) +{ + std::shared_ptr>> spans_received( + new std::vector>); + + std::unique_ptr exporter(new MockSpanExporter(spans_received)); + auto processor = std::make_shared(std::move(exporter)); + auto tracer = std::shared_ptr(new Tracer(processor, sampler)); + + while (state.KeepRunning()) + { + auto span = tracer->StartSpan("span"); + + span->SetAttribute("attr1", 3.1); + + span->End(); + } +} + +// Test to measure performance for span creation +void BM_SpanCreation(benchmark::State &state) +{ + BenchmarkSpanCreation(std::move(std::make_shared()), state); +} +BENCHMARK(BM_SpanCreation); + +// Test to measure performance overhead for no-op span creation +void BM_NoopSpanCreation(benchmark::State &state) +{ + BenchmarkSpanCreation(std::move(std::make_shared()), state); +} +BENCHMARK(BM_NoopSpanCreation); + +} // namespace +BENCHMARK_MAIN();