Skip to content

Test gfortran

Test gfortran #477

Workflow file for this run

name: Test gfortran
on:
# Trigger the workflow on push or pull request
#push:
pull_request: # DANGEROUS! MUST be disabled for self-hosted runners!
# Trigger the workflow by cron. The default time zone of GitHub Actions is UTC.
schedule:
- cron: '0 16 * * *'
# Trigger the workflow manually
workflow_dispatch:
inputs:
git-ref:
description: Git Ref (Optional)
required: false
# Show the git ref in the workflow name if it is invoked manually.
run-name: ${{ github.event_name == 'workflow_dispatch' && format('Manual run {0}', inputs.git-ref) || '' }}
jobs:
test:
name: Run gfortran tests
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, ubuntu-24.04-arm, windows-latest, macos-26-intel, macos-latest]
# windows-11-arm does not work as of 202604. See https://github.com/fortran-lang/setup-fortran/issues/211#issuecomment-4313463378
compiler: [gcc]
version: [13, latest] # Too expensive to test all versions
solver: [newuoa, cobyla, lincoa, bobyqa, uobyqa]
testdim: [small, big]
# With FFLAGS=-O3, the following combinations encounter failures of assertion on X == X_UNC/ALT
# when testing
# bobyqa: gtest_i4_r8_d1_tst, chebquad
# lincoa: gtest_i4_r8_d1_tst, chebquad
# cobyla: gtest_i4_r8_d1_tst, trigssqs
# See
# https://github.com/libprima/prima/issues/268
# https://github.com/s-prima/prima/actions/runs/22023414613
# This should be investigated and fixed when we have a macOS with M* chip at hand.
# It is reproducible on zMS.
exclude:
- os: macos-latest
testdim: small
version: latest
solver: bobyqa
- os: macos-latest
testdim: small
version: latest
solver: lincoa
- os: macos-latest
testdim: small
version: latest
solver: cobyla
steps:
- name: Set http.postBuffer and core.compression
# This is a workaround for random "early EOF" of checkout.
# See https://github.com/actions/checkout/issues/748, https://github.com/actions/checkout/issues/1379
if: startsWith(matrix.os, 'windows')
run: git config --global http.postBuffer 1048576000 && git config --global core.compression 0
- name: Run `sudo apt update`
if: startsWith(matrix.os, 'ubuntu')
run: sudo apt update || true # Otherwise, free-disk-space or other actions relying on `apt` may fail
- name: Free disk space
if: startsWith(matrix.os, 'ubuntu')
uses: jlumbroso/free-disk-space@main
with:
# all of these default to true, but feel free to set to "false" if necessary for your workflow
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: false # Important, or the runner may be shut down due to memory starvation.
- name: Clone Repository (Latest)
uses: actions/checkout@v6.0.2
if: github.event.inputs.git-ref == ''
with:
submodules: recursive
# ssh-key: ${{ secrets.SSH_PRIVATE_KEY_ACT }} # This forces checkout to use SSH, not HTTPS
# As of 231227, checkout with ssh fails frequently on Windows runners.
- name: Clone Repository (Custom Ref)
uses: actions/checkout@v6.0.2
if: github.event.inputs.git-ref != ''
with:
ref: ${{ github.event.inputs.git-ref }}
submodules: recursive
# ssh-key: ${{ secrets.SSH_PRIVATE_KEY_ACT }} # This forces checkout to use SSH, not HTTPS
# As of 231227, checkout with ssh fails frequently on Windows runners.
- name: Miscellaneous setup
shell: bash # Important; otherwise, the following statements do not work on Windows.
run: bash .github/scripts/misc_setup
- name: Set up Fortran
uses: fortran-lang/setup-fortran@main
with:
compiler: ${{ matrix.compiler }}
version: ${{ matrix.version }}
- name: Check gfortran version
shell: bash
run: |
which gcc && gcc --version && which gfortran && gfortran --version
gfortran -dumpmachine # See https://github.com/fortran-lang/setup-fortran/issues/211#issuecomment-4313463378
- name: Revise Makefile.common to exclude r16 tests when the dimension is big
if: ${{ matrix.testdim == 'big' }}
shell: bash
run: |
cd fortran/tests/makefiles || exit 42
$SEDI "s|\$(TST)_.*r16_d[0,1]_tst||g" Makefile.common && cat Makefile.common
- name: Revise test_bobyqa.f90, test_lincoa.f90, and test_cobyla.f90 so that we know what is happening if assertion fails
shell: bash
run: |
if [[ $(uname) = 'Darwin' ]]; then # macOS uses BSD sed, which does not understand \s or \n
brew install gnu-sed
SEDI="gsed -i"
fi
cd fortran/tests || exit 42
$SEDI "s|\(\s*\)\(call.*X == X_UNC.*\)|\1if (.not. (all(abs(x - x_unc) <= 0) .and. (abs(f - f_unc) <= 0 .or. (is_neginf(f) .and. is_neginf(f_unc))))) then\n\1write(*,*) 'probname = ', strip(prob%probname), 'n = ', n, 'x0 = ', x0\n\1write(*,*) 'npt = ', npt, 'rhobeg = ', rhobeg, 'rhoend = ', rhoend\n\1write(*,*) 'maxfun = ', maxfun, 'maxhist = ', maxhist, 'ftarget = ', ftarget, 'iprint = ', iprint\n\1write(*,*) 'f, x = ', f, x\n\1write(*,*) 'f_unc, x_unc = ', f_unc, x_unc\n\1write(*,*) 'fhist = ', fhist\n\1write(*,*) 'xhist = ', xhist\n\1write(*,*) 'fhist_unc = ', fhist_unc\n\1write(*,*) 'xhist_unc = ', xhist_unc\n\1error stop\n\1else\n\1write(*,*) '>>> X == X_UNC and F == F_UNC <<< probname = ', strip(prob%probname), ', irand = ', irand\n\1end if\n\1\2|" test_bobyqa.f90
cat test_bobyqa.f90
$SEDI "s|\(\s*\)\(call.*X == X_ALT.*\)|\1if (.not. (all(abs(x - x_alt) <= 0) .and. (abs(f - f_alt) <= 0 .or. (is_neginf(f) .and. is_neginf(f_alt))))) then\n\1write(*,*) 'probname = ', strip(prob%probname), 'n = ', n, 'x0 = ', x0\n\1write(*,*) 'npt = ', npt, 'rhobeg = ', rhobeg, 'rhoend = ', rhoend\n\1write(*,*) 'maxfun = ', maxfun, 'maxhist = ', maxhist, 'ftarget = ', ftarget, 'iprint = ', iprint\n\1write(*,*) 'f, x = ', f, x\n\1write(*,*) 'f_alt, x_alt = ', f_alt, x_alt\n\1write(*,*) 'fhist = ', fhist\n\1write(*,*) 'xhist = ', xhist\n\1write(*,*) 'fhist_alt = ', fhist_alt\n\1write(*,*) 'xhist_alt = ', xhist_alt\n\1error stop\n\1else\n\1write(*,*) '>>> X == X_ALT and F == F_ALT <<< probname = ', strip(prob%probname), ', irand = ', irand\n\1end if\n\1\2|" test_lincoa.f90
cat test_lincoa.f90
$SEDI "s|\(\s*\)\(call.*X == X_ALT.*\)|\1if (.not. (all(abs(x - x_alt) <= 0) .and. (abs(f - f_alt) <= 0 .or. (is_neginf(f) .and. is_neginf(f_alt))))) then\n\1write(*,*) 'probname = ', strip(prob%probname), 'n = ', n, 'x0 = ', x0\n\1write(*,*) 'rhobeg = ', rhobeg, 'rhoend = ', rhoend\n\1write(*,*) 'maxfun = ', maxfun, 'maxhist = ', maxhist, 'ftarget = ', ftarget, 'iprint = ', iprint\n\1write(*,*) 'f, x = ', f, x\n\1write(*,*) 'f_alt, x_alt = ', f_alt, x_alt\n\1write(*,*) 'fhist = ', fhist\n\1write(*,*) 'xhist = ', xhist\n\1write(*,*) 'fhist_alt = ', fhist_alt\n\1write(*,*) 'xhist_alt = ', xhist_alt\n\1error stop\n\1else\n\1write(*,*) '>>> X == X_ALT and F == F_ALT <<< probname = ', strip(prob%probname), ', irand = ', irand\n\1end if\n\1\2|" test_cobyla.f90
cat test_cobyla.f90
- name: Revise string.f90, so that we know what is happening if assertion fails
shell: bash
run: |
if [[ $(uname) = 'Darwin' ]]; then # macOS uses BSD sed, which does not understand \s or \n
brew install gnu-sed
SEDI="gsed -i"
fi
cd fortran/common || exit 42
$SEDI "s|\(call assert(abs(x - str2real(s)) <= abs(x) \* 10.0\*\*(-ndgt_loc), 'STR2REAL(S) == X', srname)\)|if (.not. abs(x - str2real(s)) <= abs(x) * 10.0**(-ndgt_loc)) then\nwrite(*,*) '====> x = ', x, 's = ', s, 'sx = ', str2real(s)\nerror stop\nelse\n\1\nend if|" string.f90
cat string.f90
- name: Revise linalg.f90 regarding a postcondition of p_norm, so that we know what is happening if it fails
shell: bash
run: |
if [[ $(uname) = 'Darwin' ]]; then # macOS uses BSD sed, which does not understand \s or \n
brew install gnu-sed
SEDI="gsed -i"
fi
cd fortran/common || exit 42
$SEDI "s|'Y >= 0 unless X contains NaN'|'Y >= 0 unless X contains NaN'\&\n\&\/\/num2str(y)\/\/num2str(sum(abs(x)))\/\/num2str(int(is_nan(sum(abs(x)))))\/\/num2str(x)|" linalg.f90
$SEDI "s|function p_norm(x, p) result(y)|function p_norm(x, p) result(y)\nuse, non_intrinsic :: string_mod, only : num2str|" linalg.f90
cat linalg.f90
- name: Conduct the test; treat timeout as SUCCESS (exit 0). Only for non-Windows.
if: runner.os != 'Windows'
uses: equipez/run-bash-command@v2
with:
timelimit: 320m
command: |
IK=i$(( 2**(1 + $(date +%-d) % 3) ))
echo "IK=${IK}"
echo "IK=${IK}" >> "$GITHUB_ENV"
# Use $(( )) rather than $(expr ). See https://unix.stackexchange.com/questions/63166/bash-e-exits-when-let-or-expr-evaluates-to-0
export TESTDIM=${{ matrix.testdim }}
echo "TESTDIM=$TESTDIM" >> "$GITHUB_ENV"
FFLAGS=-O$(($(date +%-d) % 5))
FFLAGS=${FFLAGS/O0/g}
FFLAGS=${FFLAGS/O4/fast}
export FFLAGS
echo "FFLAGS=$FFLAGS"
echo "FFLAGS=$FFLAGS" >> "$GITHUB_ENV"
cd "$ROOT_DIR"/fortran/tests && make gtest_${IK}_c.${{ matrix.solver }} && make gtest_${IK}.${{ matrix.solver }}
cd "$ROOT_DIR"/fortran/examples/${{ matrix.solver }}
export EXAMPLE_NUM=1 && make clean && make gtest
export EXAMPLE_NUM=2 && make clean && make gtest
- name: Conduct the test on Windows
if: runner.os == 'Windows'
shell: bash # Important; otherwise, `<` will not work on Windows.
run: |
# 20260213: We skip the extensive test on Windows due to the following reasons. The
# examples will still be tested on Windows.
# 0. It is quite difficult to debug on Windows. We choose to develop and debug the code on
# Linux and macOS, and only run a quick test on Windows to see whether it works at all.
# 1. Windows does not support the symlink of Linux. Makefile will fail when copying source files.
# 2. Makefile.common does not work on Windows for the moment due to quotation marks.
# Nevertheless, we should still define IK etc., as they will be used when defining the artifact names.
IK=i$(( 2**(1 + $(date +%-d) % 3) ))
echo "IK=${IK}"
echo "IK=${IK}" >> "$GITHUB_ENV"
# Use $(( )) rather than $(expr ). See https://unix.stackexchange.com/questions/63166/bash-e-exits-when-let-or-expr-evaluates-to-0
export TESTDIM=${{ matrix.testdim }}
echo "TESTDIM=$TESTDIM" >> "$GITHUB_ENV"
FFLAGS=-O$(($(date +%-d) % 5))
FFLAGS=${FFLAGS/O0/g}
FFLAGS=${FFLAGS/O4/fast}
export FFLAGS
echo "FFLAGS=$FFLAGS"
echo "FFLAGS=$FFLAGS" >> "$GITHUB_ENV"
cd "$ROOT_DIR"/fortran/examples/${{ matrix.solver }}
export EXAMPLE_NUM=1 && make clean && make gtest
export EXAMPLE_NUM=2 && make clean && make gtest
- name: Store artifacts
uses: actions/upload-artifact@v7
if: always() # Always run even if the workflow is canceled manually or due to overtime.
# Note that `$TEST_DIR` does not work on Windows, where its equivalent is `$env:TEST_DIR`.
# In the following, we enquire `$TEST_DIR` by using the `env` context, which is platform independent.
with:
name: ${{ matrix.os }}-${{ matrix.solver }}-${{ env.IK }}-${{ matrix.version }}-${{ env.TESTDIM }}-${{ env.FFLAGS }}
path: ${{ env.TEST_DIR }}/prima/fortran/tests/test.${{ matrix.solver }}/log/*.log
- name: Remove the test data
if: always() # Always run even if the workflow is canceled manually or due to overtime.
shell: bash # Important; otherwise, `rm -rf` will not work on Windows.
run: rm -rf ${{ env.TEST_DIR }}