Skip to content
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

Tracker: Support Python nogil builds #20669

Open
3 tasks
andfoy opened this issue May 8, 2024 · 4 comments
Open
3 tasks

Tracker: Support Python nogil builds #20669

andfoy opened this issue May 8, 2024 · 4 comments
Labels
Build issues Issues with building from source, including different choices of architecture, compilers and OS no-GIL Items related to supporting free-threaded builds of CPython

Comments

@andfoy
Copy link
Contributor

andfoy commented May 8, 2024

This issue aims to collect all the issues and PRs related for the upcoming Python 3.13 nogil builds.

The outline of this issue will detail the compatibility of each module in the SciPy namespace against nogil builds, specially with class APIs, which may suffer of concurrency issues due to state sharing when multiple threads share the same object instances.

Until now, as of #20611 all the test suite is passing using the latest NumPy after numpy/numpy#26348.

Resources:

scipy.spatial

scipy.interpolate

@andfoy andfoy changed the title Tracker: NoGIL compatibility in SciPy Tracker: NoGIL compatibility May 8, 2024
@andfoy andfoy changed the title Tracker: NoGIL compatibility Tracker: Support Python nogil builds May 8, 2024
@dschmitz89 dschmitz89 added no-GIL Items related to supporting free-threaded builds of CPython Build issues Issues with building from source, including different choices of architecture, compilers and OS labels May 9, 2024
@andfoy
Copy link
Contributor Author

andfoy commented May 16, 2024

Here is a list of classes in SciPy, which can be of interest, since they could have shared state that can mutate under multithreading: https://gist.github.com/andfoy/955bf6ceee8437b2092df19202490981. Feel free to comment if you have any hints or suspicions that a class might be non-thread safe

I extracted them by means of the following introspection script:

Script
import scipy
from inspect import isclass, ismodule, getmembers

cls_set = set({})
visited = set({})
queue = [scipy]

while queue != []:
    mod_or_class = queue.pop(0)
    if mod_or_class in visited:
        continue
    print(mod_or_class)
    if ismodule(mod_or_class) and mod_or_class.__name__.startswith('scipy'):
        for _, mem in getmembers(mod_or_class):
            if ismodule(mem) and mem.__name__.startswith('scipy'):
                queue.append(mem)
            elif isclass(mem):
                queue.append(mem)
    elif isclass(mod_or_class):
        cls_module = mod_or_class.__module__
        cls_name = mod_or_class.__name__
        fully_qual = f'{cls_module}.{cls_name}'
        if cls_module.startswith('scipy') and fully_qual not in cls_set:
            print(fully_qual)
            cls_set |= {fully_qual}
    visited |= {mod_or_class}

classes = sorted(cls_set)
for cls_name in classes:
      print(cls_name)

@rgommers
Copy link
Member

Feel free to comment if you have any hints or suspicions that a class might be non-thread safe

A couple of thoughts:

  • Distributions in scipy.stats store a random number generator as internal state
  • Fortran code may contain COMMON blocks, and perhaps other ways of storing global/shared state. My expectation is that a lot of our Fortran code isn't safe It's be great if a Fortran expert could comment on that (@ev-br or @ilayn?)
  • We don't have many caches, but those we have require checking. E.g. the optimize.shgo implementation has one.
  • Uarray should be using thread-local state correctly already IIRC, and isn't used a lot. So no need to prioritize that one at least.

@ev-br
Copy link
Member

ev-br commented May 22, 2024

COMMON blocks are relatively rare: the only non-legacy submodule which does not have a more modern replacement is ODRPACK (integrate/dop and odepack have an alternative in solve_ivp; mvndst` is likely ready or almost ready to be removed according to #18566 )

$ grep "COMMON /" . -rn
./scipy/integrate/mach/d1mach.f:17:      COMMON /D9MACH/ CRAY1
./scipy/integrate/dop/dopri5.f:372:      COMMON /CONDO5/XOLD,HOUT
./scipy/integrate/dop/dopri5.f:629:      COMMON /CONDO5/XOLD,H
./scipy/integrate/dop/dop853.f:546:      COMMON /CONDO8/XOLD,HOUT
./scipy/integrate/dop/dop853.f:862:      COMMON /CONDO8/XOLD,H
./scipy/integrate/odepack/zvode.f:978:C     COMMON /ZVOD01/ RVOD(50), IVOD(33)
./scipy/integrate/odepack/zvode.f:979:C     COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:1182:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:1190:      COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:1902:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:1910:      COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:2063:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:2071:      COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:2470:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:2642:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:2854:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:2862:      COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:3080:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:3088:      COMMON /ZVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/zvode.f:3342:      COMMON /ZVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13), ETA,
./scipy/integrate/odepack/zvode.f:3415:      COMMON /ZVOD01/ RVOD1(50), IVOD1(33)
./scipy/integrate/odepack/zvode.f:3416:      COMMON /ZVOD02/ RVOD2(1), IVOD2(8)
./scipy/integrate/odepack/vode.f:973:C     COMMON /DVOD01/ RVOD(48), IVOD(33)
./scipy/integrate/odepack/vode.f:974:C     COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:1168:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:1176:      COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:1882:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:1890:      COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:2042:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:2050:      COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:2449:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:2621:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:2832:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:2840:      COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:3061:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:3069:      COMMON /DVOD02/ HU, NCFN, NETF, NFE, NJE, NLU, NNI, NQU, NST
./scipy/integrate/odepack/vode.f:3329:      COMMON /DVOD01/ ACNRM, CCMXJ, CONP, CRATE, DRC, EL(13),
./scipy/integrate/odepack/vode.f:3403:      COMMON /DVOD01/ RVOD1(48), IVOD1(33)
./scipy/integrate/odepack/vode.f:3404:      COMMON /DVOD02/ RVOD2(1), IVOD2(8)
./scipy/odr/odrpack/d_test.f:28:      COMMON /TSTSET/ NTEST
./scipy/odr/odrpack/d_test.f:151:      COMMON /SETID/SETNO
./scipy/odr/odrpack/d_test.f:152:      COMMON /TSTSET/ NTEST
./scipy/odr/odrpack/d_test.f:974:      COMMON /SETID/SETNO
./scipy/odr/odrpack/d_test.f:1843:      COMMON /SETID/SETNO
./scipy/stats/mvndst.f:203:      COMMON /DKBLCK/IVLS

"implicit save" might be a build problem though, not sure TBH: #6882 (comment)

@ilayn
Copy link
Member

ilayn commented May 22, 2024

About mvndst.f ; I was about to translate it but I can't remember where I am told that it is already implemented in somewhere else and marked that issue (might be Warren or Matt) here #18679 (comment) We also have #8367 about this. But I really don't know what the status is about it. I can squeeze that in and complete the stats translation suite for quick dopamine.

COMMON, IMPLICIT SAVE and SAVE are really annoying "features" of old code. But COMMON is the lesser evil. The others are just pure pain. So I would actually like some guidance about prioritizing this Fortran saga as we are approaching to array based parts of the translation. My unfortunately reallife/work-affected schedule is

  1. id_dist (hoping to finish this asap for 1.14)
  2. slsqp (this is already translated but I'm blocked on the python side as I have not found a way to disentangle the _minimize.py yet; it is really a lot of historical crust about constraints and jacobian and classes etc. Problem is mostly my IQ)
  3. propack (real part done, complex is waiting)
  4. arpack (I don't expect too much difficulty in this one since it is a "simpler" version of propack)
  5. and then no idea what to start, I hope we can get rid of ODRPACK by reading F90 version. integrate is your playground so not sure what the situation is in that module.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Build issues Issues with building from source, including different choices of architecture, compilers and OS no-GIL Items related to supporting free-threaded builds of CPython
Projects
None yet
Development

No branches or pull requests

5 participants