* Add fast_type_map, use it authoritatively for local types and as a hint for global types nanobind has a similar two-level lookup strategy, added and explained by https://github.com/wjakob/nanobind/commit/b515b1f7f2f4ecc0357818e6201c94a9f4cbfdc2 In this PR I've ported this approach to pybind11. To avoid an ABI break, I've kept the fast maps to the `local_internals`. I think this should be safe because any particular module should see its `local_internals` reset at least as often as the global `internals`, and misses in the fast "hint" map for global types fall back to the global `internals`. Performance seems to have improved. Using my patched fork of pybind11_benchmark (https://github.com/swolchok/pybind11_benchmark/tree/benchmark-updates, specifically commit hash b6613d12607104d547b1c10a8145d1b3e9937266), I run bench.py and observe the MyInt case. Each time, I do 3 runs and just report all 3. master, Mac: 75.9, 76.9, 75.3 nsec/loop this PR, Mac: 73.8, 73.8, 73.6 nsec/loop master, Linux box: 188, 187, 188 nsec/loop this PR, Linux box: 164, 165, 164 nsec/loop Note that the "real" percentage improvement is larger than implied by the above because master does not yet include #5824. * simplify unsafe_reset_local_internals in test * pre-implement PYBIND11_INTERNALS_VERSION 12 * use PYBIND11_INTERNALS_VERSION 12 on Python 3.14 per suggestion * Implement reviewer comments: revert PY_VERSION_HEX change, fix REVIEW comment, add two-level lookup comments. ci.yml coming separately * Use the inplace build to smoke test ABI bump? * [skip ci] Remove "smoke" from comment. This is full testing, just only on a few platforms. --------- Co-authored-by: Ralf W. Grosse-Kunstleve <rgrossekunst@nvidia.com>
40 lines
1.3 KiB
C++
40 lines
1.3 KiB
C++
#include <pybind11/pybind11.h>
|
|
|
|
namespace py = pybind11;
|
|
|
|
/* Simple test module/test class to check that the referenced internals data of external pybind11
|
|
* modules aren't preserved over a finalize/initialize.
|
|
*/
|
|
|
|
namespace {
|
|
// Compare unsafe_reset_internals_for_single_interpreter in
|
|
// test_subinterpreter.cpp.
|
|
void unsafe_reset_local_internals() {
|
|
// NOTE: This code is NOT SAFE unless the caller guarantees no other threads are alive
|
|
// NOTE: This code is tied to the precise implementation of the internals holder
|
|
|
|
py::detail::get_local_internals_pp_manager().unref();
|
|
py::detail::get_local_internals();
|
|
}
|
|
} // namespace
|
|
|
|
PYBIND11_MODULE(external_module,
|
|
m,
|
|
py::mod_gil_not_used(),
|
|
py::multiple_interpreters::per_interpreter_gil()) {
|
|
// At least one test ("Single Subinterpreter") wants to reset
|
|
// internals. We have separate local internals because we are a
|
|
// separate DSO, so ours need to be reset too!
|
|
unsafe_reset_local_internals();
|
|
class A {
|
|
public:
|
|
explicit A(int value) : v{value} {};
|
|
int v;
|
|
};
|
|
|
|
py::class_<A>(m, "A").def(py::init<int>()).def_readwrite("value", &A::v);
|
|
|
|
m.def("internals_at",
|
|
[]() { return reinterpret_cast<uintptr_t>(&py::detail::get_internals()); });
|
|
}
|