1 // Benchmark for Python.
7 #include "pybind11/operators.h"
8 #include "pybind11/pybind11.h"
9 #include "pybind11/stl.h"
10 #include "pybind11/stl_bind.h"
12 #include "benchmark/benchmark.h"
14 PYBIND11_MAKE_OPAQUE(benchmark::UserCounters
);
17 namespace py
= ::pybind11
;
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()));
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
]);
37 return remaining_argv
;
40 benchmark::internal::Benchmark
* RegisterBenchmark(const char* name
,
42 return benchmark::RegisterBenchmark(
43 name
, [f
](benchmark::State
& state
) { f(&state
); });
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
)
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
)
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
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
)
114 (Benchmark
* (Benchmark::*)(benchmark::BigO
)) & Benchmark::Complexity
,
115 py::return_value_policy::reference
,
116 py::arg("complexity") = benchmark::oAuto
);
118 using benchmark::Counter
;
119 py::class_
<Counter
> py_counter(m
, "Counter");
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
)
133 .def(py::self
| py::self
);
135 py::enum_
<Counter::OneK
>(py_counter
, "OneK")
136 .value("kIs1000", Counter::OneK::kIs1000
)
137 .value("kIs1024", Counter::OneK::kIs1024
)
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
>();
151 py::bind_map
<benchmark::UserCounters
>(m
, "UserCounters");
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
);
175 m
.def("Initialize", Initialize
);
176 m
.def("RegisterBenchmark", RegisterBenchmark
,
177 py::return_value_policy::reference
);
178 m
.def("RunSpecifiedBenchmarks",
179 []() { benchmark::RunSpecifiedBenchmarks(); });