diff options
Diffstat (limited to 'vespalib/src/tests/coro/generator')
-rw-r--r-- | vespalib/src/tests/coro/generator/generator_bench.cpp | 144 | ||||
-rw-r--r-- | vespalib/src/tests/coro/generator/generator_test.cpp | 32 |
2 files changed, 97 insertions, 79 deletions
diff --git a/vespalib/src/tests/coro/generator/generator_bench.cpp b/vespalib/src/tests/coro/generator/generator_bench.cpp index ab0bcdc5c97..ae0e0fce894 100644 --- a/vespalib/src/tests/coro/generator/generator_bench.cpp +++ b/vespalib/src/tests/coro/generator/generator_bench.cpp @@ -11,8 +11,23 @@ using vespalib::coro::Generator; using vespalib::BenchmarkTimer; using vespalib::Sequence; -template <std::ranges::input_range T> -size_t calc_sum(T&& values) { +size_t calc_sum(const std::vector<size_t> &values) { + size_t sum = 0; + for (auto&& value: values) { + sum += value; + } + return sum; +} + +size_t calc_sum(Generator<size_t> values) { + size_t sum = 0; + for (auto&& value: values) { + sum += value; + } + return sum; +} + +size_t calc_sum(Generator<const size_t &> values) { size_t sum = 0; for (auto&& value: values) { sum += value; @@ -28,91 +43,84 @@ size_t calc_sum(Sequence<size_t> &seq) { return sum; } -struct ValueRange { - using iterator_concept = std::input_iterator_tag; - using difference_type = std::ptrdiff_t; - using value_type = size_t; - size_t first; - size_t last; - ValueRange() noexcept : first(0), last(0) {} - ValueRange(size_t first_in, size_t last_in) noexcept - : first(first_in), last(last_in) {} - auto begin() noexcept { return ValueRange(first, last); } - auto end() const noexcept { return std::default_sentinel_t(); } - bool operator==(std::default_sentinel_t) const noexcept { return (first == last); } - ValueRange &operator++() noexcept { ++first; return *this; } - void operator++(int) noexcept { operator++(); } - size_t operator*() const noexcept { return first; } +std::vector<size_t> make_data() __attribute__((noinline)); +std::vector<size_t> make_data() { + size_t n = 1000000; + std::vector<size_t> data; + data.reserve(n); + for (size_t i = 0; i < n; ++i) { + data.push_back(i + n); + } + return data; +} + +struct MySeq : Sequence<size_t> { + const std::vector<size_t> &data; + size_t pos; + MySeq(const std::vector<size_t> &data_in) + : data(data_in), pos(0) {} + bool valid() const override { return pos < data.size(); } + size_t get() const override { return data[pos]; } + void next() override { ++pos; } }; -size_t calc_sum_direct(size_t first, size_t last) { - return calc_sum(ValueRange(first, last)); +size_t calc_sum_direct(const std::vector<size_t> &data) { + return calc_sum(data); } -Generator<size_t> gen_values(size_t first, size_t last) { - for (size_t i = first; i < last; ++i) { - co_yield i; +size_t calc_sum_sequence(const std::vector<size_t> &data) { + MySeq my_seq(data); + return calc_sum(my_seq); +} + +Generator<size_t> gen_values(const std::vector<size_t> &data) { + for (size_t value: data) { + co_yield value; } } -size_t calc_sum_generator(size_t first, size_t last) { - return calc_sum(gen_values(first, last)); +size_t calc_sum_generator(const std::vector<size_t> &data) { + return calc_sum(gen_values(data)); } -Generator<const size_t &> gen_values_ref(size_t first, size_t last) { - for (size_t i = first; i < last; ++i) { - co_yield i; +Generator<const size_t &> gen_values_noinline(const std::vector<size_t> &data) __attribute__((noinline)); +Generator<const size_t &> gen_values_noinline(const std::vector<size_t> &data) { + for (const size_t &value: data) { + co_yield value; } } -size_t calc_sum_generator_ref(size_t first, size_t last) { - return calc_sum(gen_values_ref(first, last)); +size_t calc_sum_generator_noinline(const std::vector<size_t> &data) { + return calc_sum(gen_values_noinline(data)); } -struct MySeq : Sequence<size_t> { - size_t first; - size_t last; - MySeq(size_t first_in, size_t last_in) - : first(first_in), last(last_in) {} - bool valid() const override { return (first < last); } - size_t get() const override { return first; } - void next() override { ++first; } -}; - -size_t calc_sum_sequence(size_t first, size_t last) { - MySeq seq(first, last); - return calc_sum(seq); +double bench(auto fun, const std::vector<size_t> &data, size_t &res) { + BenchmarkTimer timer(5.0); + while (timer.has_budget()) { + timer.before(); + res = fun(data); + timer.after(); + } + return timer.min_time() * 1000.0; } TEST(GeneratorBench, direct_vs_generated_for_loop) { - size_t first = 0; - size_t last = 100000; - size_t res_direct = 0; - size_t res_generator = 1; - size_t res_generator_ref = 2; - size_t res_sequence = 3; - double direct_ms = BenchmarkTimer::benchmark([first,last,&res_direct](){ - res_direct = calc_sum_direct(first, last); - }, 5.0) * 1000.0; - fprintf(stderr, "direct: %g ms\n", direct_ms); - double generator_ms = BenchmarkTimer::benchmark([first,last,&res_generator](){ - res_generator = calc_sum_generator(first, last); - }, 5.0) * 1000.0; - fprintf(stderr, "generator: %g ms\n", generator_ms); - double generator_ref_ms = BenchmarkTimer::benchmark([first,last,&res_generator_ref](){ - res_generator_ref = calc_sum_generator_ref(first, last); - }, 5.0) * 1000.0; - fprintf(stderr, "generator_ref: %g ms\n", generator_ref_ms); - double sequence_ms = BenchmarkTimer::benchmark([first,last,&res_sequence](){ - res_sequence = calc_sum_sequence(first, last); - }, 5.0) * 1000.0; + auto data = make_data(); + size_t result[4] = { 0, 1, 2, 3 }; + double sequence_ms = bench(calc_sum_sequence, data, result[0]); fprintf(stderr, "sequence: %g ms\n", sequence_ms); - EXPECT_EQ(res_direct, res_generator); - EXPECT_EQ(res_direct, res_generator_ref); - EXPECT_EQ(res_direct, res_sequence); + double generator_noinline_ms = bench(calc_sum_generator_noinline, data, result[1]); + fprintf(stderr, "generator_noinline: %g ms\n", generator_noinline_ms); + double generator_ms = bench(calc_sum_generator, data, result[2]); + fprintf(stderr, "generator: %g ms\n", generator_ms); + double direct_ms = bench(calc_sum_direct, data, result[3]); + fprintf(stderr, "direct: %g ms\n", direct_ms); + EXPECT_EQ(result[0], result[1]); + EXPECT_EQ(result[0], result[2]); + EXPECT_EQ(result[0], result[3]); fprintf(stderr, "ratio (generator/direct): %g\n", (generator_ms/direct_ms)); - fprintf(stderr, "ratio (generator/sequence): %g\n", (generator_ms/sequence_ms)); - fprintf(stderr, "ratio (generator/generator_ref): %g\n", (generator_ms/generator_ref_ms)); + fprintf(stderr, "ratio (generator_noinline/generator): %g\n", (generator_noinline_ms/generator_ms)); + fprintf(stderr, "ratio (sequence/generator): %g\n", (sequence_ms/generator_ms)); } GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/tests/coro/generator/generator_test.cpp b/vespalib/src/tests/coro/generator/generator_test.cpp index 149fe379faa..28e26329b13 100644 --- a/vespalib/src/tests/coro/generator/generator_test.cpp +++ b/vespalib/src/tests/coro/generator/generator_test.cpp @@ -36,8 +36,12 @@ Generator<int> make_numbers(int begin, int end) { } Generator<int> make_numbers(int begin, int split, int end) { - co_yield make_numbers(begin, split); - co_yield make_numbers(split, end); + for (int num: make_numbers(begin, split)) { + co_yield num; + } + for (int num: make_numbers(split, end)) { + co_yield num; + } } static_assert(std::input_iterator<Generator<std::unique_ptr<int>>::Iterator>); @@ -67,13 +71,19 @@ Generator<int> make_failed_numbers(int begin, int end, int fail) { Generator<int> make_safe(Generator<int> gen) { try { - co_yield gen; + for (int num: gen) { + co_yield num; + } } catch (...) {} } Generator<int> a_then_b(Generator<int> a, Generator<int> b) { - co_yield a; - co_yield b; + for (int num: a) { + co_yield num; + } + for (int num: b) { + co_yield num; + } } TEST(GeneratorTest, generate_some_numbers) { @@ -116,13 +126,13 @@ TEST(GeneratorTest, generate_unmovable_values) { auto pos = gen.begin(); auto end = gen.end(); ASSERT_FALSE(pos == end); - EXPECT_EQ(pos->get(), 1); + EXPECT_EQ((*pos).get(), 1); ++pos; ASSERT_FALSE(pos == end); - EXPECT_EQ(pos->get(), 2); + EXPECT_EQ((*pos).get(), 2); ++pos; ASSERT_FALSE(pos == end); - EXPECT_EQ(pos->get(), 3); + EXPECT_EQ((*pos).get(), 3); ++pos; EXPECT_TRUE(pos == end); } @@ -148,7 +158,7 @@ TEST(GeneratorTest, explicit_range_for_loop) { EXPECT_EQ(expect, 10); } -TEST(GeneratorTest, recursive_generator) { +TEST(GeneratorTest, nested_generator) { int expect = 1; for (int x: make_numbers(1, 4, 10)) { EXPECT_EQ(x, expect); @@ -157,7 +167,7 @@ TEST(GeneratorTest, recursive_generator) { EXPECT_EQ(expect, 10); } -TEST(GeneratorTest, deeper_recursive_generator) { +TEST(GeneratorTest, deeper_nested_generator) { int expect = 1; for (int x: a_then_b(make_numbers(1, 3, 5), make_numbers(5, 7, 10))) { EXPECT_EQ(x, expect); @@ -201,7 +211,7 @@ TEST(GeneratorTest, exception_captured_by_parent_generator) { EXPECT_EQ(expect, 10); } -TEST(GeneratorTest, moving_iterator_with_recursive_generator) { +TEST(GeneratorTest, moving_iterator_with_nested_generator) { auto gen = a_then_b(make_numbers(1, 3, 5), make_numbers(5, 7, 9)); auto pos = std::ranges::begin(gen); auto end = std::ranges::end(gen); |