From 43833c2e2493de3737a26420282e1785df6d72b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yaman=20G=C3=BC=C3=A7l=C3=BC?= Date: Fri, 6 Sep 2024 15:41:45 +0200 Subject: [PATCH] Improve and test Pyccel compiler flags (#428) - Add compiler flags for GFortran >= 14 on Apple silicon chips - Add unit test in `test_epyccel_flags.py` to check compiler flags passed to `epyccel` - Update GitHub actions used in documentation workflow --- .github/workflows/continuous-integration.yml | 4 +-- .github/workflows/documentation.yml | 10 +++--- psydac/api/settings.py | 19 ++++++++--- psydac/api/tests/test_epyccel_flags.py | 35 ++++++++++++++++++++ pytest.ini | 1 + 5 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 psydac/api/tests/test_epyccel_flags.py diff --git a/.github/workflows/continuous-integration.yml b/.github/workflows/continuous-integration.yml index 7724f4be4..6181f9861 100644 --- a/.github/workflows/continuous-integration.yml +++ b/.github/workflows/continuous-integration.yml @@ -159,9 +159,9 @@ jobs: python -m pip install . python -m pip freeze - - name: Test pyccel optimization flags + - name: Test Pyccel optimization flags run: | - pyccel --verbose ./psydac/linalg/kernels/axpy_kernels.py + pytest --pyargs psydac -m pyccel --capture=no - name: Initialize test directory run: | diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 88e8065d5..be24f89c9 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -18,9 +18,9 @@ jobs: GITHUB_PAT: ${{ secrets.GITHUB_TOKEN}} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up Python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: 3.9 - name: Install non-Python dependencies on Ubuntu @@ -37,9 +37,9 @@ jobs: make -C docs html python docs/update_links.py - name: Setup Pages - uses: actions/configure-pages@v3 + uses: actions/configure-pages@v5 - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v3 with: path: 'docs/build/html' @@ -53,4 +53,4 @@ jobs: steps: - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v2 + uses: actions/deploy-pages@v4 diff --git a/psydac/api/settings.py b/psydac/api/settings.py index 74a48c645..3a3830107 100644 --- a/psydac/api/settings.py +++ b/psydac/api/settings.py @@ -1,5 +1,8 @@ # coding: utf-8 +import subprocess # nosec B404 import platform +import re +from packaging.version import Version __all__ = ('PSYDAC_DEFAULT_FOLDER', 'PSYDAC_BACKENDS') @@ -40,18 +43,26 @@ 'openmp' : False} # ... +# Get gfortran version +gfortran_version_output = subprocess.check_output(['gfortran', '--version']).decode('utf-8') # nosec B603, B607 +gfortran_version_string = re.search("(\d+\.\d+\.\d+)", gfortran_version_output).group() +gfortran_version = Version(gfortran_version_string) + # Platform-dependent flags -if platform.system() == "Darwin" and platform.machine() == 'arm64': +if platform.system() == "Darwin" and platform.machine() == 'arm64' and gfortran_version >= Version("14"): + # Apple silicon requires architecture-specific flags (see https://github.com/pyccel/psydac/pull/411) - import subprocess # nosec B404 + # which are only available on GCC version >= 14 cpu_brand = subprocess.check_output(['sysctl','-n','machdep.cpu.brand_string']).decode('utf-8') # nosec B603, B607 - if "Apple M1" in cpu_brand: - PSYDAC_BACKEND_GPYCCEL['flags'] += ' -mcpu=apple-m1' + if "Apple M1" in cpu_brand: PSYDAC_BACKEND_GPYCCEL['flags'] += ' -mcpu=apple-m1' + elif "Apple M2" in cpu_brand: PSYDAC_BACKEND_GPYCCEL['flags'] += ' -mcpu=apple-m2' + elif "Apple M3" in cpu_brand: PSYDAC_BACKEND_GPYCCEL['flags'] += ' -mcpu=apple-m3' else: # TODO: Support later Apple CPU models. Perhaps the CPU naming scheme could be easily guessed # based on the output of 'sysctl -n machdep.cpu.brand_string', but I wouldn't rely on this # guess unless it has been manually verified. Loud errors are better than silent failures! raise SystemError(f"Unsupported Apple CPU '{cpu_brand}'.") + else: # Default architecture flags PSYDAC_BACKEND_GPYCCEL['flags'] += ' -march=native -mtune=native' diff --git a/psydac/api/tests/test_epyccel_flags.py b/psydac/api/tests/test_epyccel_flags.py new file mode 100644 index 000000000..cdbcb0906 --- /dev/null +++ b/psydac/api/tests/test_epyccel_flags.py @@ -0,0 +1,35 @@ +import pytest + + +@pytest.mark.pyccel +def test_epyccel_flags(): + + from pyccel.epyccel import epyccel + from psydac.api.settings import PSYDAC_BACKEND_GPYCCEL as backend + + kwargs = {'language' : 'fortran', + 'compiler' : backend['compiler'], + 'fflags' : backend['flags'], + 'accelerators' : ['openmp'] if backend['openmp'] else [], + 'verbose' : True, + } + + # Function to be Pyccel-ized + def f(x : float): + return 3 * x + + # Pyccel magic + # ------------ + # Fortran code is generated and then compiled with the selected compiler. + # The compiled function is callable from Python through the C Python API. + # The necessary C wrapper functions are also generated by Pyccel. + fast_f = epyccel(f, **kwargs) + + # Check output of pyccelized function + assert fast_f(3.5) == f(3.5) + + +# Interactive usage +if __name__ == '__main__': + test_epyccel_flags() + print('PASSED') diff --git a/pytest.ini b/pytest.ini index c18eb444d..91ef13cfa 100644 --- a/pytest.ini +++ b/pytest.ini @@ -9,6 +9,7 @@ markers = serial: single-process test, parallel: test to be run using 'mpiexec', petsc: test requiring a working PETSc installation with petsc4py Python bindings + pyccel: test for checking Pyccel setup on machine python_files = test_*.py python_classes =