You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
I have a case where I'd like to have fast access to the C++ object wrapped in a Python object of a given type, or raise an error if the object is not an instance of that type. The type is a custom base C++ class bound via py::class_. Unfortunately, pybind11’s generic casting is too slow.
I think the problem is similar to the performance issues discussed in #376, but here regarding Python -> C++ conversion.
More context
I’d like to expose functions taking Numpy arrays of numpy.object dtype as arguments, where the objects are instances of a custom C++ class exposed in Python. For example:
py::array_t<int> get_int_property(const py::array_t<py::object> arr) {
py::buffer_info buf = arr.request();
auto result = py::array_t<int>(buf.size);
py::buffer_info result_buf = result.request();
int *rptr = static_cast<int *>(result_buf.ptr);
for (size_t i = 0; i < buf.size; i++) {
// Parent is a pybind11 registered C++ class (see below)auto parent_ptr = (*arr.data(i)).cast<Parent*>();
rptr[i] = parent_ptr->get_int_property();
}
return result;
}
The input arrays potentially have millions of elements. Unfortunately, >90% of the execution time is spent doing the Python -> C++ cast and <10% is spent executing the C++ trivial method. Ideally the Python -> C++ cast should be very cheap (on par with the execution time of the C++ method here).
From a pybind11 handle I can access to a Parent object like this:
// a Child or AnotherChild instance wrapped in a Python object
py::handle h;
auto parent_ptr = h.cast<Parent*>();
But it is 10x slower than just doing:
auto inst = reinterpret_cast<py::detail::instance *>(h.ptr());
auto parent_ptr = reinterpret_cast<Parent*>(inst->simple_value_holder[0]);
For obvious safety reasons, I'd need checking the type of the Python object first. Basically I could do this:
PyTypeObject *parent_pytype = py::detail::get_type_info(typeid(Parent))->type;
PyTypeObject *h_type = Py_TYPE(h.ptr());
if(!PyType_IsSubtype(h_type, parent_type)) {
throwpy::type_error("not a Parent object");
}
auto inst = reinterpret_cast<py::detail::instance *>(h.ptr());
auto parent_ptr = reinterpret_cast<Parent*>(inst->simple_value_holder[0]);
Or just use py::isinstance().
But still, py::detail::get_type_info is a real bottleneck. As I understand, it looks into pybind11 registered types, which is wasteful doing for each conversion in my case. I'd just need to get the PyTypeObject * of the Parent class once, after it has been registered.
I could certainly implement some kind of cache, so that get_type_info is called only once. That's not public API, though. Is there any way to get the type information without relying on pybind11 internals? AFAIU (#1572) this is not supported?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
-
Summary
I have a case where I'd like to have fast access to the C++ object wrapped in a Python object of a given type, or raise an error if the object is not an instance of that type. The type is a custom base C++ class bound via
py::class_
. Unfortunately, pybind11’s generic casting is too slow.I think the problem is similar to the performance issues discussed in #376, but here regarding Python -> C++ conversion.
More context
I’d like to expose functions taking Numpy arrays of
numpy.object
dtype as arguments, where the objects are instances of a custom C++ class exposed in Python. For example:The input arrays potentially have millions of elements. Unfortunately, >90% of the execution time is spent doing the Python -> C++ cast and <10% is spent executing the C++ trivial method. Ideally the Python -> C++ cast should be very cheap (on par with the execution time of the C++ method here).
Details
My case looks very much like this:
From a pybind11 handle I can access to a
Parent
object like this:But it is 10x slower than just doing:
For obvious safety reasons, I'd need checking the type of the Python object first. Basically I could do this:
Or just use
py::isinstance()
.But still,
py::detail::get_type_info
is a real bottleneck. As I understand, it looks into pybind11 registered types, which is wasteful doing for each conversion in my case. I'd just need to get the PyTypeObject * of theParent
class once, after it has been registered.I could certainly implement some kind of cache, so that
get_type_info
is called only once. That's not public API, though. Is there any way to get the type information without relying on pybind11 internals? AFAIU (#1572) this is not supported?Beta Was this translation helpful? Give feedback.
All reactions