Skip to content
Open
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
125 changes: 125 additions & 0 deletions protocol_benchmark.cc
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,27 @@ struct ALike {
int count() { return 42; }
};

struct ALikeToo {
std::string_view name() const { return "ALikeToo"; }

int count() { return 99; }
};

// Member function call benchmarks
static void Direct_Call(benchmark::State& state) {
ALike a;
benchmark::DoNotOptimize(a);
for (auto _ : state) {
benchmark::DoNotOptimize(a.name());
benchmark::DoNotOptimize(a.count());
}
}

BENCHMARK(Direct_Call);

static void Protocol_Virtual_Call(benchmark::State& state) {
xyz::protocol<xyz::A_virtual> p(std::in_place_type<ALike>);
benchmark::DoNotOptimize(p);
for (auto _ : state) {
benchmark::DoNotOptimize(p.name());
benchmark::DoNotOptimize(p.count());
Expand All @@ -28,6 +46,7 @@ BENCHMARK(Protocol_Virtual_Call);

static void Protocol_Manual_Call(benchmark::State& state) {
xyz::protocol<xyz::A_manual> p(std::in_place_type<ALike>);
benchmark::DoNotOptimize(p);
for (auto _ : state) {
benchmark::DoNotOptimize(p.name());
benchmark::DoNotOptimize(p.count());
Expand All @@ -37,6 +56,16 @@ static void Protocol_Manual_Call(benchmark::State& state) {
BENCHMARK(Protocol_Manual_Call);

// Copy construction benchmarks
static void Direct_Copy(benchmark::State& state) {
ALike a;
for (auto _ : state) {
ALike copy(a);
benchmark::DoNotOptimize(copy);
}
}

BENCHMARK(Direct_Copy);

static void Protocol_Virtual_Copy(benchmark::State& state) {
xyz::protocol<xyz::A_virtual> p(std::in_place_type<ALike>);
for (auto _ : state) {
Expand All @@ -58,6 +87,18 @@ static void Protocol_Manual_Copy(benchmark::State& state) {
BENCHMARK(Protocol_Manual_Copy);

// Move construction/assignment benchmarks
static void Direct_Move(benchmark::State& state) {
ALike a;
for (auto _ : state) {
ALike moved(std::move(a));
benchmark::DoNotOptimize(moved);
a = std::move(moved);
benchmark::DoNotOptimize(a);
}
}

BENCHMARK(Direct_Move);

static void Protocol_Virtual_Move(benchmark::State& state) {
xyz::protocol<xyz::A_virtual> p(std::in_place_type<ALike>);
for (auto _ : state) {
Expand All @@ -83,6 +124,18 @@ static void Protocol_Manual_Move(benchmark::State& state) {
BENCHMARK(Protocol_Manual_Move);

// Swap benchmarks
static void Direct_Swap(benchmark::State& state) {
ALike a1;
ALike a2;
for (auto _ : state) {
std::swap(a1, a2);
benchmark::DoNotOptimize(a1);
benchmark::DoNotOptimize(a2);
}
}

BENCHMARK(Direct_Swap);

static void Protocol_Virtual_Swap(benchmark::State& state) {
xyz::protocol<xyz::A_virtual> p1(std::in_place_type<ALike>);
xyz::protocol<xyz::A_virtual> p2(std::in_place_type<ALike>);
Expand All @@ -108,6 +161,15 @@ static void Protocol_Manual_Swap(benchmark::State& state) {
BENCHMARK(Protocol_Manual_Swap);

// Construction and Destruction benchmarks
static void Direct_CtorDtor(benchmark::State& state) {
for (auto _ : state) {
ALike a;
benchmark::DoNotOptimize(a);
}
}

BENCHMARK(Direct_CtorDtor);

static void Protocol_Virtual_CtorDtor(benchmark::State& state) {
for (auto _ : state) {
xyz::protocol<xyz::A_virtual> p(std::in_place_type<ALike>);
Expand All @@ -130,6 +192,7 @@ BENCHMARK(Protocol_Manual_CtorDtor);
static void ProtocolView_Virtual_Call(benchmark::State& state) {
ALike alike;
xyz::protocol_view<xyz::A_virtual> view(alike);
benchmark::DoNotOptimize(view);
for (auto _ : state) {
benchmark::DoNotOptimize(view.name());
benchmark::DoNotOptimize(view.count());
Expand All @@ -141,6 +204,7 @@ BENCHMARK(ProtocolView_Virtual_Call);
static void ProtocolView_Manual_Call(benchmark::State& state) {
ALike alike;
xyz::protocol_view<xyz::A_manual> view(alike);
benchmark::DoNotOptimize(view);
for (auto _ : state) {
benchmark::DoNotOptimize(view.name());
benchmark::DoNotOptimize(view.count());
Expand All @@ -152,6 +216,7 @@ BENCHMARK(ProtocolView_Manual_Call);
static void RawPointer_Call(benchmark::State& state) {
ALike alike;
ALike* ptr = &alike;
benchmark::DoNotOptimize(ptr);
for (auto _ : state) {
benchmark::DoNotOptimize(ptr->name());
benchmark::DoNotOptimize(ptr->count());
Expand All @@ -160,6 +225,66 @@ static void RawPointer_Call(benchmark::State& state) {

BENCHMARK(RawPointer_Call);

// Jitter benchmarks to defeat branch prediction
static void ProtocolView_Virtual_Call_Jitter(benchmark::State& state) {
ALike a1;
ALikeToo a2;
xyz::protocol_view<xyz::A_virtual> views[2] = {
xyz::protocol_view<xyz::A_virtual>(a1),
xyz::protocol_view<xyz::A_virtual>(a2)};

benchmark::DoNotOptimize(views);

size_t i = 0;
for (auto _ : state) {
auto& view = views[i & 1];
benchmark::DoNotOptimize(view.name());
benchmark::DoNotOptimize(view.count());
++i;
}
}

BENCHMARK(ProtocolView_Virtual_Call_Jitter);

static void ProtocolView_Manual_Call_Jitter(benchmark::State& state) {
ALike a1;
ALikeToo a2;
xyz::protocol_view<xyz::A_manual> views[2] = {
xyz::protocol_view<xyz::A_manual>(a1),
xyz::protocol_view<xyz::A_manual>(a2)};

benchmark::DoNotOptimize(views);

size_t i = 0;
for (auto _ : state) {
auto& view = views[i & 1];
benchmark::DoNotOptimize(view.name());
benchmark::DoNotOptimize(view.count());
++i;
}
}

BENCHMARK(ProtocolView_Manual_Call_Jitter);

static void RawPointer_Call_Jitter(benchmark::State& state) {
ALike a1;
ALike a2; // Raw pointer array must be of the same type, so this is just to
// measure the array overhead
ALike* ptrs[2] = {&a1, &a2};

benchmark::DoNotOptimize(ptrs);

size_t i = 0;
for (auto _ : state) {
auto* ptr = ptrs[i & 1];
benchmark::DoNotOptimize(ptr->name());
benchmark::DoNotOptimize(ptr->count());
++i;
}
}

BENCHMARK(RawPointer_Call_Jitter);

} // namespace

BENCHMARK_MAIN();
Loading