Skip to content

Commit

Permalink
Sampler Performance Testing (open-telemetry#175)
Browse files Browse the repository at this point in the history
  • Loading branch information
nholbrook authored Jul 23, 2020
1 parent eb7cbd1 commit 5b8cd5b
Show file tree
Hide file tree
Showing 3 changed files with 206 additions and 6 deletions.
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"
#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
{
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_;
};

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<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();

0 comments on commit 5b8cd5b

Please sign in to comment.