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