benchmark.cc 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Benchmark for Python.
  2. #include <map>
  3. #include <string>
  4. #include <vector>
  5. #include "pybind11/operators.h"
  6. #include "pybind11/pybind11.h"
  7. #include "pybind11/stl.h"
  8. #include "pybind11/stl_bind.h"
  9. #include "benchmark/benchmark.h"
  10. PYBIND11_MAKE_OPAQUE(benchmark::UserCounters);
  11. namespace {
  12. namespace py = ::pybind11;
  13. std::vector<std::string> Initialize(const std::vector<std::string>& argv) {
  14. // The `argv` pointers here become invalid when this function returns, but
  15. // benchmark holds the pointer to `argv[0]`. We create a static copy of it
  16. // so it persists, and replace the pointer below.
  17. static std::string executable_name(argv[0]);
  18. std::vector<char*> ptrs;
  19. ptrs.reserve(argv.size());
  20. for (auto& arg : argv) {
  21. ptrs.push_back(const_cast<char*>(arg.c_str()));
  22. }
  23. ptrs[0] = const_cast<char*>(executable_name.c_str());
  24. int argc = static_cast<int>(argv.size());
  25. benchmark::Initialize(&argc, ptrs.data());
  26. std::vector<std::string> remaining_argv;
  27. remaining_argv.reserve(argc);
  28. for (int i = 0; i < argc; ++i) {
  29. remaining_argv.emplace_back(ptrs[i]);
  30. }
  31. return remaining_argv;
  32. }
  33. benchmark::internal::Benchmark* RegisterBenchmark(const char* name,
  34. py::function f) {
  35. return benchmark::RegisterBenchmark(
  36. name, [f](benchmark::State& state) { f(&state); });
  37. }
  38. PYBIND11_MODULE(_benchmark, m) {
  39. using benchmark::TimeUnit;
  40. py::enum_<TimeUnit>(m, "TimeUnit")
  41. .value("kNanosecond", TimeUnit::kNanosecond)
  42. .value("kMicrosecond", TimeUnit::kMicrosecond)
  43. .value("kMillisecond", TimeUnit::kMillisecond)
  44. .value("kSecond", TimeUnit::kSecond)
  45. .export_values();
  46. using benchmark::BigO;
  47. py::enum_<BigO>(m, "BigO")
  48. .value("oNone", BigO::oNone)
  49. .value("o1", BigO::o1)
  50. .value("oN", BigO::oN)
  51. .value("oNSquared", BigO::oNSquared)
  52. .value("oNCubed", BigO::oNCubed)
  53. .value("oLogN", BigO::oLogN)
  54. .value("oNLogN", BigO::oLogN)
  55. .value("oAuto", BigO::oAuto)
  56. .value("oLambda", BigO::oLambda)
  57. .export_values();
  58. using benchmark::internal::Benchmark;
  59. py::class_<Benchmark>(m, "Benchmark")
  60. // For methods returning a pointer tor the current object, reference
  61. // return policy is used to ask pybind not to take ownership oof the
  62. // returned object and avoid calling delete on it.
  63. // https://pybind11.readthedocs.io/en/stable/advanced/functions.html#return-value-policies
  64. //
  65. // For methods taking a const std::vector<...>&, a copy is created
  66. // because a it is bound to a Python list.
  67. // https://pybind11.readthedocs.io/en/stable/advanced/cast/stl.html
  68. .def("unit", &Benchmark::Unit, py::return_value_policy::reference)
  69. .def("arg", &Benchmark::Arg, py::return_value_policy::reference)
  70. .def("args", &Benchmark::Args, py::return_value_policy::reference)
  71. .def("range", &Benchmark::Range, py::return_value_policy::reference,
  72. py::arg("start"), py::arg("limit"))
  73. .def("dense_range", &Benchmark::DenseRange,
  74. py::return_value_policy::reference, py::arg("start"),
  75. py::arg("limit"), py::arg("step") = 1)
  76. .def("ranges", &Benchmark::Ranges, py::return_value_policy::reference)
  77. .def("args_product", &Benchmark::ArgsProduct,
  78. py::return_value_policy::reference)
  79. .def("arg_name", &Benchmark::ArgName, py::return_value_policy::reference)
  80. .def("arg_names", &Benchmark::ArgNames,
  81. py::return_value_policy::reference)
  82. .def("range_pair", &Benchmark::RangePair,
  83. py::return_value_policy::reference, py::arg("lo1"), py::arg("hi1"),
  84. py::arg("lo2"), py::arg("hi2"))
  85. .def("range_multiplier", &Benchmark::RangeMultiplier,
  86. py::return_value_policy::reference)
  87. .def("min_time", &Benchmark::MinTime, py::return_value_policy::reference)
  88. .def("iterations", &Benchmark::Iterations,
  89. py::return_value_policy::reference)
  90. .def("repetitions", &Benchmark::Repetitions,
  91. py::return_value_policy::reference)
  92. .def("report_aggregates_only", &Benchmark::ReportAggregatesOnly,
  93. py::return_value_policy::reference, py::arg("value") = true)
  94. .def("display_aggregates_only", &Benchmark::DisplayAggregatesOnly,
  95. py::return_value_policy::reference, py::arg("value") = true)
  96. .def("measure_process_cpu_time", &Benchmark::MeasureProcessCPUTime,
  97. py::return_value_policy::reference)
  98. .def("use_real_time", &Benchmark::UseRealTime,
  99. py::return_value_policy::reference)
  100. .def("use_manual_time", &Benchmark::UseManualTime,
  101. py::return_value_policy::reference)
  102. .def(
  103. "complexity",
  104. (Benchmark * (Benchmark::*)(benchmark::BigO)) & Benchmark::Complexity,
  105. py::return_value_policy::reference,
  106. py::arg("complexity") = benchmark::oAuto);
  107. using benchmark::Counter;
  108. py::class_<Counter> py_counter(m, "Counter");
  109. py::enum_<Counter::Flags>(py_counter, "Flags")
  110. .value("kDefaults", Counter::Flags::kDefaults)
  111. .value("kIsRate", Counter::Flags::kIsRate)
  112. .value("kAvgThreads", Counter::Flags::kAvgThreads)
  113. .value("kAvgThreadsRate", Counter::Flags::kAvgThreadsRate)
  114. .value("kIsIterationInvariant", Counter::Flags::kIsIterationInvariant)
  115. .value("kIsIterationInvariantRate",
  116. Counter::Flags::kIsIterationInvariantRate)
  117. .value("kAvgIterations", Counter::Flags::kAvgIterations)
  118. .value("kAvgIterationsRate", Counter::Flags::kAvgIterationsRate)
  119. .value("kInvert", Counter::Flags::kInvert)
  120. .export_values()
  121. .def(py::self | py::self);
  122. py::enum_<Counter::OneK>(py_counter, "OneK")
  123. .value("kIs1000", Counter::OneK::kIs1000)
  124. .value("kIs1024", Counter::OneK::kIs1024)
  125. .export_values();
  126. py_counter
  127. .def(py::init<double, Counter::Flags, Counter::OneK>(),
  128. py::arg("value") = 0., py::arg("flags") = Counter::kDefaults,
  129. py::arg("k") = Counter::kIs1000)
  130. .def(py::init([](double value) { return Counter(value); }))
  131. .def_readwrite("value", &Counter::value)
  132. .def_readwrite("flags", &Counter::flags)
  133. .def_readwrite("oneK", &Counter::oneK);
  134. py::implicitly_convertible<py::float_, Counter>();
  135. py::implicitly_convertible<py::int_, Counter>();
  136. py::bind_map<benchmark::UserCounters>(m, "UserCounters");
  137. using benchmark::State;
  138. py::class_<State>(m, "State")
  139. .def("__bool__", &State::KeepRunning)
  140. .def_property_readonly("keep_running", &State::KeepRunning)
  141. .def("pause_timing", &State::PauseTiming)
  142. .def("resume_timing", &State::ResumeTiming)
  143. .def("skip_with_error", &State::SkipWithError)
  144. .def_property_readonly("error_occurred", &State::error_occurred)
  145. .def("set_iteration_time", &State::SetIterationTime)
  146. .def_property("bytes_processed", &State::bytes_processed,
  147. &State::SetBytesProcessed)
  148. .def_property("complexity_n", &State::complexity_length_n,
  149. &State::SetComplexityN)
  150. .def_property("items_processed", &State::items_processed,
  151. &State::SetItemsProcessed)
  152. .def("set_label", (void(State::*)(const char*)) & State::SetLabel)
  153. .def("range", &State::range, py::arg("pos") = 0)
  154. .def_property_readonly("iterations", &State::iterations)
  155. .def_readwrite("counters", &State::counters)
  156. .def_property_readonly("thread_index", &State::thread_index)
  157. .def_property_readonly("threads", &State::threads);
  158. m.def("Initialize", Initialize);
  159. m.def("RegisterBenchmark", RegisterBenchmark,
  160. py::return_value_policy::reference);
  161. m.def("RunSpecifiedBenchmarks",
  162. []() { benchmark::RunSpecifiedBenchmarks(); });
  163. };
  164. } // namespace