diff options
author | Michael Hirsch, Ph.D <scivision@users.noreply.github.com> | 2019-11-24 00:13:54 -0500 |
---|---|---|
committer | Michael Hirsch, Ph.D <scivision@users.noreply.github.com> | 2019-11-30 21:29:49 -0500 |
commit | 92b77cb3210280315c47d18f3c87cdd2c59021bc (patch) | |
tree | 6d2e5196aab7a1d6827ad1416761bbfbc135e226 | |
parent | 818c92003c41b72194cdc668a3346a4b7247bd23 (diff) | |
download | meson-92b77cb3210280315c47d18f3c87cdd2c59021bc.zip meson-92b77cb3210280315c47d18f3c87cdd2c59021bc.tar.gz meson-92b77cb3210280315c47d18f3c87cdd2c59021bc.tar.bz2 |
deps: add scalapack
Scalapack uses a library stack that can be challenging to manage.
Not least of all since many Scalapacks ship with broken / incomplete
pkg-config files and CMake FindScalapack.cmake
This resolves those issues for typical Scalapack setups including:
* Linux: Intel MKL or OpenMPI + Netlib
* MacOS: Intel MKL or OpenMPI + Netlib
* Windows: Intel MKL (OpenMPI not available on Windows)
-rw-r--r-- | .github/workflows/ci_frameworks.yml | 67 | ||||
-rw-r--r-- | docs/markdown/snippets/scalapack.md | 14 | ||||
-rw-r--r-- | mesonbuild/dependencies/__init__.py | 10 | ||||
-rw-r--r-- | mesonbuild/dependencies/scalapack.py | 121 | ||||
-rwxr-xr-x | run_project_tests.py | 4 | ||||
-rw-r--r-- | test cases/frameworks/30 scalapack/main.c | 34 | ||||
-rw-r--r-- | test cases/frameworks/30 scalapack/main.f90 | 25 | ||||
-rw-r--r-- | test cases/frameworks/30 scalapack/meson.build | 42 |
8 files changed, 314 insertions, 3 deletions
diff --git a/.github/workflows/ci_frameworks.yml b/.github/workflows/ci_frameworks.yml new file mode 100644 index 0000000..0a0ce8b --- /dev/null +++ b/.github/workflows/ci_frameworks.yml @@ -0,0 +1,67 @@ +name: ci_frameworks + +on: + push: + paths: + - "mesonbuild/dependencies/**" + - "test cases/frameworks/**" + - ".github/workflows/frameworks.yml" + pull_request: + paths: + - "mesonbuild/dependencies/**" + - "test cases/frameworks/**" + - ".github/workflows/frameworks.yml" + +jobs: + + scalapack_linux: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: python -m pip install . + - name: install prereq + run: | + sudo apt update -yq + sudo apt install -yq --no-install-recommends pkg-config ninja-build gfortran liblapack-dev libscalapack-mpi-dev libopenmpi-dev openmpi-bin + - run: meson setup "test cases/frameworks/30 scalapack" build + env: + FC: gfortran + CC: gcc + - run: ninja -C build + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Scalpack_Linux_Build + path: build/meson-logs/meson-log.txt + - run: meson test -C build -v + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Scalapack_Linux_Test + path: build/meson-logs/testlog.txt + + scalapack_mac: + runs-on: macos-latest + steps: + - uses: actions/checkout@v1 + - uses: actions/setup-python@v1 + with: + python-version: '3.x' + - run: python -m pip install -e . + - run: brew install pkg-config ninja gcc openmpi lapack scalapack + - run: meson setup "test cases/frameworks/30 scalapack" build + - run: ninja -C build + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Scalapack_Mac_build + path: build/meson-logs/meson-log.txt + - run: meson test -C build -v + - uses: actions/upload-artifact@v1 + if: failure() + with: + name: Scalapack_Mac_test + path: build/meson-logs/testlog.txt diff --git a/docs/markdown/snippets/scalapack.md b/docs/markdown/snippets/scalapack.md new file mode 100644 index 0000000..03ddbd4 --- /dev/null +++ b/docs/markdown/snippets/scalapack.md @@ -0,0 +1,14 @@ +## Scalapack + +added in **0.53.0**: + +```meson +scalapack = dependency('scalapack') +``` + +Historically and through today, typical Scalapack setups have broken and incomplete pkg-config or +FindScalapack.cmake. Meson handles finding Scalapack on setups including: + +* Linux: Intel MKL or OpenMPI + Netlib +* MacOS: Intel MKL or OpenMPI + Netlib +* Windows: Intel MKL (OpenMPI not available on Windows)
\ No newline at end of file diff --git a/mesonbuild/dependencies/__init__.py b/mesonbuild/dependencies/__init__.py index 1b7c03f..889a610 100644 --- a/mesonbuild/dependencies/__init__.py +++ b/mesonbuild/dependencies/__init__.py @@ -22,6 +22,7 @@ from .base import ( # noqa: F401 from .dev import GMockDependency, GTestDependency, LLVMDependency, ValgrindDependency from .coarrays import CoarrayDependency from .mpi import MPIDependency +from .scalapack import ScalapackDependency from .misc import (BlocksDependency, NetCDFDependency, OpenMPDependency, Python3Dependency, ThreadDependency, PcapDependency, CupsDependency, LibWmfDependency, LibGCryptDependency, GpgmeDependency, ShadercDependency) from .platform import AppleFrameworks from .ui import GLDependency, GnuStepDependency, Qt4Dependency, Qt5Dependency, SDL2Dependency, WxDependency, VulkanDependency @@ -37,11 +38,14 @@ packages.update({ 'boost': BoostDependency, 'cuda': CudaDependency, - # From misc: - 'blocks': BlocksDependency, + # per-file 'coarray': CoarrayDependency, - 'mpi': MPIDependency, 'hdf5': HDF5Dependency, + 'mpi': MPIDependency, + 'scalapack': ScalapackDependency, + + # From misc: + 'blocks': BlocksDependency, 'netcdf': NetCDFDependency, 'openmp': OpenMPDependency, 'python3': Python3Dependency, diff --git a/mesonbuild/dependencies/scalapack.py b/mesonbuild/dependencies/scalapack.py new file mode 100644 index 0000000..4057091 --- /dev/null +++ b/mesonbuild/dependencies/scalapack.py @@ -0,0 +1,121 @@ +# Copyright 2013-2019 The Meson development team + +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at + +# http://www.apache.org/licenses/LICENSE-2.0 + +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from pathlib import Path +import os + +from .. import mesonlib +from .base import (CMakeDependency, ExternalDependency, PkgConfigDependency) + + +class ScalapackDependency(ExternalDependency): + def __init__(self, environment, kwargs: dict): + language = kwargs.get('language') + super().__init__('scalapack', environment, language, kwargs) + kwargs['required'] = False + kwargs['silent'] = True + self.is_found = False + self.static = kwargs.get('static', False) + + # 1. try pkg-config + pkgconfig_files = [] + mklroot = None + is_gcc = None + if language == 'fortran': + is_gcc = environment.detect_fortran_compiler(self.for_machine).get_id() == 'gcc' + elif language == 'c': + is_gcc = environment.detect_c_compiler(self.for_machine).get_id() == 'gcc' + elif language == 'cpp': + is_gcc = environment.detect_cpp_compiler(self.for_machine).get_id() == 'gcc' + # Intel MKL works with non-Intel compilers too -- but not gcc on windows + if 'MKLROOT' in os.environ and not (mesonlib.is_windows() and is_gcc): + try: + mklroot = Path(os.environ['MKLROOT']).resolve() + except Exception: + pass + if mklroot is not None: + # MKL pkg-config is a start, but you have to add / change stuff + # https://software.intel.com/en-us/articles/intel-math-kernel-library-intel-mkl-and-pkg-config-tool + pkgconfig_files = ( + ['mkl-static-lp64-iomp'] if self.static else ['mkl-dynamic-lp64-iomp'] + ) + if mesonlib.is_windows(): + suffix = '.lib' + elif self.static: + suffix = '.a' + else: + suffix = '' + libdir = mklroot / 'lib/intel64' + # Intel compiler might not have Parallel Suite + pkgconfig_files += ['scalapack-openmpi', 'scalapack'] + + for pkg in pkgconfig_files: + pkgdep = PkgConfigDependency( + pkg, environment, kwargs, language=self.language + ) + if pkgdep.found(): + self.compile_args = pkgdep.get_compile_args() + if mklroot: + link_args = pkgdep.get_link_args() + if is_gcc: + for i, a in enumerate(link_args): + if 'mkl_intel_lp64' in a: + link_args[i] = a.replace('intel', 'gf') + break + # MKL pkg-config omits scalapack + # be sure "-L" and "-Wl" are first if present + i = 0 + for j, a in enumerate(link_args): + if a.startswith(('-L', '-Wl')): + i = j + 1 + elif j > 3: + break + if mesonlib.is_windows() or self.static: + link_args.insert( + i, str(libdir / ('mkl_scalapack_lp64' + suffix)) + ) + link_args.insert( + i + 1, str(libdir / ('mkl_blacs_intelmpi_lp64' + suffix)) + ) + else: + link_args.insert(i, '-lmkl_scalapack_lp64') + link_args.insert(i + 1, '-lmkl_blacs_intelmpi_lp64') + else: + link_args = pkgdep.get_link_args() + self.link_args = link_args + + self.version = pkgdep.get_version() + if self.version == 'unknown' and mklroot: + try: + v = ( + mklroot.as_posix() + .split('compilers_and_libraries_')[1] + .split('/', 1)[0] + ) + if v: + self.version = v + except IndexError: + pass + + self.is_found = True + self.pcdep = pkgdep + return + # 2. try CMake + cmakedep = CMakeDependency('Scalapack', environment, kwargs) + if cmakedep.found(): + self.compile_args = cmakedep.get_compile_args() + self.link_args = cmakedep.get_link_args() + self.version = cmakedep.get_version() + self.is_found = True + return diff --git a/run_project_tests.py b/run_project_tests.py index dbda839..7c69267 100755 --- a/run_project_tests.py +++ b/run_project_tests.py @@ -557,6 +557,10 @@ def skippable(suite, test): if test.endswith('29 blocks'): return True + # tested on GitHub Actions instead of Docker + if test.endswith('30 scalapack'): + return True + # No frameworks test should be skipped on linux CI, as we expect all # prerequisites to be installed if mesonlib.is_linux(): diff --git a/test cases/frameworks/30 scalapack/main.c b/test cases/frameworks/30 scalapack/main.c new file mode 100644 index 0000000..ca01977 --- /dev/null +++ b/test cases/frameworks/30 scalapack/main.c @@ -0,0 +1,34 @@ +#include <stdio.h> + +// #include <mkl.h> +// #include <mkl_scalapack.h> +// #include <mkl_blacs.h> + +extern float pslamch_(const int *, const char *); +extern void blacs_pinfo_(int *, int *); +extern void blacs_get_(const int *, const int *, int *); +extern void blacs_gridinit_(int *, const char *, const int *, const int *); +extern void blacs_gridinfo_(const int *, int *, int *, int *, int *); +extern void blacs_gridexit_(const int *); +extern void blacs_exit_(const int *); + +int main(void){ + +int myid, nprocs, ictxt, mycol, myrow, npcol=2, nprow=2; +const int i0=0, i1=1, in1=-1; + +blacs_pinfo_(&myid, &nprocs); +blacs_get_(&in1, &i0, &ictxt); +blacs_gridinit_(&ictxt, "C", &nprocs, &i1); + +blacs_gridinfo_(&ictxt, &nprow, &npcol, &myrow, &mycol); + +float eps = pslamch_(&ictxt, "E"); + +if (myrow == mycol) printf("OK: Scalapack C: eps= %f\n", eps); + +blacs_gridexit_(&ictxt); +blacs_exit_(&i0); + +return 0; +}
\ No newline at end of file diff --git a/test cases/frameworks/30 scalapack/main.f90 b/test cases/frameworks/30 scalapack/main.f90 new file mode 100644 index 0000000..5e3a192 --- /dev/null +++ b/test cases/frameworks/30 scalapack/main.f90 @@ -0,0 +1,25 @@ +! minimal Scalapack demo +implicit none + +integer :: ictxt, myid, nprocs, mycol, myrow, npcol, nprow +real :: eps +real, external :: pslamch + +! arbitrary test parameters +npcol = 2 +nprow = 2 + +call blacs_pinfo(myid, nprocs) +call blacs_get(-1, 0, ictxt) +call blacs_gridinit(ictxt, "C", nprocs, 1) + +call blacs_gridinfo(ictxt, nprow, npcol, myrow, mycol) + +eps = pslamch(ictxt, 'E') + +if(myrow == mycol) print '(A, F10.6)', "OK: Scalapack Fortran eps=", eps + +call blacs_gridexit(ictxt) +call blacs_exit(0) + +end program
\ No newline at end of file diff --git a/test cases/frameworks/30 scalapack/meson.build b/test cases/frameworks/30 scalapack/meson.build new file mode 100644 index 0000000..f9c453f --- /dev/null +++ b/test cases/frameworks/30 scalapack/meson.build @@ -0,0 +1,42 @@ +project('test scalapack', 'c') + +cc = meson.get_compiler('c') + +mpiexec = find_program('mpiexec', required: false) +if not mpiexec.found() + error('MESON_SKIP_TEST: mpiexec not found') +endif + +mpi_c = dependency('mpi', language: 'c', required: false) +if not mpi_c.found() + error('MESON_SKIP_TEST: MPI library not available') +endif + +# examples can run with any number of MPI images. +mpi_args = ['-np', '1'] + +scalapack = dependency('scalapack', required: false) +if not scalapack.found() + error('MESON_SKIP_TEST: scalapack library not available') +endif + +# https://software.intel.com/en-us/mkl-developer-reference-c-scalapack-routines +c_exe = executable('scalapack_c', 'main.c', + dependencies: [scalapack, mpi_c]) +test('scalapack_c', mpiexec, + args: [mpi_args, c_exe], + timeout: 30) + +if add_languages('fortran') + mpi_f = dependency('mpi', language: 'fortran', required: false) + if not mpi_f.found() + error('MESON_SKIP_TEST: MPI Fortran library not available') + endif + + # https://software.intel.com/en-us/mkl-developer-reference-fortran-scalapack-routines + f_exe = executable('scalapack_fortran', 'main.f90', + dependencies: [scalapack, mpi_f]) + test('scalapack_fortran', mpiexec, + args: [mpi_args, f_exe], + timeout: 30) +endif
\ No newline at end of file |