ronan has quit [Ping timeout: 250 seconds]
ronan has joined #hpy
ronan has quit [Ping timeout: 252 seconds]
ronan has joined #hpy
<antocuni> uhm, I have a doubt about HPyField&co.
<antocuni> in CPython, if I have a custom object with a PyObject* field, and this field only contains atomic types such as long or str, it is not required to set Py_TPFLAGS_HAVE_GC and tp_traverse
<antocuni> but in HPy, we will probably need the equivalent of tp_traverse for *every* type with HPyField fields
<antocuni> I wonder whether this might cause a slowdown on CPython
_whitelogger has joined #hpy
Joannah has joined #hpy
<Hodgestar> I wonder if we could make HPyField a sort of case to and from a long-lived pointer to the underlying data? So `HPyField_Store(ctx, h)` returns an opaque thing which in CPython might be just a pointer to the struct, but on PyPy is something else (???), and `HPyField_Load(ctx, opaque_thing)` returns a new handle. And perhaps `HPyField_Release(ctx, opaque_thing)` to say you are done with the thing you stored?
<Hodgestar> s/case/cast/
<Hodgestar> s/long-lived pointer/long-lived opaque thing/
<antocuni> Hodgestar: isn't this exactly the plan?
<Hodgestar> Maybe that is not different enough to the current idea to help avoid having to always do tp_traverse?
<antocuni> Hodgestar: the current idea is explained here: https://github.com/hpyproject/hpy/issues/9
<antocuni> and it looks exactly like what you describe, although with different names
<Hodgestar> What if there were two kinds of HPyField? One for built-in atomic types that don't need traverse and one for more general types?
<antocuni> but you still need tp_traverse; e.g. the pypy GC needs to find all the alive objects
<Hodgestar> antocuni: Well, at least I seem to remember the plan, even if I don't know I remember the plan? :)
<Hodgestar> antocuni: But then PyPy HPy can just also have a non-trivial tp_traverse for HPyAtomicField too? And CPython mode can not?
<antocuni> yes, I suppose that it would work
<antocuni> although I'm not sure I like the idea of introducing yet another concept
<antocuni> another option is to let the user to declare "I promise this type does not need GC support" in the type spec
<antocuni> i.e., correct-but-slightly-slower by default, but with the possibility to override the behavior on CPython to get back the previous speed
<Hodgestar> What would "does not need GC support" mean on PyPy and GraalPython?
<antocuni> probably nothing
<antocuni> but it means something on CPython
<antocuni> i.e., it's a flag which enables a faster implementation when running on CPython1
<Hodgestar> It would be nice we if did not have to include such a legacy concept in the API.
<antocuni> I agree, but HPyAtomicField is basically the same legacy concept
<Hodgestar> I wonder if there is a better concept that will allow faster implementations for any implementation if there is one to be had.
<Hodgestar> Re HPyAtomicField: Agreed.
<antocuni> so, the core of the issue is how CPython manages memory
<antocuni> refcount works in 90% of the cases
<antocuni> for the rest 10% you need gc.collect(), and for gc.collect() to work you need tp_traverse + Py_TPFLAGS_HAVE_GC
<antocuni> basically, if you are sure that your PyObject* fields can't have references to other PyObject* fields, you can avoid Py_TPFLAGS_HAVE_GC
<Hodgestar> Could one imagine PyPy not needing tp_traverse in some optimized cases somehow?
<antocuni> personally, I can't
<Hodgestar> What if the jit knew that the gc root was always held somewhere else too in specific cases? (not sure if I am using the right words here)
<antocuni> it's still bad, because if it moves the object it needs to know which locations to update
<Hodgestar> Ah. :|
<Hodgestar> An HPyField wouldn't necessarily need to know about the moved address though -- HPyField_Load could find the new address when the handle is created.
<antocuni> I *think* that a more general concept is: a type can be !Py_TPFLAGS_HAVE_GC if all it's PyObject* fields are !Py_TPFLAGS_HAVE_GC
<antocuni> but I'm not 100% sure it's correct, since the docs use a more vague wording:
<antocuni> "Types which do not store references to other objects, or which only store references to atomic types (such as numbers or strings), do not need to provide any explicit support for garbage collection."
marvin__ has quit [Remote host closed the connection]
marvin_ has joined #hpy
<antocuni> FWIW, I started to work on HPyField in this WIP PR: https://github.com/hpyproject/hpy/pull/228
<Hodgestar> Why does HPyField require tp_traverse at all? Could it instead hold some other fixed reference and any pointers are only looked up when HPyField_Load is called? Would would holding those fixed references require too much overhead? In CPython the fixed reference could really be a fixed pointer and an incref to keep it alive.
<Hodgestar> I should really look at the actual implementation before suggesting more things, but that will have to wait a couple of days (I am trying to get through some other work stuff and tomorrow I am off for my birthday).
<antocuni> happy early birthday then :)
<antocuni> I don't understand your suggestion about "fixed references" though
<Hodgestar> Thank you. :)
<Hodgestar> Re fixed references: E.g. HPyField returns an index n into a big global list of field references. Then the GC only needs to know to update the references in the big global list. HPyField_Load(ctx, n) then returns a handle that has the new address. Maybe this is a bad idea, but that's the sort of picture I had in mind.
<antocuni> I'm happy to be proven wrong, but this sounds slow on both CPython AND PyPy :), and probably GraalPython too
<antocuni> also, if it needs to be an index into a list, we could just store HPys there
<antocuni> plus, you would need to HPyField_Close() those references upon deletions
<antocuni> and you still need the tp_traverse on CPython
<antocuni> so, it sounds like the worst of all words :)
<Hodgestar> Yes, the problem is that then many many objects will need to be stored twice and an explicit close would be needed.
<Hodgestar> What about just a flag which says whether a type holds fields? If it doesn't hold fields then it can't be involved in a reference cycle and maybe that is useful for other implementations to know too?
<antocuni> I think we are going in circles here :)
<Hodgestar> Quite possibly. I will be quiet for now.
<antocuni> so, the current idea/solution/design is that types having HPyField fields will also need to provide the equivalent of tp_traverse (maybe with another name)
<antocuni> so, having tp_traverse is equivalent of setting this flag
<antocuni> and HPyType_FromSpec will create a CPython type with Py_TPFLAGS_HAVE_GC + tp_traverse accordingly
<antocuni> my concern is for those types which will have HPyField, but that currently on CPython don't need Py_TPFLAGS_HAVE_GC
<antocuni> a naive implementation will set Py_TPFLAGS_HAVE_GC on *all* those types, even though for some of them it's suboptimal
<antocuni> but the more I think of it, the more I am convinced that it should be the user to explicitly select which kind of behavior wants
* antocuni off
mattip has quit [Ping timeout: 258 seconds]
mattip has joined #hpy