Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion sdk/test/trace/BUILD
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
load("//bazel:otel_cc_benchmark.bzl", "otel_cc_benchmark")

cc_test(
name = "tracer_provider_test",
srcs = [
Expand Down Expand Up @@ -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"],
)
22 changes: 17 additions & 5 deletions sdk/test/trace/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
180 changes: 180 additions & 0 deletions sdk/test/trace/sampler_benchmark.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,180 @@
#include "opentelemetry/sdk/trace/sampler.h"
#include "opentelemetry/sdk/trace/samplers/always_off.h"
Comment thread
nholbrook marked this conversation as resolved.
Comment thread
nholbrook marked this conversation as resolved.
#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 <cstdint>

#include <benchmark/benchmark.h>

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
Comment thread
nholbrook marked this conversation as resolved.
{
public:
MockSpanExporter(std::shared_ptr<std::vector<std::unique_ptr<SpanData>>> spans_received) noexcept
: spans_received_(spans_received)
{}

std::unique_ptr<Recordable> MakeRecordable() noexcept override
{
return std::unique_ptr<Recordable>(new SpanData);
}

ExportResult Export(const nostd::span<std::unique_ptr<Recordable>> &recordables) noexcept override
{
for (auto &recordable : recordables)
{
auto span = std::unique_ptr<SpanData>(static_cast<SpanData *>(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<std::vector<std::unique_ptr<SpanData>>> spans_received_;
};
Comment thread
nholbrook marked this conversation as resolved.

namespace
{
// Sampler constructor used as a baseline to compare with other samplers
void BM_AlwaysOffSamplerConstruction(benchmark::State &state)
Comment thread
nholbrook marked this conversation as resolved.
{
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<AlwaysOnSampler>()));
}
}
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<std::string, int>;
M m1 = {{}};
opentelemetry::trace::KeyValueIterableView<M> 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<AlwaysOnSampler>());

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> sampler, benchmark::State &state)
{
std::shared_ptr<std::vector<std::unique_ptr<SpanData>>> spans_received(
new std::vector<std::unique_ptr<SpanData>>);

std::unique_ptr<SpanExporter> exporter(new MockSpanExporter(spans_received));
auto processor = std::make_shared<SimpleSpanProcessor>(std::move(exporter));
auto tracer = std::shared_ptr<opentelemetry::trace::Tracer>(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<AlwaysOnSampler>()), 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<AlwaysOffSampler>()), state);
}
BENCHMARK(BM_NoopSpanCreation);

} // namespace
BENCHMARK_MAIN();