catch_benchmark_function.hpp 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. /*
  2. * Created by Joachim on 16/04/2019.
  3. * Adapted from donated nonius code.
  4. *
  5. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  6. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. */
  8. // Dumb std::function implementation for consistent call overhead
  9. #ifndef TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
  10. #define TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED
  11. #include "../catch_chronometer.hpp"
  12. #include "catch_complete_invoke.hpp"
  13. #include "../../catch_meta.hpp"
  14. #include <cassert>
  15. #include <type_traits>
  16. #include <utility>
  17. #include <memory>
  18. namespace Catch {
  19. namespace Benchmark {
  20. namespace Detail {
  21. template <typename T>
  22. using Decay = typename std::decay<T>::type;
  23. template <typename T, typename U>
  24. struct is_related
  25. : std::is_same<Decay<T>, Decay<U>> {};
  26. /// We need to reinvent std::function because every piece of code that might add overhead
  27. /// in a measurement context needs to have consistent performance characteristics so that we
  28. /// can account for it in the measurement.
  29. /// Implementations of std::function with optimizations that aren't always applicable, like
  30. /// small buffer optimizations, are not uncommon.
  31. /// This is effectively an implementation of std::function without any such optimizations;
  32. /// it may be slow, but it is consistently slow.
  33. struct BenchmarkFunction {
  34. private:
  35. struct callable {
  36. virtual void call(Chronometer meter) const = 0;
  37. virtual callable* clone() const = 0;
  38. virtual ~callable() = default;
  39. };
  40. template <typename Fun>
  41. struct model : public callable {
  42. model(Fun&& fun) : fun(std::move(fun)) {}
  43. model(Fun const& fun) : fun(fun) {}
  44. model<Fun>* clone() const override { return new model<Fun>(*this); }
  45. void call(Chronometer meter) const override {
  46. call(meter, is_callable<Fun(Chronometer)>());
  47. }
  48. void call(Chronometer meter, std::true_type) const {
  49. fun(meter);
  50. }
  51. void call(Chronometer meter, std::false_type) const {
  52. meter.measure(fun);
  53. }
  54. Fun fun;
  55. };
  56. struct do_nothing { void operator()() const {} };
  57. template <typename T>
  58. BenchmarkFunction(model<T>* c) : f(c) {}
  59. public:
  60. BenchmarkFunction()
  61. : f(new model<do_nothing>{ {} }) {}
  62. template <typename Fun,
  63. typename std::enable_if<!is_related<Fun, BenchmarkFunction>::value, int>::type = 0>
  64. BenchmarkFunction(Fun&& fun)
  65. : f(new model<typename std::decay<Fun>::type>(std::forward<Fun>(fun))) {}
  66. BenchmarkFunction(BenchmarkFunction&& that)
  67. : f(std::move(that.f)) {}
  68. BenchmarkFunction(BenchmarkFunction const& that)
  69. : f(that.f->clone()) {}
  70. BenchmarkFunction& operator=(BenchmarkFunction&& that) {
  71. f = std::move(that.f);
  72. return *this;
  73. }
  74. BenchmarkFunction& operator=(BenchmarkFunction const& that) {
  75. f.reset(that.f->clone());
  76. return *this;
  77. }
  78. void operator()(Chronometer meter) const { f->call(meter); }
  79. private:
  80. std::unique_ptr<callable> f;
  81. };
  82. } // namespace Detail
  83. } // namespace Benchmark
  84. } // namespace Catch
  85. #endif // TWOBLUECUBES_CATCH_DETAIL_BENCHMARK_FUNCTION_HPP_INCLUDED