-
Notifications
You must be signed in to change notification settings - Fork 2.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
WIP: PyPy support #527
WIP: PyPy support #527
Conversation
Related discussion on the PyPy bug tracker: https://bitbucket.org/pypy/pypy/issues/2434/support-pybind11-in-conjunction-with-pypys |
A progress update here:
Cheers, |
Nice! That went pretty quickly from "Hello, World" to 95% of the test suite :) Just a quick comment regarding number 6: while gc.collect():
pass |
It doesn't work. PyPy always returns zero from |
I filed a bug report regarding the reference counting leak involving the buffer protocol: https://bitbucket.org/pypy/pypy/issues/2444/pypy-cpyext-reference-counting-leak-when |
PyPy bugreport regarding multiple inheritance: https://bitbucket.org/pypy/pypy/issues/2445/support-pybind11-in-conjunction-with-pypys |
Hi. PyPY dev here. I am slowly looking into the issues raised. About "PyPy doesn't seem to register class docstrings for some reason" - once PyType_Ready is called, no changes to the c PyTypeObject struct will be reflected into app-level python. About reference counting, we do not support sys.getrefcount() at all and do not promise to collect objects that have been freed. We will not support using del as a mechanism to do anything but free resources. And in more detail: We create an internal app-level object when PyType_Ready is called that reflects the c-level object, we track the refcount of the c-level object and when it goes to 0 may delete both objects at our convenience but our garbage collection is a mark-and-sweep scheme, however if there is no memory pressure we may choose to not collect anything. When we do call the del method on objects, it may be during the execution of exit() from the interpreter. We do not currently have a mechanism to update the app-level object from the c-level object (except in some special cases) after PyType_Ready is called. |
Hi @mattip, cool, that's fantastic -- thank you for taking a look. Meanwhile, I've posted a followup to the multiple inheritance issue on the PyPy issue tracker. I've created a new ticket about the issue involving The design decisions regarding the Thanks, |
ad797b7
to
f3519d6
Compare
Seeing as PyPy doesn't guarantee cleanup until exit and in general GC behavior can vary based on config and platform, it may be good to disable Perhaps a global option can be added to pytest and guard all |
My impression was that PyPy uses an asynchronous tri-color collector that might not have captured an object that has become garbage in the current iteration (the object might have been referenced at the beginning of that GC cycle), but it will do so in the next one at the latest. Having spent quite a while with this, my practical experience was that two calls of |
The two main issues (multiple inheritance, docstrings) are now fixed in PyPy 🎉 That just leaves the refcounting issue involving the buffer protocol, and I think we're ready to ship this: https://bitbucket.org/pypy/pypy/issues/2444/pypy-cpyext-reference-counting-leak-when |
Slightly off-topic, but I noticed that |
Agreed. I vouch for linelength of 99 or 100 :) |
@aldanor: this sounds fine. I don't remember why I reflowed that file, probably it did not fit into my arbitrarily sized editor window :) |
6a113ab
to
3f4e1a9
Compare
^ @aldanor, @dean0x7d, @jagerman, @lyskov, @SylvainCorlay, @JohanMabille, @pschella I believe that the few remaining PyPy integration issues will be addressed shortly (the PyPy devs have been super-responsive and already fixed most of the items I reported) This means PyPy support can be part of pybind11 2.0 🎉 . Since it's a somewhat intrusive breaking change (new system and public interface for creating objects with metaclasses and supporting the buffer object protocol), it would be good to have some extra pairs of eyes looking at this PR. Thanks, |
@@ -1,10 +1,16 @@ | |||
import gc | |||
|
|||
|
|||
def collect(): | |||
gc.collect() | |||
gc.collect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This function also appears in test_keep_alive.py
and test_numpy_array.py
. To avoid duplication, it's probably worth adding it to pytest_namespace
in conftest.py
. Then it can be called like pytest.gc_collect()
.
@@ -111,6 +111,11 @@ def test_property_return_value_policies(access): | |||
assert getattr(obj, access + "_func").value == 1 | |||
|
|||
|
|||
@pytest.mark.parametrize("access", ["static_ro", "static_rw"]) | |||
def test_property_return_value_policies_static(access): | |||
test_property_return_value_policies(access) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this can be merged back with the test above now that PyPy doesn't need to skip the static part.
"""When returning an rvalue, the return value policy is automatically changed from | ||
`reference(_internal)` to `move`. The following would not work otherwise. | ||
""" | ||
from pybind11_tests import TestPropRVP |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same as previous comment.
@@ -19,6 +19,7 @@ def test_roundtrip(): | |||
|
|||
|
|||
def test_roundtrip_with_dict(): | |||
return False |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, this test was being skipped but was reported as 'passed' because there were no assertion errors. Should be checked on PyPy.
@@ -119,8 +119,12 @@ def __repr__(self): | |||
assert cstats.alive() == 0 | |||
|
|||
|
|||
def test_docs(doc): | |||
# PyPy does not seem to propagate the tp_docs field at the moment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wasn't this fixed? Leftover comment?
I have tried running my project tests while using this PR code but i am running into what looks like memory error in almost all of them:
I will see if i can obtain a better backtrace... |
ok on Mac OS, i can see extra message: And i got the following backtrace:
Please let me know if there is anything else i can do to help |
The Python line that lead to this is nothing special: pybind11::class_<core::pose::Pose, std::shared_ptr<core::pose::Pose>> cl(M("core::pose"), "Pose", "...");
pybind11::handle cl_type = cl;
cl.def(pybind11::init<>());
cl.def(pybind11::init<const class core::pose::Pose &>(), pybind11::arg("src"));
cl.def(pybind11::init<const class core::pose::Pose &, unsigned long, unsigned long>(), pybind11::arg("src"), pybind11::arg("residue_begin"), pybind11::arg("residue_end"));
... |
Right, of course.. |
looks like there is a few new commits now available in @jagerman could it be that you missing that example is using |
@lyskov - no, the reference_internal isn't the problem, that just uses a keep-alive to delay to Container destruction until after the Data destruction. That part is working: the second Data destruction is happening when Container gets destroyed. |
That's probably just luck, the core problem is still there. |
hmmm, ok... then i have questions:
|
Also, i was under the impression that object held with |
Ah, right, I forgot about that. So yes, it is fixed (but you'd run into it again if you returned a pointer). |
So, how do i need to bind function that will return pointer to object that should not be deleted? |
Scratch what I said, you should be fine with a pointer, too. |
ok, i am re-compiling my tests with an updated version of this PR and will post when i have testing results. |
For never deleting an object, there are two options:
As for double delete problems, I believe those are now only a risk with the |
Great, thank you for clarifying this @dean0x7d ! And i will see if i can refactor my code to use |
Your T* holder declaration isn't doing anything anyway. |
@jagerman i guess it does not now, but it was indeed needed before. A while back binding like: |
Hmm, I think that right now there is actually no difference between: py::class_<MyClass, std::unique_ptr<MyClass, py::nodelete>>(m, "MyClass") and py::class_<MyClass, MyClass*>(m, "MyClass") Unless I'm overlooking something? |
I assume you mean with the T* holder declaration (without it you get a static assertion failure). |
Ah, I forgot about the |
allright, i just run my set of tests with a new version of source and this time i see no issues so as far as i can tell everything is working! |
This is merged now. |
Kudos on this one. This is great that it got through. |
The readme/docs say:
But I think this should be >= 5.7 (future version, current nightly). Last time I checked 5.6 doesn't even compile. |
I wonder if it would be useful to put a static_assert testing for known-unsupported compilers. E.g. it could catch gcc < 4.8, MSVC < 2015 update 3, ICC < 15. And perhaps protected with a |
@jagerman: sounds like a nice idea! |
@dean0x7d: fixed, thanks |
This commit includes a few minor modifications to pybind11 that are needed to get simple hello-world style functions to compile and run on the latest PyPy. Types are now supported as well.
The test suite compiles but crashes when executed.