diff --git a/include/seastar/testing/perf_tests.hh b/include/seastar/testing/perf_tests.hh index 8ee5180d98..a60a4c1b91 100644 --- a/include/seastar/testing/perf_tests.hh +++ b/include/seastar/testing/perf_tests.hh @@ -26,6 +26,7 @@ #include +#include #include #include #include @@ -222,39 +223,17 @@ public: extern time_measurement measure_time; -namespace { - -template -struct do_if_constexpr_ : FalseFn { - do_if_constexpr_(TrueFn, FalseFn false_fn) : FalseFn(std::move(false_fn)) { } - decltype(auto) operator()() const { - // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=64095 - return FalseFn::operator()(0); - } -}; -template -struct do_if_constexpr_ : TrueFn { - do_if_constexpr_(TrueFn true_fn, FalseFn) : TrueFn(std::move(true_fn)) { } - decltype(auto) operator()() const { return TrueFn::operator()(0); } -}; - -template -do_if_constexpr_ if_constexpr_(TrueFn&& true_fn, FalseFn&& false_fn) -{ - return do_if_constexpr_(std::forward(true_fn), - std::forward(false_fn)); -} - -} - template class concrete_performance_test final : public performance_test { std::optional _test; + + using test_ret_type = decltype(_test->run()); + // true iff the test method returns future<...> + static constexpr bool is_async_test = is_future::value; + // true iff the test returns the number of iterations run, otherwise it returns + // void and we consider each invocation to be 1 iteration + static constexpr bool is_iteration_returning = !(std::is_same_v> || std::is_void_v); private: - template - auto run_test(Args&&...) { - return _test->run(); - } protected: virtual void set_up() override { @@ -267,45 +246,36 @@ protected: [[gnu::hot]] virtual future do_single_run() override { - // Redundant 'this->'s courtesy of https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61636 _instructions_retired_counter.enable(); _cpu_cycles_retired_counter.enable(); - return if_constexpr_run())>::value>([&] (auto&&...) { - measure_time.start_run(&_instructions_retired_counter); - return do_until([this] { return this->stop_iteration(); }, [this] { - return if_constexpr_run()), future<>>>([&] (auto&&...) { - this->next_iteration(1); - return _test->run(); - }, [&] (auto&&... dependency) { - // We need `dependency` to make sure the compiler won't be able to instantiate anything - // (and notice that the code does not compile) if this part of if_constexpr_ is not active. - return run_test(dependency...).then([&] (size_t n) { - this->next_iteration(n); - }); - })(); - }).then([] { - return measure_time.stop_run(); - }).finally([this] { - _instructions_retired_counter.disable(); - _cpu_cycles_retired_counter.disable(); - }); - }, [&] (auto&&...) { - measure_time.start_run(&_instructions_retired_counter, &_cpu_cycles_retired_counter); - while (!stop_iteration()) { - if_constexpr_run())>>([&] (auto&&...) { - (void)_test->run(); - this->next_iteration(1); - }, [&] (auto&&... dependency) { - // We need `dependency` to make sure the compiler won't be able to instantiate anything - // (and notice that the code does not compile) if this part of if_constexpr_ is not active. - this->next_iteration(run_test(dependency...)); - })(); + measure_time.start_run(&_instructions_retired_counter, &_cpu_cycles_retired_counter); + while (!stop_iteration()) { + if constexpr (is_async_test) { + if constexpr (is_iteration_returning) { + auto f = _test->run(); + next_iteration(f.available() ? std::move(f).get() : co_await std::move(f)); + } else { + auto f = _test->run(); + // The available() check is functionally redundant, but is significantly faster + // than invoking the co_await machinery on a future-returning function. + if (!f.available()) { + co_await std::move(f); + } + next_iteration(1); + } + } else { + if constexpr (is_iteration_returning) { + next_iteration(_test->run()); + } else { + _test->run(); + next_iteration(1); + } } - auto ret = measure_time.stop_run(); - _instructions_retired_counter.disable(); - _cpu_cycles_retired_counter.disable(); - return make_ready_future(std::move(ret)); - })(); + } + auto ret = measure_time.stop_run(); + _instructions_retired_counter.disable(); + _cpu_cycles_retired_counter.disable(); + co_return ret; } public: using performance_test::performance_test;