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)
pull/6228/head
Michael Hirsch, Ph.D 5 years ago
parent 818c92003c
commit 92b77cb321
No known key found for this signature in database
GPG Key ID: 6D23CDADAB0294F9
  1. 67
      .github/workflows/ci_frameworks.yml
  2. 14
      docs/markdown/snippets/scalapack.md
  3. 10
      mesonbuild/dependencies/__init__.py
  4. 121
      mesonbuild/dependencies/scalapack.py
  5. 4
      run_project_tests.py
  6. 34
      test cases/frameworks/30 scalapack/main.c
  7. 25
      test cases/frameworks/30 scalapack/main.f90
  8. 42
      test cases/frameworks/30 scalapack/meson.build

@ -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

@ -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)

@ -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,

@ -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

@ -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():

@ -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;
}

@ -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

@ -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
Loading…
Cancel
Save