[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Petr Viktorin

On 15. 12. 21 23:57, Guido van Rossum wrote:
On Wed, Dec 15, 2021 at 6:04 AM Antoine Pitrou > wrote:


On Wed, 15 Dec 2021 14:13:03 +0100
Antoine Pitrou mailto:anto...@python.org>> wrote:

 > Did you try to take into account the envisioned project for adding a
 > "complete" GC and removing the GIL?

Sorry, I was misremembering the details.  Sam Gross' proposal
(posted here on 07/10/2021) doesn't switch to a "complete GC", but it
changes reference counting to a more sophisticated scheme (which
includes immortalization of objects):


https://docs.google.com/document/d/18CXhDb1ygxg-YXNBJNzfzZsDFosB5e6BfnXLlejd9l0/edit




A note about this: Sam's immortalization covers exactly the objects that 
Eric is planning to move into the interpreter state struct: "such as 
interned strings, small integers, statically allocated PyTypeObjects, 
and the True, False, and None objects". (Well, he says "such as" but I 
think so does Eric. :-)


Sam's approach is to use the lower bit of the ob_refcnt field to 
indicate immortal objects. This would not work given the stable ABI 
(which has macros that directly increment and decrement the ob_refcnt 
field). In fact, I think that Sam's work doesn't preserve the stable ABI 
at all. However, setting a very high bit (the bit just below the sign 
bit) would probably work. Say we're using 32 bits. We use the value 
0x_6000_ as the initial refcount for immortal objects. The stable 
ABI will sometimes increment this, sometimes decrement it. But as long 
as the imbalance is less than 0x_2000_, the refcount will remain in 
the inclusive range [ 0x_4000_ , 0x_7FFF_ ] and we can test for 
immortality by testing a single bit:


if (o->ob_refcnt & 0x_4000_)

I don't know how long that would take, but I suspect that a program that 
just increments the refcount relentlessly would have to run for hours 
before hitting this range. On a 64-bit machine the same approach would 
require years to run before a refcount would exceed the maximum 
allowable imbalance. (These estimates are from Mark Shannon.)


But does the sign bit need to stay intact, and do we actually need to 
rely on the immortal bit to always be set for immortal objects?
If the refcount rolls over to zero, an immortal object's dealloc could 
bump it back and give itself another few minutes.
Allowing such rollover would mean having to deal with negative 
refcounts, but that might be acceptable.


Another potential issue is that there may be some applications that take 
refcounts at face value (perhaps obtained using sys.getrefcount()). 
These would find that immortal objects have a very large refcount, which 
might surprise them. But technically a very large refcount is totally 
valid, and the kinds of objects that we plan to immortalize are all 
widely shared -- who cares if the refcount for None is 5000 or 
1610612736? As long as the refcount of *mortal* objects is the same as 
it was before, this shouldn't be a problem.


A very small refcount would be even more surprising, but the same logic 
applies: who cares if the refcount for None is 5000 or -5000?



___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/2RZLYU2YPJET6SQYDORFEQSE53KPPCYJ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Petr Viktorin



On 16. 12. 21 2:54, Guido van Rossum wrote:
(I just realized that we started discussing details of immortal objects 
in the wrong thread -- this is Eric's overview thread, there's a 
separate thread on immortal objects. But alla, I'll respond here below.)


On Wed, Dec 15, 2021 at 5:05 PM Neil Schemenauer > wrote:


On 2021-12-15 2:57 p.m., Guido van Rossum wrote:


But as long as the imbalance is less than 0x_2000_, the
refcount will remain in the inclusive range [ 0x_4000_ ,
0x_7FFF_ ] and we can test for immortality by testing a single
bit:

if (o->ob_refcnt & 0x_4000_)


Could we have a full GC pass reset those counts to make it even more
unlikely to get out of bounds?

Maybe, but so far these are all immutable singletons that aren't linked 
into the GC at all. Of course we could just add extra code to the GC 
code that just resets all these refcounts, but since there are ~260 
small integers that might slow things down more than we'd like. More 
testing is required. Maybe we can get away with doing nothing on 64-bit 
machines but we'll have to slow down a tad for 32-bit -- that would be 
acceptable (since the future is clearly 64-bit).


Allocating immortal objects from a specific memory region seems like
another idea worth pursuing.  It seems mimalloc has the ability to
allocate pools aligned to certain large boundaries. That takes some
platform specific magic.   If we can do that, the test for
immortality is pretty cheap.  However, if you can't allocate them at
a fixed region determined at compile time, I don't think you can
match the performance of the code above. Maybe it helps that you
could determine immortality by looking at the PyObject pointer and
without loading the ob_refcnt value from memory?  You would do
something like:

if (((uintptr_t)o) & _Py_immortal_mask)

The _Py_immortal_mask value would not be known at compile time but
would be a global constant.  So, it would be cached by the CPU.


Inmmortal objects should be allocated dynamically. AFAIK, determining 
whether something was malloc'd or not would need to be platform-specific.




___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/6Q2FQNLUKTBBRRBMN7DB5UP4RKCMQRLQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Petr Viktorin

On 16. 12. 21 3:41, Jim J. Jewett wrote:

In Python 3.11, Python still implements around 100 types as "static
types" which are not compatible with subinterpreters, like
&PyLong_Type and &PyUnicode_Type. I opened
https://bugs.python.org/issue40601 about these static types, but it
seems like changing it may break the C API *and* the stable ABI (maybe
a clever hack will avoid that).


If sub-interpreters each need their own copy of even immutable built-in types, 
then what advantage do they have over separate processes?


They need copies of all *Python* objects. A non-Python library may allow 
several Python wrappers/proxies for a single internal object, 
effectively sharing that object between subinterpreters.
(Which is a problem for removing the GIL -- currently all operations 
done by such wrappers are protected by the GIL.)

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KNMHKD3EXPXIMYEQOHEQ76DK64YRNQQX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Static types and subinterpreters running in parallel

2021-12-16 Thread Victor Stinner
Hi,

One option to solve the https://bugs.python.org/issue40601 "[C API]
Hide static types from the limited C API" issue without breaking the
backward compatibility is to leave the C API and the stable ABI as
they are for the main interpreter (static types), but force
subinterpreters running in parallel to use their own heap types. It
means that subinterpreters would be able to use the main interpreter
GIL or own their GIL. By default, the GIL would still be shared.

C extensions using "&PyLongType" (static type) would continue to work
in the main interpreter.

C extensions which want to opt-in for running subinterpreters in
parallel would not access to "&PyLong_Type" but be forced to call
PyLong_GetType() (heap type).

Internally, Python should be modified to replace "&PyLongType" with
PyLong_GetType(). So the code would work with static types and heap
types.

It also means that a subinterpreter running in parallel would only be
able to import C extensions built with explicit support for this
feature. Otherwise, an ImportError would be raised.

Victor
-- 
Night gathers, and now my watch begins. It shall not end until my death.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/QTY25AHCLOXRCQ2LADUUZFVKNVLLYS25/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Victor Stinner
On Thu, Dec 16, 2021 at 2:29 AM Nathaniel Smith  wrote:
> On Wed, Dec 15, 2021 at 3:07 AM Victor Stinner  wrote:
> > I wrote https://bugs.python.org/issue39511 and
> > https://github.com/python/cpython/pull/18301 to have per-interpreter
> > None, True and False singletons. My change is backward compatible on
> > the C API: you can still use "Py_None" in your C code. The code gets
> > the singleton object from the current interpreter with a function
> > call:
> >
> > #define Py_None Py_GetNone()
> >
> > Py_GetNone() is implemented as: "return _PyInterpreterState_GET()->none;"
>
> It's backward compatible for the C API, but not for the stable C ABI
> -- that exports Py_None directly as a symbol.

You're right. But we can add a macro like Py_SUBINTERPRETER_API which
would change the implementation:

* By default, "Py_None" would continue returning "&_Py_NoneStruct".
* If Py_SUBINTERPRETER_API macro is defined, Py_None would call Py_GetNone().

=> no impact on the stable ABI (if used, the stable ABI is not supported)

=> no impact on performance (if not used)

=> only C extensions which opt-in for "subinterpreter running in
parallel" support (define Py_SUBINTERPRETER_API) would be impacted.

Stdlib C extensions would have to be built with Py_SUBINTERPRETER_API,
but it is ok if the require a recent ABI since they are shipped with
Python directly (and not currently built with the limited C API).

Victor
-- 
Night gathers, and now my watch begins. It shall not end until my death.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/WNPPGD5HXOMWNHHR7INW5JFBLEENWFIV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Petr Viktorin

On 16. 12. 21 11:52, Victor Stinner wrote:

On Thu, Dec 16, 2021 at 2:29 AM Nathaniel Smith  wrote:

On Wed, Dec 15, 2021 at 3:07 AM Victor Stinner  wrote:

I wrote https://bugs.python.org/issue39511 and
https://github.com/python/cpython/pull/18301 to have per-interpreter
None, True and False singletons. My change is backward compatible on
the C API: you can still use "Py_None" in your C code. The code gets
the singleton object from the current interpreter with a function
call:

 #define Py_None Py_GetNone()

Py_GetNone() is implemented as: "return _PyInterpreterState_GET()->none;"


It's backward compatible for the C API, but not for the stable C ABI
-- that exports Py_None directly as a symbol.


You're right. But we can add a macro like Py_SUBINTERPRETER_API which
would change the implementation:

* By default, "Py_None" would continue returning "&_Py_NoneStruct".
* If Py_SUBINTERPRETER_API macro is defined, Py_None would call Py_GetNone().

=> no impact on the stable ABI (if used, the stable ABI is not supported)


The stable ABI could be orthogonal here -- you could compile for the 
stable ABI even with Py_SUBINTERPRETER_API.


This would require (_PyInterpreterState_GET()->none == Py_None) in the 
"main" interpreter, and extrensions without Py_SUBINTERPRETER_API only 
loadable in the "main" interpreter.



=> no impact on performance (if not used)


But it *would* be used in all of the stdlib, right?


=> only C extensions which opt-in for "subinterpreter running in
parallel" support (define Py_SUBINTERPRETER_API) would be impacted.

Stdlib C extensions would have to be built with Py_SUBINTERPRETER_API,
but it is ok if the require a recent ABI since they are shipped with
Python directly (and not currently built with the limited C API).

Victor


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/AYZ5434A555PTO2VULF3VWADSUJXBG7S/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Victor Stinner
On Thu, Dec 16, 2021 at 12:00 AM Guido van Rossum  wrote:
> Sam's approach is to use the lower bit of the ob_refcnt field to indicate 
> immortal objects. This would not work given the stable ABI (which has macros 
> that directly increment and decrement the ob_refcnt field). (...) we can test 
> for immortality by testing a single bit:
>
> if (o->ob_refcnt & 0x_4000_)

If PyQt5 or pycryptography is built with the Python 3.9 limited C API,
it will use the old Py_INCREF/Py_DECREF which doesn't have special
code for immortal objects.

I understand that if a C extension built for an old stable ABI
decrements the refcount below the limit, the object becomes mortal
(can be deleted), no?

I'm thinking about the case when a C extension is used in
subinterpreters run in parallel (one GIL per interpreter) without any
kind of locking around Py_INCREF/Py_DECREF: "data races" made "on
purpose" (to not make Py_INCREF/Py_DECREF slower for the general
case). Or you can think about a similar scenario with the "nogil"
project.

For now, I suggest to consider "subinterpreters running in parallel"
and nogil use cases as special and require to build C extensions with
a special option, since there are other C API changes which are
incompatible with the stabl ABI anyway.

* Subinterpreters running in parallel are not compatible with static
type: it requires to change the ABI
* nogil changes PyObject structure, Py_INCREF and Py_DECREF: it
requires to change the ABI

Victor
-- 
Night gathers, and now my watch begins. It shall not end until my death.
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/L5OXHXPFONRKLR3W6U46LUSUIBN4FCZQ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Antoine Pitrou
On Thu, 16 Dec 2021 14:32:05 +1100
Steven D'Aprano  wrote:
> On Wed, Dec 15, 2021 at 02:57:46PM -0800, Guido van Rossum wrote:
> 
> > Another potential issue is that there may be some applications that take
> > refcounts at face value (perhaps obtained using sys.getrefcount()). These
> > would find that immortal objects have a very large refcount, which might
> > surprise them. But technically a very large refcount is totally valid, and
> > the kinds of objects that we plan to immortalize are all widely shared --
> > who cares if the refcount for None is 5000 or 1610612736? As long as the
> > refcount of *mortal* objects is the same as it was before, this shouldn't
> > be a problem.  
> 
> I agree with your reasoning. But can we agree to document the presence 
> and interpretation of the magic bit, so that if anyone actually does 
> care (for whatever reason, good bad or indifferent) they can mask off 
> the immortal bit to get the real ref num?

The "real number of references" would not be known for immortal objects.

Regards

Antoine.


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/W67N2OEYKUOIH2A67J5LMY2SZ7C4KMTX/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Antoine Pitrou
On Tue, 14 Dec 2021 10:38:25 -0700
Eric Snow  wrote:
> 
> So we (the core devs) would effectively be requiring those extensions
> to support subinterpreters, regardless of letting them opt out.  This
> situation has been weighing heavily on my mind since Nathaniel brought
> this up.  Here are some ideas I've had or heard of about what we could
> do to help:
> 
> * add a page to the C-API documentation about how to support subinterpreters
> * identify the extensions most likely to be impacted and offer to help
> * add more helpers to the C-API to make adding subinterpreter support
> less painful
> * fall back to loading the extension in its own namespace (e.g. use 
> ldm_open())
> * fall back to copying the extension's file and loading from the copied file
> * ...

As a data point, in PyArrow, we have a bunch of C++ code that interacts
with Python but doesn't belong in a particular Python module.  That C++
code can of course have global state, including perhaps Python objects.

What might be nice would be a C API to allow creating interpreter-local
opaque structs, for example:

void* Py_GetInterpreterLocal(const char* unique_name);
void* Py_SetInterpreterLocal(const char* unique_name,
 void* ptr, void(*)() destructor);


Then in extension code you'd be able to write, e.g.:


typedef struct {
  PyObject* cached_decimal;
  std::vector some_other_data;
} MyLocalState ;

static void destroy_state(MyLocalState* state) {
  Py_XDECREF(state->cached_decimal);
  delete state;
}

static MyLocalState* get_state() {
  MyLocalState* state = NULL;
  state = Py_GetInterpreterLocal("pyarrow._lib.internal");
  if (state == NULL) {
state = new MyLocalState;
Py_SetInterpreterLocal("pyarrow._lib.internal", state,
   destroy_state);
  }
  return state;
}


PyObject* get_decimal_module() {
  MyLocalState* state = get_state();
  if (state->cached_decimal == NULL) {
state->cached_decimal = PyImport_ImportModule("decimal");
  }
  return state->cached_decimal;
}



> 
>  I'd appreciate your thoughts on what we can do to help.  Thanks!
> 
> -eric



___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/TTVWSOOVMY2AKYARI5VSQ3RF4U7DHLX6/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Petr Viktorin

On 16. 12. 21 12:33, Antoine Pitrou wrote:

On Tue, 14 Dec 2021 10:38:25 -0700
Eric Snow  wrote:


So we (the core devs) would effectively be requiring those extensions
to support subinterpreters, regardless of letting them opt out.  This
situation has been weighing heavily on my mind since Nathaniel brought
this up.  Here are some ideas I've had or heard of about what we could
do to help:

* add a page to the C-API documentation about how to support subinterpreters
* identify the extensions most likely to be impacted and offer to help
* add more helpers to the C-API to make adding subinterpreter support
less painful
* fall back to loading the extension in its own namespace (e.g. use ldm_open())
* fall back to copying the extension's file and loading from the copied file
* ...


As a data point, in PyArrow, we have a bunch of C++ code that interacts
with Python but doesn't belong in a particular Python module.  That C++
code can of course have global state, including perhaps Python objects.

What might be nice would be a C API to allow creating interpreter-local
opaque structs, for example:

void* Py_GetInterpreterLocal(const char* unique_name);
void* Py_SetInterpreterLocal(const char* unique_name,
  void* ptr, void(*)() destructor);


Then in extension code you'd be able to write, e.g.:




What's the reason these can't be tied to the module?
(As the author of PEP 630, which argues that module state is the best 
default place for this kind of mutable "globals", I'm interested in the 
cases where it isn't so.)


How do you ensure these Python objects are destroyed by/before 
Py_Finalize()? (If you do that -- I realize it's not something people 
typically think about.)

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/QUHYVSXGQHXONLRLZNOMH5VMRS44PHPO/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Steven D'Aprano
On Thu, Dec 16, 2021 at 12:23:09PM +0100, Antoine Pitrou wrote:
> 
> The "real number of references" would not be known for immortal objects.

Oh that surprises me. How does that work? Does that imply that some code 
might not increment the ref count, while other code will?


-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/EBSQGPCX67AFL5YK2UBKOR7PQS2LNLXZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Antoine Pitrou
On Thu, 16 Dec 2021 23:32:17 +1100
Steven D'Aprano  wrote:
> On Thu, Dec 16, 2021 at 12:23:09PM +0100, Antoine Pitrou wrote:
> > 
> > The "real number of references" would not be known for immortal objects.  
> 
> Oh that surprises me. How does that work? Does that imply that some code 
> might not increment the ref count, while other code will?

If an object is immortal, then its refcount wouldn't change at all.

« Some objects, such as interned strings, small integers, statically
allocated PyTypeObjects, and the True, False, and None objects stay
alive for the lifetime of the program. These objects are marked as
immortal by setting the least-significant bit of the local reference
count field (bit 0). The Py_INCREF and Py_DECREF macros are no-ops for
these objects. This avoids contention on the reference count fields of
these objects when they are accessed concurrently by multiple threads. »

Regards

Antoine.


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4ILXFPPJIPXROUU52NMPKDLFV6LNEJAT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Antoine Pitrou
On Thu, 16 Dec 2021 13:25:53 +0100
Petr Viktorin  wrote:
> On 16. 12. 21 12:33, Antoine Pitrou wrote:
> > On Tue, 14 Dec 2021 10:38:25 -0700
> > Eric Snow  wrote:  
> >>
> >> So we (the core devs) would effectively be requiring those extensions
> >> to support subinterpreters, regardless of letting them opt out.  This
> >> situation has been weighing heavily on my mind since Nathaniel brought
> >> this up.  Here are some ideas I've had or heard of about what we could
> >> do to help:
> >>
> >> * add a page to the C-API documentation about how to support 
> >> subinterpreters
> >> * identify the extensions most likely to be impacted and offer to help
> >> * add more helpers to the C-API to make adding subinterpreter support
> >> less painful
> >> * fall back to loading the extension in its own namespace (e.g. use 
> >> ldm_open())
> >> * fall back to copying the extension's file and loading from the copied 
> >> file
> >> * ...  
> > 
> > As a data point, in PyArrow, we have a bunch of C++ code that interacts
> > with Python but doesn't belong in a particular Python module.  That C++
> > code can of course have global state, including perhaps Python objects.
> > 
> > What might be nice would be a C API to allow creating interpreter-local
> > opaque structs, for example:
> > 
> > void* Py_GetInterpreterLocal(const char* unique_name);
> > void* Py_SetInterpreterLocal(const char* unique_name,
> >   void* ptr, void(*)() destructor);
> > 
> > 
> > Then in extension code you'd be able to write, e.g.:
> 
> What's the reason these can't be tied to the module?

Because the module is simply not known.  This is C++ utility code
called from several different Cython extension modules.

> (As the author of PEP 630, which argues that module state is the best 
> default place for this kind of mutable "globals", I'm interested in the 
> cases where it isn't so.)

That works in a world where all third-party code using the CPython C
API lives in a particular extension module.  While it is certainly the
most common case, I doubt it is universal.

> How do you ensure these Python objects are destroyed by/before 
> Py_Finalize()? (If you do that -- I realize it's not something people 
> typically think about.)

When finalizing a given (sub)interpreter, it would visit all registered
interpreter locals and call their "destructor" callback.

Regards

Antoine.


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/R4FKSJZI366ZO76OUDF4WCY6RQRYMNCG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Steven D'Aprano
On Thu, Dec 16, 2021 at 01:46:38PM +0100, Antoine Pitrou wrote:

> If an object is immortal, then its refcount wouldn't change at all.

Ah, that makes sense, thanks for the explanation.

-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/O45UDYGAKMB7HHBB4WYLV76M3Y2XKTAY/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: my plans for subinterpreters (and a per-interpreter GIL)

2021-12-16 Thread Eric Snow
On Thu, Dec 16, 2021 at 2:48 AM Petr Viktorin  wrote:
> But does the sign bit need to stay intact, and do we actually need to
> rely on the immortal bit to always be set for immortal objects?
> If the refcount rolls over to zero, an immortal object's dealloc could
> bump it back and give itself another few minutes.
> Allowing such rollover would mean having to deal with negative
> refcounts, but that might be acceptable.

FWIW, my original attempt at immortal objects (quite a while ago) used
the sign bit as the marker (negative refcount meant immortal).
However, this broke GC and Py_DECREF() and getting those to work right
was a pain.  It also made a few things harder to debug because a
negative refcount no longer necessarily indicated something had gone
wrong.  In the end I switched to a really high bit as the marker and
it was all much simpler.

-eric
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/LJ2WVSUPJY2X3VVJW4EEEFNOBRJ7AB4V/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Eddie Elizondo via Python-Dev
I've just updated the original Immortal Instances PR with a bunch of tricks 
that I used to achieve as much performance parity as possible: 
https://github.com/python/cpython/pull/19474 . You can see the details along 
with some benchmarks in the PR itself.

This should address a bunch of the original performance concerns. Furthermore, 
it opens up the possibility of iterating on top of this to keep improving perf 
(i.e immortal intern strings, immortal heap types, less gc cycles from moving 
long lived objects to the perm gen, etc.).
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/IDG6XIL7265EYGV5ZANOTQ7SPXU55HNT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] RFC on Callable Syntax PEP

2021-12-16 Thread Steven Troxler
Hello all,

Thanks everyone for comments on our earlier thread [1] about callable type 
syntax. We now  have a draft PEP [2] proposing an arrow-based syntax for 
callable types, for example:

```
(int, str) -> bool # equivalent to Callable[[int, str], bool]
```

In support of the PEP we also have:
- a reference implementation of the parser [3] to ensure the grammar is correct 
 (tests [5], [6], [7])
- a detailed specification of planned runtime behavior [4], which is not yet in 
the reference implementation

We'd like to get your feedback about the PEP in general, and especially details 
and edge cases we need to consider regarding runtime behavior.

Cheers,
Steven Troxler

-
[1] Earlier python-dev thread 
https://mail.python.org/archives/list/python-dev@python.org/thread/VBHJOS3LOXGVU6I4FABM6DKHH65GGCUB/
[2] PEP 677: https://www.python.org/dev/peps/pep-0677/
[3] Reference implementation of Parser: 
https://github.com/stroxler/cpython/tree/callable-type-syntax--shorthand
[4] Details on the runtime behavior:  
https://docs.google.com/document/d/15nmTDA_39Lo-EULQQwdwYx_Q1IYX4dD5WPnHbFG71Lk/edit

[5] Ast tests for parser changes:
https://github.com/stroxler/cpython/blob/20eb59fdca0d6d8dbe4efa3b04038c7c22024654/Lib/test/test_ast.py#L359-L392
[6] Easy-read tests of examples from the PEP: 
https://github.com/stroxler/cpython/blob/callable-type-syntax--shorthand/Lib/test/test_callable_type_examples_for_pep.py
[7] Test sanity checking hundreds of examples pulled from typeshed:
https://github.com/stroxler/cpython/blob/callable-type-syntax--shorthand/Lib/test/test_callable_type_examples_for_pep.py
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OGACYN2X7RX2GHAUP2AKRPT6DP432VCN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Static types and subinterpreters running in parallel

2021-12-16 Thread Guido van Rossum
Eric has been looking into this. It's probably the only solution if we
can't get immutable objects. But I would prefer the latter, if we can get
the performance penalty low enough.

On Thu, Dec 16, 2021 at 2:31 AM Victor Stinner  wrote:

> Hi,
>
> One option to solve the https://bugs.python.org/issue40601 "[C API]
> Hide static types from the limited C API" issue without breaking the
> backward compatibility is to leave the C API and the stable ABI as
> they are for the main interpreter (static types), but force
> subinterpreters running in parallel to use their own heap types. It
> means that subinterpreters would be able to use the main interpreter
> GIL or own their GIL. By default, the GIL would still be shared.
>
> C extensions using "&PyLongType" (static type) would continue to work
> in the main interpreter.
>
> C extensions which want to opt-in for running subinterpreters in
> parallel would not access to "&PyLong_Type" but be forced to call
> PyLong_GetType() (heap type).
>
> Internally, Python should be modified to replace "&PyLongType" with
> PyLong_GetType(). So the code would work with static types and heap
> types.
>
> It also means that a subinterpreter running in parallel would only be
> able to import C extensions built with explicit support for this
> feature. Otherwise, an ImportError would be raised.
>
> Victor
> --
> Night gathers, and now my watch begins. It shall not end until my death.
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/QTY25AHCLOXRCQ2LADUUZFVKNVLLYS25/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/R2R7AHGEWHIRXBQ2VT63E6E5PZGFFZTT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Guido van Rossum
On Thu, Dec 16, 2021 at 3:08 AM Petr Viktorin  wrote:

> On 16. 12. 21 11:52, Victor Stinner wrote:
> > On Thu, Dec 16, 2021 at 2:29 AM Nathaniel Smith  wrote:
> >> On Wed, Dec 15, 2021 at 3:07 AM Victor Stinner 
> wrote:
> >>> I wrote https://bugs.python.org/issue39511 and
> >>> https://github.com/python/cpython/pull/18301 to have per-interpreter
> >>> None, True and False singletons. My change is backward compatible on
> >>> the C API: you can still use "Py_None" in your C code. The code gets
> >>> the singleton object from the current interpreter with a function
> >>> call:
> >>>
> >>>  #define Py_None Py_GetNone()
> >>>
> >>> Py_GetNone() is implemented as: "return
> _PyInterpreterState_GET()->none;"
> >>
> >> It's backward compatible for the C API, but not for the stable C ABI
> >> -- that exports Py_None directly as a symbol.
> >
> > You're right. But we can add a macro like Py_SUBINTERPRETER_API which
> > would change the implementation:
> >
> > * By default, "Py_None" would continue returning "&_Py_NoneStruct".
> > * If Py_SUBINTERPRETER_API macro is defined, Py_None would call
> Py_GetNone().
> >
> > => no impact on the stable ABI (if used, the stable ABI is not supported)
>
> The stable ABI could be orthogonal here -- you could compile for the
> stable ABI even with Py_SUBINTERPRETER_API.
>
> This would require (_PyInterpreterState_GET()->none == Py_None) in the
> "main" interpreter, and extrensions without Py_SUBINTERPRETER_API only
> loadable in the "main" interpreter.
>

That would slow things down a bit -- even if the pointer to the interpreter
state was already in a register, getting None would require loading the
pointer to Py_None from memory by indexing relative to that register.
Compared to a plain global, the latter would be a "load constant"
instruction, and Eric's other proposal (move the Py_None struct itself into
the interpreter state) would be just adding a constant to the register
(possibly the fastest solution, since that constant would be much smaller
than the full address of the global). Alas, that last version is not
compatible with the stable ABI. So I'm still in favor of trying harder to
make immortable objects a reality.

-- 
--Guido van Rossum (python.org/~guido)
*Pronouns: he/him **(why is my pronoun here?)*

___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KLTRUX5FK2KM5URUKKW2GPFRW4VZN35W/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Eric Snow
On Thu, Dec 16, 2021 at 4:34 AM Antoine Pitrou  wrote:
> As a data point, in PyArrow, we have a bunch of C++ code that interacts
> with Python but doesn't belong in a particular Python module.  That C++
> code can of course have global state, including perhaps Python objects.

Thanks for that example!

> What might be nice would be a C API to allow creating interpreter-local
> opaque structs, for example:
>
> void* Py_GetInterpreterLocal(const char* unique_name);
> void* Py_SetInterpreterLocal(const char* unique_name,
>  void* ptr, void(*)() destructor);

That's interesting.  I can imagine that as just a step beyond the
module state API, with the module being implicit.  Do you think this
would be an improvement over using module state?  (I'm genuinely
curious.)

-eric
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/KB7ET6XXJFTJDBHL7ABEPSGTD3M2RNAW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Antoine Pitrou
On Thu, 16 Dec 2021 11:38:28 -0700
Eric Snow  wrote:

> On Thu, Dec 16, 2021 at 4:34 AM Antoine Pitrou  wrote:
> > As a data point, in PyArrow, we have a bunch of C++ code that interacts
> > with Python but doesn't belong in a particular Python module.  That C++
> > code can of course have global state, including perhaps Python objects.  
> 
> Thanks for that example!
> 
> > What might be nice would be a C API to allow creating interpreter-local
> > opaque structs, for example:
> >
> > void* Py_GetInterpreterLocal(const char* unique_name);
> > void* Py_SetInterpreterLocal(const char* unique_name,
> >  void* ptr, void(*)() destructor);  
> 
> That's interesting.  I can imagine that as just a step beyond the
> module state API, with the module being implicit.  Do you think this
> would be an improvement over using module state?  (I'm genuinely
> curious.)

It would certainly be much easier to use (you just have to choose a
unique name, like e.g. for capsules).

Regards

Antoine.


___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4DIIJJKJBPGWL3UX5WNU35QRJX7U3BBA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Static types and subinterpreters running in parallel

2021-12-16 Thread Eric Snow
On Thu, Dec 16, 2021 at 10:54 AM Guido van Rossum  wrote:
>
> Eric has been looking into this. It's probably the only solution if we can't 
> get immutable objects.

Yep.  I've investigated the following approach (for the objects
exposed in the public and limited C-API):

* add a pointer field to PyInterpreterState (or a sub-struct) for each
of the objects
* for the main interpreter, set those pointers to the existing
statically declared objects
* for subinterpreters make a copy (memcpy()?) and fix it up
* add a lookup API and encourage extensions to use it
* for 3.11+ change the symbols to macros:
   + in the internal C-API (Py_BUILD_CORE), the macro would resolve to
the corresponding PyInterpreterState field
   + in the public C-API (and limited API extensions built with
3.11+), the macro would resolve to a call to a (non-inline) lookup
function
   + for limited API extensions built against earlier Python versions
we'd still export the existing symbols
* limited API extensions built against pre-3.11 Python would only be
allowed to run in the main interpreter on 3.11+
   + they probably weren't built with subinterpreters in mind anyway

There are still a number of details to sort out, but nothing that
seems like a huge obstacle.  Here are the ones that come to mind,
along with other details, caveats, and open questions:

* the static types exposed in the C-API are PyObject values rather than pointers
   + I solved this by dereferencing the result of the lookup function
(Guido's idea), e.g. #define PyTuple_Type (*(_Py_GetObject_Tuple()))
* there is definitely a penalty to using a per-interpreter lookup function
   + this would only apply to extension modules since internally we
would access the PyInterpreterState fields directly
   + this is mostly a potential problem only when the object is
directly referenced frequently (e.g. a tight loop),
   + the impact would probably center on use of the high-frequency
singletons (None, True, False) and possibly with Py*_CheckExact()
calls
   + would it be enough of a problem to be worth mitigating?  how
would we do so?
* static types in extensions can't have tp_base set to a builtin type
(since the macro won't resolve)
   + extensions that support subinterpreters (i.e. PEP 489) won't be
using static types (a weak assumption)
   + extensions that do not support subinterpreters and still have
static types would probably break
   + how to fix that?
* limited API extensions built against 3.11+ but running under older
Python versions would break?
   + how to fix that?

> But I would prefer the latter, if we can get the performance penalty low 
> enough.

Absolutely.  Using immortal objects to solve this is a much simpler solution.

-eric
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/7RPTHCLEUHR34PIJKRN453UEWCAI56NW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Jim J. Jewett
Guido van Rossum wrote:
> On Wed, Dec 15, 2021 at 6:57 PM Jim J. Jewett jimjjew...@gmail.com wrote:
> > Immortal objects shouldn't be reclaimed by garbage collection, but they
> > still count as potential external roots for non-cyclic liveness.
> So everything referenced by an immortal object should also be made immortal

Why?  As long as you can get a list of all immortal objects (and a traversal 
function from each), this is just an extra step (annoying, but tolerable) that 
removes a bunch of objects from the pool of potential garbage before you even 
begin looking for cycles.

> -- even its type. Hence immortal objects must be immutable. 

This is probably a good idea, since avoiding changes also avoids races and Copy 
on Write and cache propagation, etc ... but I don't see why it is *needed*, 
rather than helpful.

-jJ
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/4KY5XSHRMP3F3CWAW2OUW4NRXN4AB7EM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Guido van Rossum
It’s *needed* when multiple interpreters share them.

On Thu, Dec 16, 2021 at 14:03 Jim J. Jewett  wrote:

> Guido van Rossum wrote:
> > On Wed, Dec 15, 2021 at 6:57 PM Jim J. Jewett jimjjew...@gmail.com
> wrote:
> > > Immortal objects shouldn't be reclaimed by garbage collection, but they
> > > still count as potential external roots for non-cyclic liveness.
> > So everything referenced by an immortal object should also be made
> immortal
>
> Why?  As long as you can get a list of all immortal objects (and a
> traversal function from each), this is just an extra step (annoying, but
> tolerable) that removes a bunch of objects from the pool of potential
> garbage before you even begin looking for cycles.
>
> > -- even its type. Hence immortal objects must be immutable.
>
> This is probably a good idea, since avoiding changes also avoids races and
> Copy on Write and cache propagation, etc ... but I don't see why it is
> *needed*, rather than helpful.
>
> -jJ
> ___
> Python-Dev mailing list -- python-dev@python.org
> To unsubscribe send an email to python-dev-le...@python.org
> https://mail.python.org/mailman3/lists/python-dev.python.org/
> Message archived at
> https://mail.python.org/archives/list/python-dev@python.org/message/4KY5XSHRMP3F3CWAW2OUW4NRXN4AB7EM/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-- 
--Guido (mobile)
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/PBCVE2XUKBHZ3F463I3BIXEM33NLQNH3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Greg Ewing

On 17/12/21 6:52 am, Eddie Elizondo via Python-Dev wrote:

I've just updated the original Immortal Instances PR


Is it just me, or does Immortal Instances sound like a
video game franchise?

--
Greg
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/OCO5D53ACVM7CAOIXCPC4FPKIDGDSUXR/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: subinterpreters and their possible impact on large extension projects

2021-12-16 Thread Jim J. Jewett
Petr Viktorin wrote:
>>> In Python 3.11, Python still implements around 100 types as "static
>>> types" which are not compatible with subinterpreters,
...
>>> seems like changing it may break the C API *and* the stable ABI

> > If sub-interpreters each need their own copy of even immutable built-in 
> > types, then what advantage do they have over separate processes?

> They need copies of all *Python* objects. A non-Python library may allow 
> several Python wrappers/proxies for a single internal object, 
> effectively sharing that object between subinterpreters.
> (Which is a problem for removing the GIL -- currently all operations 
> done by such wrappers are protected by the GIL.)

OK, so what is the advantage of having multiple interpreters?

The only advantage I can see is that if you're embedding what are essentially 
several distinct python processes, you can still keep them all inside the 
single process used by the embedding program.  But seems pretty far along the 
"they're already compiling anyhow; so the ABI isn't crucial" path.

-jJ
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/C2Z2RPRAIGYDODATM5BQQL6DA6LEOVVN/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: "immortal" objects and how they would help per-interpreter GIL

2021-12-16 Thread Steven D'Aprano
On Fri, Dec 17, 2021 at 11:35:24AM +1300, Greg Ewing wrote:
> On 17/12/21 6:52 am, Eddie Elizondo via Python-Dev wrote:
> >I've just updated the original Immortal Instances PR
> 
> Is it just me, or does Immortal Instances sound like a
> video game franchise?

Or a Doctor Who episode. Doctor Who and the Immortal Instances of Doom.


-- 
Steve
___
Python-Dev mailing list -- python-dev@python.org
To unsubscribe send an email to python-dev-le...@python.org
https://mail.python.org/mailman3/lists/python-dev.python.org/
Message archived at 
https://mail.python.org/archives/list/python-dev@python.org/message/6LCAF3XZQQB3OSOGH5ECMCJPSRJHTOIA/
Code of Conduct: http://python.org/psf/codeofconduct/