diff --git a/.github/actions/test-mkl/action.yml b/.github/actions/test-mkl/action.yml new file mode 100644 index 0000000..a586838 --- /dev/null +++ b/.github/actions/test-mkl/action.yml @@ -0,0 +1,56 @@ +name: Test mkl +description: Test installation of mkl libraries +inputs: + compiler: + description: "Toolchain or compiler to install" + required: true + version: + description: "Version of toolchain or compiler" + required: true + install_mkl: + description: "If MKL should be installed along with the compiler" + required: false + default: "false" +runs: + using: "composite" + steps: + - name: Test compile and link mkl (bash) + working-directory: test + shell: bash + run: | + # check settings if mkl tests should be run + # mkl cannot be installed for 2021.5 on macos; + # and for macos-14 also not 2021.6-2021.9 + mkl_tests=true + echo "$RUNNER_OS" + if [[ "${{ inputs.compiler }}" =~ "gcc" ]]; then mkl_tests=false; fi + if [[ "${{ inputs.compiler }}" =~ "lfortran" ]]; then mkl_tests=false; fi + if [[ "${{ inputs.compiler }}" =~ "nvidia" ]]; then mkl_tests=false; fi + if [[ "${{ inputs.install_mkl }}" == "false" ]]; then mkl_tests=false; fi + if [[ "${{ inputs.version }}" == "2021.5" ]] && [[ "$RUNNER_OS" == "macOS" ]]; then mkl_tests=false; fi + if [[ "$RUNNER_OS" == "macOS" ]]; then + macos_version=$(sw_vers | grep "ProductVersion") + echo "$macos_version" + if [[ "$macos_version" =~ "14." ]] && [[ "${{ inputs.version }}" == '2021.6' || "${{ inputs.version }}" == '2021.7' || "${{ inputs.version }}" == '2021.7.1' || "${{ inputs.version }}" == '2021.8' ]]; then + mkl_tests=false + fi + fi + + # # now we know if we should, run the tests + if $mkl_tests; then + if [ "$RUNNER_OS" == "macOS" ]; then + MKLLIB="$MKLROOT/lib" + export DYLD_LIBRARY_PATH="$MKLLIB:$DYLD_LIBRARY_PATH" + elif [ "$RUNNER_OS" == "Linux" ]; then + MKLLIB="$MKLROOT/latest/lib/intel64" + export LD_LIBRARY_PATH="$MKLLIB:$LD_LIBRARY_PATH" + fi + linking="-L$MKLLIB -lmkl_intel_lp64 -lmkl_sequential -lmkl_core" + # hello world with blas call program + ${{ env.FC }} $args $linking -o hw_mkl hw_mkl.f90 + output=$(./hw_mkl '2>&1') + [[ "$output" == *"hello world 9.00000000000000"* ]] && echo "$output" || (echo "Unexpected Fortran program 'hw_mkl' output: $output"; exit 1) + rm hw_mkl + else + echo "Skipping MKL tests" + fi \ No newline at end of file diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 7f65195..21a5bd5 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -12,6 +12,7 @@ on: branches: - main - develop* + - math paths-ignore: - '**.md' schedule: @@ -74,6 +75,7 @@ jobs: with: compiler: ${{ matrix.toolchain.compiler }} version: ${{ matrix.toolchain.version }} + install_mkl: true # - name: Debug with tmate # uses: mxschmitt/action-tmate@v3 @@ -85,6 +87,17 @@ jobs: compiler: ${{ matrix.toolchain.compiler }} version: ${{ matrix.toolchain.version }} + - name: Test MKL libraries + # we could also exclude 2021.5 for all macos versions here + # this needs refactoring at some point - should the install + # fail if no mkl version exists? + if: steps.setup-fortran.outcome == 'success' && runner.os != 'windows' + uses: ./.github/actions/test-mkl + with: + compiler: ${{ matrix.toolchain.compiler }} + version: ${{ matrix.toolchain.version }} + install_mkl: true + - name: Test C compiler continue-on-error: true if: needs.options.outputs.mode == 'report' && steps.setup-fortran.outcome == 'success' diff --git a/README.md b/README.md index e5cf5dc..bc680d9 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ jobs: with: compiler: ${{ matrix.toolchain.compiler }} version: ${{ matrix.toolchain.version }} + install_mkl: "true" - run: | ${{ env.FC }} ... # environment vars FC, CC, and CXX are set @@ -69,6 +70,7 @@ jobs: - *lfortran* for `lfortran` - *nvidia-hpc* for `nvfortran` - *version*: Version of the compiler toolchain. See [runner compatibility](#runner-compatibility) charts below. +- *install_mkl*: If MKL libraries should be installed alongsider the intel compiler. Defaults to `false`. ## Outputs @@ -119,6 +121,8 @@ Toolchain support varies across GitHub-hosted runner images. **Note:** LFortran is currently only discoverable by name with `bash` on Windows, see [here for context](https://github.com/fortran-lang/setup-fortran/pull/57#issuecomment-2021605094). +**Note:** MKL libraries can only be installed for the Intel Fortran compiler, and only on linux and MacOS operating systems; with the exception of intel-classic 2021.5, for which no compatible library is available. + ## License Licensed under the Apache License, Version 2.0 (the “License”); diff --git a/action.yml b/action.yml index 5f2f627..04627ba 100644 --- a/action.yml +++ b/action.yml @@ -1,4 +1,4 @@ -name: "Setup Fortran" +name: "Setup Fortran and math libraries" description: "Setup Fortran compiler and toolchain" inputs: compiler: @@ -8,6 +8,10 @@ inputs: version: description: "Version of toolchain or compiler" required: false + install_mkl: + description: "If MKL should be installed along with the compiler" + required: false + default: "false" outputs: fc: description: "Path to Fortran compiler" @@ -68,6 +72,7 @@ runs: env: COMPILER: ${{ inputs.compiler }} VERSION: ${{ inputs.version }} + INSTALL_MKL: ${{ inputs.install_mkl }} run: | action_path=$(echo '/${{ github.action_path }}' | sed -e 's/\\/\//g' -e 's/://') source "$action_path/setup-fortran.sh" @@ -87,11 +92,11 @@ runs: ;; intel-classic) version=${VERSION:-2023.2.0} - install_intel $platform true + install_intel $platform true ${{ inputs.install_mkl }} ;; intel) version=${VERSION:-2024.1} - install_intel $platform false + install_intel $platform false ${{ inputs.install_mkl }} ;; nvidia-hpc) version=${VERSION:-23.11} @@ -151,6 +156,7 @@ runs: echo FC=$FC>>$GITHUB_ENV echo CC=$CC>>$GITHUB_ENV echo CXX=$CXX>>$GITHUB_ENV + echo "MKLLIB=$MKLLIB" >> $GITHUB_ENV # set fpm env vars echo FPM_FC=$FC>>$GITHUB_ENV diff --git a/install-intel-macos.sh b/install-intel-macos.sh new file mode 100644 index 0000000..4a16bd2 --- /dev/null +++ b/install-intel-macos.sh @@ -0,0 +1,21 @@ +install_mkl=$1 +MACOS_URL=$2 +if [ "$MACOS_URL" == "" ]; then + echo "ERROR: MACOS URL is empty - please check the version mapping for mkl/intel compiler" + echo "SKIPPING MKL/intel installation..." +elif [ "$MACOS_URL" == "2021.5" ] and $install_mkl; then + echo "ERROR: MKL not available for this intel compiler version" + echo "SKIPPING MKL installation..." +else + require_fetch + $fetch $MACOS_URL > m_BASE_HPC_Kit.dmg + hdiutil verify m_BASE_HPC_Kit.dmg + hdiutil attach m_BASE_HPC_Kit.dmg + sudo /Volumes/"$(basename "$MACOS_URL" .dmg)"/bootstrapper.app/Contents/MacOS/bootstrapper -s \ + --action install \ + --eula=accept \ + --continue-with-optional-error=yes \ + --log-dir=. + hdiutil detach /Volumes/"$(basename "$MACOS_URL" .dmg)" -quiet + rm m_BASE_HPC_Kit.dmg +fi \ No newline at end of file diff --git a/setup-fortran.sh b/setup-fortran.sh index 1dc5c5f..095b16b 100755 --- a/setup-fortran.sh +++ b/setup-fortran.sh @@ -156,6 +156,7 @@ LD_LIBRARY_PATH=$LD_LIBRARY_PATH LIBRARY_PATH=$LIBRARY_PATH INFOPATH=$INFOPATH MANPATH=$MANPATH +MKLROOT=$MKLROOT ONEAPI_ROOT=$ONEAPI_ROOT CLASSPATH=$CLASSPATH CMAKE_PREFIX_PATH=$CMAKE_PREFIX_PATH @@ -237,6 +238,19 @@ intel_version_map_l() fi } +mkl_version_map_l() +{ + local intel_version=$1 + case $intel_version in + 2021.1 | 2021.1.2) + mkl_version=2021.1.1 + ;; + *) + mkl_version=$intel_version + ;; + esac +} + intel_version_map_m() { local actual_version=$1 @@ -271,6 +285,45 @@ intel_version_map_m() esac } +mkl_version_map_m() +{ + local intel_version=$1 + macos_version=$(sw_vers | grep "ProductVersion") + echo "Found macos version $macos_version" + if [[ "$macos_version" == *"14"* ]]; then + echo "MacOS 14 requires different basekit versions to work" + case $intel_version in + # compiler versions 2021.1, 2021.2, 2021.3, 2021.4, 2021.10 work with latest basekit + 2021.1.0 | 2021.2.0 | 2021.3.0 | 2021.4.0 | 2023.2.0) + mkl_version=2023.2.0 + ;; + # compiler versions 2021.9 works with other basekits + 2023.1.0) + mkl_version=2023.1.0 + ;; + # all others don't work with any basekit + *) + mkl_version="" + ;; + esac + else + case $intel_version in + 2021.1.0 | 2021.2.0 | 2021.3.0 | 2021.4.0 | 2022.2.0 | 2022.3.0 | 2022.3.1 | 2023.0.0 ) + mkl_version=2022.2.0 + ;; + 2022.1.0) + mkl_version="" + ;; + 2023.1.0) + mkl_version=2023.1.0 + ;; + *) + mkl_version=2023.2.0 + ;; + esac + fi +} + intel_version_map_w() { local actual_version=$1 @@ -330,7 +383,10 @@ install_intel_apt() { local version=$1 local classic=$2 + local mkl_version=$1 + local install_mkl=$3 intel_version_map_l $version $classic + mkl_version_map_l $version require_fetch local _KEY="GPG-PUB-KEY-INTEL-SW-PRODUCTS.PUB" @@ -341,6 +397,11 @@ install_intel_apt() | sudo tee /etc/apt/sources.list.d/oneAPI.list sudo apt-get update + # first install mkl, then the compilers, to keep setvars clean + if $install_mkl; then + sudo apt-get install intel-oneapi-mkl-$mkl_version + fi + # c/cpp compiler package names changed with 2024+ case $version in 2024*) @@ -352,7 +413,6 @@ install_intel_apt() intel-oneapi-compiler-{fortran,dpcpp-cpp-and-cpp-classic}-$version ;; esac - source /opt/intel/oneapi/setvars.sh export_intel_vars } @@ -360,51 +420,43 @@ install_intel_apt() install_intel_dmg() { local version=$1 + local mkl_version=$1 + local install_mkl=$2 intel_version_map_m $version + mkl_version_map_m $version case $version in 2021.1.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17426/m_BaseKit_p_2021.1.0.2427.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17398/m_HPCKit_p_2021.1.0.2681.dmg ;; 2021.2.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17714/m_BaseKit_p_2021.2.0.2855.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17643/m_HPCKit_p_2021.2.0.2903.dmg ;; 2021.3.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17969/m_BaseKit_p_2021.3.0.3043.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/17890/m_HPCKit_p_2021.3.0.3226.dmg ;; 2021.4.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18256/m_BaseKit_p_2021.4.0.3384.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18242/m_HPCKit_p_2021.4.0.3389.dmg ;; 2022.1.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18342/m_BaseKit_p_2022.1.0.92.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18341/m_HPCKit_p_2022.1.0.86.dmg ;; 2022.2.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/18675/m_BaseKit_p_2022.2.0.226_offline.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/18681/m_HPCKit_p_2022.2.0.158_offline.dmg ;; 2022.3.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18865/m_BaseKit_p_2022.3.0.8743.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18866/m_HPCKit_p_2022.3.0.8685.dmg ;; 2022.3.1) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18971/m_BaseKit_p_2022.3.1.17244.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/18977/m_HPCKit_p_2022.3.1.15344.dmg ;; 2023.0.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/19080/m_BaseKit_p_2023.0.0.25441.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/irc_nas/19086/m_HPCKit_p_2023.0.0.25440.dmg ;; 2023.1.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/2516a0a0-de4d-4f3d-9e83-545b32127dbb/m_BaseKit_p_2023.1.0.45568.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/a99cb1c5-5af6-4824-9811-ae172d24e594/m_HPCKit_p_2023.1.0.44543.dmg ;; 2023.2.0) - MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/cd013e6c-49c4-488b-8b86-25df6693a9b7/m_BaseKit_p_2023.2.0.49398.dmg MACOS_HPCKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/edb4dc2f-266f-47f2-8d56-21bc7764e119/m_HPCKit_p_2023.2.0.49443.dmg ;; *) @@ -412,16 +464,28 @@ install_intel_dmg() ;; esac - require_fetch - $fetch $MACOS_HPCKIT_URL > m_HPCKit.dmg - hdiutil attach m_HPCKit.dmg - sudo /Volumes/"$(basename "$MACOS_HPCKIT_URL" .dmg)"/bootstrapper.app/Contents/MacOS/bootstrapper -s \ - --action install \ - --eula=accept \ - --continue-with-optional-error=yes \ - --log-dir=. - hdiutil detach /Volumes/"$(basename "$MACOS_HPCKIT_URL" .dmg)" -quiet - rm m_HPCKit.dmg + case $mkl_version in + 2022.2.0) + MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/18675/m_BaseKit_p_2022.2.0.226_offline.dmg + ;; + 2023.1.0) + MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/2516a0a0-de4d-4f3d-9e83-545b32127dbb/m_BaseKit_p_2023.1.0.45568.dmg + ;; + 2023.2.0) + MACOS_BASEKIT_URL=https://registrationcenter-download.intel.com/akdlm/IRC_NAS/cd013e6c-49c4-488b-8b86-25df6693a9b7/m_BaseKit_p_2023.2.0.49398.dmg + ;; + "") + ;; + *) + exit 1 + ;; + esac + + if $install_mkl; then + source "$GITHUB_ACTION_PATH/install-intel-macos.sh" true $MACOS_BASEKIT_URL + fi + + source "$GITHUB_ACTION_PATH/install-intel-macos.sh" false $MACOS_HPCKIT_URL source /opt/intel/oneapi/setvars.sh export_intel_vars @@ -482,12 +546,15 @@ install_intel() { local platform=$1 local classic=$2 + local install_mkl=$3 + mkl_subdir="" case $platform in linux*) - install_intel_apt $version $classic + install_intel_apt $version $classic $install_mkl + mkl_subdir="intel64" ;; darwin*) - install_intel_dmg $version + install_intel_dmg $version $install_mkl ;; mingw*) install_intel_win $version $classic @@ -513,6 +580,11 @@ install_intel() export CC="icx" export CXX="icpx" fi + + if $install_mkl; then + export MKLLIB="$ONEAPI_ROOT/mkl/latest/lib/$mkl_subdir" + export MKLROOT="$ONEAPI_ROOT/mkl/latest" + fi } export_nvidiahpc_vars() diff --git a/test/hw_mkl.f90 b/test/hw_mkl.f90 new file mode 100644 index 0000000..cc7445c --- /dev/null +++ b/test/hw_mkl.f90 @@ -0,0 +1,13 @@ +program hello + implicit none + double precision, dimension(3):: a, b + double precision:: c + double precision:: DDOT + + a = (/ 3.D0, 3.D0, 3.D0 /) + b = (/ 1.D0, 1.D0, 1.D0 /) + + c = DDOT(3, a, 1, b, 1) + + print *, "hello world", c +end program hello \ No newline at end of file