Skip to content

Instantly share code, notes, and snippets.

@krzysztof-jusiak
Last active February 4, 2024 08:40
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save krzysztof-jusiak/e532ec7d8e7bf3a3fa4cbb6d8db64877 to your computer and use it in GitHub Desktop.
Save krzysztof-jusiak/e532ec7d8e7bf3a3fa4cbb6d8db64877 to your computer and use it in GitHub Desktop.
Simple generators benchmark
// https://godbolt.org/z/b9s5cxPao
#include <generator>
#include <utility>
auto generator_baseline() -> int {
static THREAD_LOCAL auto i = 0;
return i++;
}
// c++20 coroutines
auto generator_coroutines() noexcept(true) -> std::generator<int> {
for (auto i = 0;; ++i) {
co_yield i;
}
}
auto generator_goto() -> int {
if (static THREAD_LOCAL auto state = 0; std::exchange(state, 1)) {
goto resume;
}
for (static THREAD_LOCAL auto i = 0;; ++i) {
return i;
resume:;
}
}
// computed-goto - gnu::extension
auto generator_computed_goto() {
static THREAD_LOCAL auto label = &&init;
goto *label;
init:;
for (static THREAD_LOCAL auto i = 0;; ++i) {
label = &&resume;
return i;
resume:;
}
};
// duff's device
auto generator_switch() -> int {
switch (static THREAD_LOCAL auto state = 0; state) {
case 0:
state = 1;
for (static THREAD_LOCAL auto i = 0;; ++i) {
return i;
case 1:;
}
}
return {};
}
auto generator_goto_lambda = [i = 0]() mutable -> int {
if (static THREAD_LOCAL auto state = 0; std::exchange(state, 1)) {
goto resume;
}
for (i = 0;; ++i) {
return i;
resume:;
}
};
// computed-goto - gnu::extension
auto generator_computed_goto_lambda = [i = 0]() mutable -> int {
static THREAD_LOCAL auto label = &&init;
goto *label;
init:;
for (i = 0;; ++i) {
label = &&resume;
return i;
resume:;
}
};
#define ANKERL_NANOBENCH_IMPLEMENT
#include <nanobench.h>
int main() {
static constexpr auto iterations = 1'00'000'000;
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_baseline", [&] { ankerl::nanobench::doNotOptimizeAway(generator_baseline()); });
auto gen = generator_coroutines();
auto it = gen.begin();
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_coroutines", [&] { ankerl::nanobench::doNotOptimizeAway(*it); it++; });
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_goto", [&] { ankerl::nanobench::doNotOptimizeAway(generator_goto()); });
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_computed_goto", [&] { ankerl::nanobench::doNotOptimizeAway(generator_computed_goto()); });
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_switch", [&] { ankerl::nanobench::doNotOptimizeAway(generator_switch()); });
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_goto_lambda", [&] { ankerl::nanobench::doNotOptimizeAway(generator_goto_lambda()); });
ankerl::nanobench::Bench().minEpochIterations(iterations).run("generator_computed_goto_lambda", [&] { ankerl::nanobench::doNotOptimizeAway(generator_computed_goto_lambda()); });
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment