From c40f1023ef4b62f2bc0b9d5b02f6ade4fc40c0c6 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Mon, 9 Sep 2024 17:49:58 +0100 Subject: [PATCH 1/7] Add test for freethreading --- meson.build | 6 ++++++ src/flint/test/test_all.py | 38 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/meson.build b/meson.build index 6a816fc2..30215a9b 100644 --- a/meson.build +++ b/meson.build @@ -83,6 +83,12 @@ add_project_arguments( language : 'cython' ) +# Enable free-threading if Cython is new enough: +#cy = meson.get_compiler('cython') +#if cy.version().version_compare('>=3.1.0') +# add_project_arguments('-Xfreethreading_compatible=true', language : 'cython') +#endif + if get_option('coverage') add_project_arguments('-X', 'linetrace=True', language : 'cython') add_project_arguments('-DCYTHON_TRACE=1', language : 'c') diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index f5876fa9..c4df0c5c 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -1612,10 +1612,12 @@ def set_bad2(): M6 = M6_copy assert M6.nullspace() == (M([[1,15,1],[0,0,0],[0,0,0]],17).transpose(), 1) + def test_nmod_series(): # XXX: currently no code in nmod_series.pyx pass + def test_arb(): A = flint.arb assert A(3) > A(2.5) @@ -1626,6 +1628,7 @@ def test_arb(): assert A(3) != A(2) assert not (A("1.1") == A("1.1")) + def test_pickling(): objects = [ flint.fmpz(1), @@ -4735,6 +4738,39 @@ def test_fq_default_poly(): assert raises(lambda: f.pow_trunc(-1, 5), ValueError) +def test_python_threads(): + + from threading import Thread + + iterations = 10**5 + threads = 3 + 1 + size = 3 + M = flint.fmpz_mat([[0]*size for _ in range(size)]) + + def set_values(): + for i in range(iterations // 5): + i = random.randrange(M.nrows()) + j = random.randrange(M.ncols()) + if random.uniform(0, 1) > 0.5: + # Bigger than 2**62: + M[i,j] = 10**128 + else: + # Smaller than 2**62: + M[i,j] = 0 + + def get_dets(): + for i in range(iterations): + M.det() + + threads = [Thread(target=set_values) for _ in range(threads-1)] + threads.append(Thread(target=get_dets)) + + for t in threads: + t.start() + for t in threads: + t.join() + + def test_all_tests(): test_funcs = {f for name, f in globals().items() if name.startswith("test_")} untested = test_funcs - set(all_tests) @@ -4813,5 +4849,7 @@ def test_all_tests(): test_pickling, + test_python_threads, + test_all_tests, ] From 173b88f6dc8dc7cc5b1de0c136bd841a46c0edc2 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 18:00:44 +0000 Subject: [PATCH 2/7] Add CPython 3.13t to the build matrix --- .github/workflows/buildwheel.yml | 11 ++++++++++- meson.build | 8 ++++---- pyproject.toml | 25 ++++++++++++------------- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 72ba8ee5..22da497d 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -86,7 +86,7 @@ jobs: os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] # This list to be kept in sync with cibuildwheel config # and python-requires in pyproject.toml. - python-version: ['3.11', '3.12', '3.13'] # , 'pypy3.10'] + python-version: ['3.11', '3.12', '3.13', '3.13t'] # , 'pypy3.10'] steps: - uses: actions/setup-python@v5 @@ -97,6 +97,15 @@ jobs: name: wheels-${{ matrix.os }} path: wheelhouse - run: pip install --no-index --find-links wheelhouse python_flint + + # Check if the GIL is disabled in the free-threading build after import. + - run: | + python --version --version + which python + python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" + python -c "import sys; print(sys._is_gil_enabled())" + python -c "import sys; import flint; print(sys._is_gil_enabled())" + - run: python -m flint.test --verbose # On new enough Ubuntu we can build against the system deb. diff --git a/meson.build b/meson.build index 30215a9b..28542ab1 100644 --- a/meson.build +++ b/meson.build @@ -84,10 +84,10 @@ add_project_arguments( ) # Enable free-threading if Cython is new enough: -#cy = meson.get_compiler('cython') -#if cy.version().version_compare('>=3.1.0') -# add_project_arguments('-Xfreethreading_compatible=true', language : 'cython') -#endif +cy = meson.get_compiler('cython') +if cy.version().version_compare('>=3.1.0a1') + add_project_arguments('-Xfreethreading_compatible=true', language : 'cython') +endif if get_option('coverage') add_project_arguments('-X', 'linetrace=True', language : 'cython') diff --git a/pyproject.toml b/pyproject.toml index 713cd156..bc78ff9e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,6 +6,7 @@ version = "0.7.0" requires-python = ">= 3.11" authors = [ {name = "Fredrik Johansson", email = "fredrik.johansson@gmail.com"}, + {name = "Oscar Benjamin", email = "oscar.j.benjamin@gmail.com"}, ] license = {text = "MIT"} classifiers = [ @@ -27,16 +28,16 @@ content-type = "text/markdown" # Minimum build requirements tested in CI need to be kept in sync with the # versions in requires below so that they are tested. # -# The upper cap on Cython is speculative but we may as well cap it given that -# it is only a build requirement and that it is not uncommon for newer Cython -# versions to break the build. For example Cython 3.0 broke the build and then -# Cython 3.1 broke the build again so python-flint 0.6.0 did not have any upper -# cap but it should have had cython>=3.0,<3.1 i.e. precisely one minor release -# of Cython works. In future we could contemplate not having an upper cap but -# until we have actually witnessed a Cython 3.x release that does not break the -# build we should keep the upper cap. +# To support the freethreaded build (CPython 3.13t) the alpha release 3.1.0a1 +# of Cython is needed as a minimum requirement. It is possible that future +# versions of Cython might still work but typically a Cython release breaks +# something in the build of python-flint so we pin the exact version here. # -requires = ["meson-python>=0.13", "cython>=3.0.11,<=3.1.0a1"] +# Apart from the freethreading build any Cython version from 3.0.11 onwards is +# fine. It is not possible to have a separate version constraint here for the +# freethreading build only though. +# +requires = ["meson-python>=0.13", "cython==3.1.0a1"] build-backend = "mesonpy" [tool.cython-lint] @@ -81,12 +82,10 @@ package = "flint" [tool.cibuildwheel] # requires-python needs to keep in sync with this and also the list of Python # versions the wheels are tested against in CI. -build = "cp311-* cp312-* cp313-*" # pp311-*" +build = "cp311-* cp312-* cp313-* cp313t-*" # pp311-*" skip = "*-win32 *-manylinux_i686 *-musllinux_*" -# This is needed for free-threaded wheels: -# build = "cp313t-*" -# free-threaded-support = true +free-threaded-support = true manylinux-x86_64-image = "manylinux2014" manylinux-aarch64-image = "manylinux_2_28" From 2112ec36b7a345ebf5be5018d0fc94fb01176a17 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 18:39:48 +0000 Subject: [PATCH 3/7] Fix the Cython version check in meson.build --- .github/workflows/buildwheel.yml | 4 ++-- meson.build | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 22da497d..b7b58e82 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -103,8 +103,8 @@ jobs: python --version --version which python python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - python -c "import sys; print(sys._is_gil_enabled())" - python -c "import sys; import flint; print(sys._is_gil_enabled())" + python -c "import sys; print(getattr(sys, '_is_gil_enabled', lambda: True)())" + python -c "import sys; import flint; print(getattr(sys, '_is_gil_enabled', lambda: True)())" - run: python -m flint.test --verbose diff --git a/meson.build b/meson.build index 28542ab1..40720356 100644 --- a/meson.build +++ b/meson.build @@ -83,10 +83,15 @@ add_project_arguments( language : 'cython' ) -# Enable free-threading if Cython is new enough: +# Enable free-threading if Cython is new enough. The check should be +# >= 3.1.0a1 but meson gets confused by the a1 alpha release suffix. +# so we go with >= 3.1 (which will be correct once 3.1 is released). cy = meson.get_compiler('cython') -if cy.version().version_compare('>=3.1.0a1') - add_project_arguments('-Xfreethreading_compatible=true', language : 'cython') +if cy.version().version_compare('>=3.1') + message('Enabling freethreading') + add_project_arguments('-Xfreethreading_compatible=true', language : 'cython') +else + message('Disabling freethreading') endif if get_option('coverage') From 3c220ee48a2adc789bf8cd59f052181ce78761b9 Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 18:59:51 +0000 Subject: [PATCH 4/7] Use deadsnakes to test 3.13t wheel --- .github/workflows/buildwheel.yml | 45 +++++++++++++++++++++++++++++++- 1 file changed, 44 insertions(+), 1 deletion(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index b7b58e82..e1b97963 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -86,7 +86,13 @@ jobs: os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] # This list to be kept in sync with cibuildwheel config # and python-requires in pyproject.toml. - python-version: ['3.11', '3.12', '3.13', '3.13t'] # , 'pypy3.10'] + # + # It should be possible to add '3.13t' here when a newer version of + # actions/setup-python is available. As of v5.4.0 it cannote be used + # although a fix has been merged so presumably v5.5.0 or v.5.4.1 will + # provide this... + # https://github.com/actions/setup-python/pull/973 + python-version: ['3.11', '3.12', '3.13'] # , 'pypy3.10'] steps: - uses: actions/setup-python@v5 @@ -108,6 +114,43 @@ jobs: - run: python -m flint.test --verbose + test_wheels_freethreaded_ubuntu: + # XXX: Remove this job and add to the matrix above when a newer version of + # actions/setup-python is released. + needs: build_wheels + name: Test 3.13t wheel on Ubuntu + runs-on: ubuntu-24.04 + + steps: + # https://github.com/actions/setup-python/issues/771 + # deadsnakes only works for Ubuntu... + - uses: deadsnakes/action@v3.2.0 + with: + python-version: 3.13 + nogil: true + - run: | + python --version --version + which python + python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" + python -c "import sys; print(sys._is_gil_enabled())" + + - uses: actions/download-artifact@v4 + with: + name: wheels-${{ matrix.os }} + path: wheelhouse + + - run: pip install --no-index --find-links wheelhouse python_flint + + # Check if the GIL is disabled in the free-threading build after import. + - run: | + python --version --version + which python + python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" + python -c "import sys; print(getattr(sys, '_is_gil_enabled', lambda: True)())" + python -c "import sys; import flint; print(getattr(sys, '_is_gil_enabled', lambda: True)())" + + - run: python -m flint.test --verbose + # On new enough Ubuntu we can build against the system deb. test_pip_flint_deb: name: Build on ${{ matrix.os }} From b8b00e7dfddda99f2b4190fe1fd7f7ca1d8295ad Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 19:21:05 +0000 Subject: [PATCH 5/7] Use Quansight-Labs/setup-python --- .github/workflows/buildwheel.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index e1b97963..0c2eb363 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -10,7 +10,8 @@ jobs: strategy: fail-fast: false matrix: - os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] + # os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] + os: [macos-14] steps: - uses: actions/checkout@v4 @@ -92,10 +93,10 @@ jobs: # although a fix has been merged so presumably v5.5.0 or v.5.4.1 will # provide this... # https://github.com/actions/setup-python/pull/973 - python-version: ['3.11', '3.12', '3.13'] # , 'pypy3.10'] + python-version: ['3.11', '3.12', '3.13', '3.13t'] # , 'pypy3.10'] steps: - - uses: actions/setup-python@v5 + - uses: Quansight-Labs/setup-python@v5 with: python-version: ${{ matrix.python-version }} - uses: actions/download-artifact@v4 From 7c12d94aa6a665dda0301b465c167cfcc2569c4d Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 19:34:44 +0000 Subject: [PATCH 6/7] Use Quansight-Labs/setup-python --- .github/workflows/buildwheel.yml | 81 ++------------------------------ 1 file changed, 5 insertions(+), 76 deletions(-) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 0c2eb363..40554fd1 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -10,8 +10,7 @@ jobs: strategy: fail-fast: false matrix: - # os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] - os: [macos-14] + os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] steps: - uses: actions/checkout@v4 @@ -87,15 +86,13 @@ jobs: os: [ubuntu-24.04, ubuntu-24.04-arm, windows-2019, macos-13, macos-14] # This list to be kept in sync with cibuildwheel config # and python-requires in pyproject.toml. - # - # It should be possible to add '3.13t' here when a newer version of - # actions/setup-python is available. As of v5.4.0 it cannote be used - # although a fix has been merged so presumably v5.5.0 or v.5.4.1 will - # provide this... - # https://github.com/actions/setup-python/pull/973 python-version: ['3.11', '3.12', '3.13', '3.13t'] # , 'pypy3.10'] steps: + # Quansight-labs/setup-python is needed for 3.13t until a new version of + # actions/setup-python (>5.4.0) is released. + # + # https://github.com/actions/setup-python/pull/973 - uses: Quansight-Labs/setup-python@v5 with: python-version: ${{ matrix.python-version }} @@ -115,43 +112,6 @@ jobs: - run: python -m flint.test --verbose - test_wheels_freethreaded_ubuntu: - # XXX: Remove this job and add to the matrix above when a newer version of - # actions/setup-python is released. - needs: build_wheels - name: Test 3.13t wheel on Ubuntu - runs-on: ubuntu-24.04 - - steps: - # https://github.com/actions/setup-python/issues/771 - # deadsnakes only works for Ubuntu... - - uses: deadsnakes/action@v3.2.0 - with: - python-version: 3.13 - nogil: true - - run: | - python --version --version - which python - python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - python -c "import sys; print(sys._is_gil_enabled())" - - - uses: actions/download-artifact@v4 - with: - name: wheels-${{ matrix.os }} - path: wheelhouse - - - run: pip install --no-index --find-links wheelhouse python_flint - - # Check if the GIL is disabled in the free-threading build after import. - - run: | - python --version --version - which python - python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - python -c "import sys; print(getattr(sys, '_is_gil_enabled', lambda: True)())" - python -c "import sys; import flint; print(getattr(sys, '_is_gil_enabled', lambda: True)())" - - - run: python -m flint.test --verbose - # On new enough Ubuntu we can build against the system deb. test_pip_flint_deb: name: Build on ${{ matrix.os }} @@ -280,37 +240,6 @@ jobs: - run: pip install -r requirements-dev.txt - run: bin/coverage.sh - # On new enough Ubuntu we can build against the system deb. - test_freethreaded: - name: Free-threaded ${{ matrix.python-version }} on ${{ matrix.os }} - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-24.04] - python-version: ['3.13', '3.14-dev'] - steps: - - uses: actions/checkout@v4 - # Can't use actions/setup-python - # https://github.com/actions/setup-python/issues/771 - # deadsnakes only works for Ubuntu... - - uses: deadsnakes/action@v3.2.0 - with: - python-version: ${{ matrix.python-version }} - nogil: true - - run: | - python --version --version - which python - python -c "import sysconfig; print(sysconfig.get_config_var('Py_GIL_DISABLED'))" - python -c "import sys; print(sys._is_gil_enabled())" - - run: sudo apt-get update - - run: sudo apt-get install libflint-dev - # Need Cython master until 3.1 is released - - run: pip install git+https://github.com/cython/cython.git@master - - run: pip install -r requirements-dev.txt - - run: pip install --no-build-isolation . - - run: python -m flint.test --verbose - # Run SymPy test suite against python-flint master test_sympy: name: Test SymPy ${{ matrix.sympy-version }} From b84f13c2ed9933f175162df7dde2e3e0c00a26bb Mon Sep 17 00:00:00 2001 From: Oscar Benjamin Date: Sun, 16 Mar 2025 20:14:01 +0000 Subject: [PATCH 7/7] Skip threads test on the freethreading build --- .github/workflows/buildwheel.yml | 6 ++++++ src/flint/test/test_all.py | 15 +++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/.github/workflows/buildwheel.yml b/.github/workflows/buildwheel.yml index 40554fd1..185f177b 100644 --- a/.github/workflows/buildwheel.yml +++ b/.github/workflows/buildwheel.yml @@ -88,6 +88,12 @@ jobs: # and python-requires in pyproject.toml. python-version: ['3.11', '3.12', '3.13', '3.13t'] # , 'pypy3.10'] + # XXX: Maybe this exclude can be removed when changing from + # Quansight-Labs/setup-python... + exclude: + - os: ubuntu-24.04-arm + python-version: '3.13t' + steps: # Quansight-labs/setup-python is needed for 3.13t until a new version of # actions/setup-python (>5.4.0) is released. diff --git a/src/flint/test/test_all.py b/src/flint/test/test_all.py index c4df0c5c..a32f2159 100644 --- a/src/flint/test/test_all.py +++ b/src/flint/test/test_all.py @@ -4739,6 +4739,21 @@ def test_fq_default_poly(): def test_python_threads(): + # + # https://github.com/flintlib/python-flint/issues/224 + # + # XXX: This test crashes under the free-threading mode because of memory + # corruption. + # + # It is not clear if this should be fixed or if mutating + # matrices/polynomials that are shared between multiple threads should just + # be disallowed. + # + + # Skip the test on the free-threaded build... + import sys + if sys.version_info[:2] >= (3, 13) and not sys._is_gil_enabled(): + return from threading import Thread