CP2K/SIRIUS: add support for building with CUDA, fix CP2K build with MKL (#11418)

* cp2k/sirius: add CUDA support

* cp2k: fix building with MKL

* sirius: make sure to link against Spacks blas/lapack/scalapack
This commit is contained in:
Tiziano Müller 2019-08-13 19:59:08 +02:00 committed by Massimiliano Culpo
parent 68c176998a
commit 95fec7adfc
3 changed files with 169 additions and 16 deletions

View File

@ -10,7 +10,7 @@
import spack.util.environment import spack.util.environment
class Cp2k(MakefilePackage): class Cp2k(MakefilePackage, CudaPackage):
"""CP2K is a quantum chemistry and solid state physics software package """CP2K is a quantum chemistry and solid state physics software package
that can perform atomistic simulations of solid state, liquid, molecular, that can perform atomistic simulations of solid state, liquid, molecular,
periodic, material, crystal, and biological systems periodic, material, crystal, and biological systems
@ -44,6 +44,23 @@ class Cp2k(MakefilePackage):
description=('Enable planewave electronic structure' description=('Enable planewave electronic structure'
' calculations via SIRIUS')) ' calculations via SIRIUS'))
# override cuda_arch from CudaPackage since we only support one arch
# at a time and only specific ones for which we have parameter files
# for optimal kernels
variant('cuda_arch',
description='CUDA architecture',
default='none',
values=('none', '35', '37', '60'),
multi=False)
variant('cuda_arch_35_k20x', default=False,
description=('CP2K (resp. DBCSR) has specific parameter sets for'
' different GPU models. Enable this when building'
' with cuda_arch=35 for a K20x instead of a K40'))
variant('cuda_fft', default=False,
description=('Use CUDA also for FFTs in the PW part of CP2K'))
variant('cuda_blas', default=False,
description=('Use CUBLAS for general matrix operations in DBCSR'))
depends_on('python', type='build') depends_on('python', type='build')
depends_on('fftw@3:', when='~openmp') depends_on('fftw@3:', when='~openmp')
@ -91,19 +108,23 @@ class Cp2k(MakefilePackage):
# to get JSON-based UPF format support used in combination with SIRIUS # to get JSON-based UPF format support used in combination with SIRIUS
depends_on('json-fortran', when='+sirius') depends_on('json-fortran', when='+sirius')
# the bundled libcusmm uses numpy in the parameter prediction (v7+)
depends_on('py-numpy', when='@7:+cuda', type='build')
# PEXSI, ELPA and SIRIUS need MPI in CP2K # PEXSI, ELPA and SIRIUS need MPI in CP2K
conflicts('~mpi', '+pexsi') conflicts('~mpi', '+pexsi')
conflicts('~mpi', '+elpa') conflicts('~mpi', '+elpa')
conflicts('~mpi', '+sirius') conflicts('~mpi', '+sirius')
conflicts('+sirius', '@:6.999') # sirius support was introduced in 7+ conflicts('+sirius', '@:6.999') # sirius support was introduced in 7+
conflicts('~cuda', '+cuda_fft')
conflicts('~cuda', '+cuda_blas')
# Apparently cp2k@4.1 needs an "experimental" version of libwannier.a # Apparently cp2k@4.1 needs an "experimental" version of libwannier.a
# which is only available contacting the developer directly. See INSTALL # which is only available contacting the developer directly. See INSTALL
# in the stage of cp2k@4.1 # in the stage of cp2k@4.1
depends_on('wannier90', when='@3.0+mpi', type='build') depends_on('wannier90', when='@3.0+mpi', type='build')
# TODO : add dependency on CUDA
# CP2K needs compiler specific compilation flags, e.g. optflags # CP2K needs compiler specific compilation flags, e.g. optflags
conflicts('%clang') conflicts('%clang')
conflicts('%cray') conflicts('%cray')
@ -161,19 +182,23 @@ def edit(self, spec, prefix):
elif '^mpi@2:' in spec: elif '^mpi@2:' in spec:
cppflags.append('-D__MPI_VERSION=2') cppflags.append('-D__MPI_VERSION=2')
if '^intel-mkl' in spec:
cppflags.append('-D__FFTSG')
cflags = optimization_flags[self.spec.compiler.name][:] cflags = optimization_flags[self.spec.compiler.name][:]
cxxflags = optimization_flags[self.spec.compiler.name][:] cxxflags = optimization_flags[self.spec.compiler.name][:]
fcflags = optimization_flags[self.spec.compiler.name][:] fcflags = optimization_flags[self.spec.compiler.name][:]
nvflags = ['-O3']
ldflags = [] ldflags = []
libs = [] libs = []
gpuver = ''
if '%intel' in spec: if '%intel' in spec:
cflags.append('-fp-model precise') cflags.append('-fp-model precise')
cxxflags.append('-fp-model precise') cxxflags.append('-fp-model precise')
fcflags.extend(['-fp-model source', '-heap-arrays 64']) fcflags += [
'-fp-model source',
'-heap-arrays 64',
'-g',
'-traceback',
]
elif '%gcc' in spec: elif '%gcc' in spec:
fcflags.extend([ fcflags.extend([
'-ffree-form', '-ffree-form',
@ -184,8 +209,12 @@ def edit(self, spec, prefix):
fcflags.extend(['-Mfreeform', '-Mextend']) fcflags.extend(['-Mfreeform', '-Mextend'])
if '+openmp' in spec: if '+openmp' in spec:
cflags.append(self.compiler.openmp_flag)
cxxflags.append(self.compiler.openmp_flag)
fcflags.append(self.compiler.openmp_flag) fcflags.append(self.compiler.openmp_flag)
ldflags.append(self.compiler.openmp_flag) ldflags.append(self.compiler.openmp_flag)
nvflags.append('-Xcompiler="{0}"'.format(
self.compiler.openmp_flag))
ldflags.append(fftw.libs.search_flags) ldflags.append(fftw.libs.search_flags)
@ -231,6 +260,11 @@ def edit(self, spec, prefix):
ldflags.append((lapack + blas).search_flags) ldflags.append((lapack + blas).search_flags)
libs.extend([str(x) for x in (fftw.libs, lapack, blas)]) libs.extend([str(x) for x in (fftw.libs, lapack, blas)])
if self.spec.variants['blas'].value == 'mkl':
cppflags += ['-D__MKL']
elif self.spec.variants['blas'].value == 'accelerate':
cppflags += ['-D__ACCELERATE']
# MPI # MPI
if '+mpi' in self.spec: if '+mpi' in self.spec:
cppflags.extend([ cppflags.extend([
@ -309,15 +343,38 @@ def edit(self, spec, prefix):
sirius = spec['sirius'] sirius = spec['sirius']
cppflags.append('-D__SIRIUS') cppflags.append('-D__SIRIUS')
fcflags += ['-I{0}'.format(os.path.join(sirius.prefix, 'fortran'))] fcflags += ['-I{0}'.format(os.path.join(sirius.prefix, 'fortran'))]
libs += [ libs += list(sirius.libs)
os.path.join(sirius.libs.directories[0],
'libsirius_f.{0}'.format(dso_suffix))
]
cppflags.append('-D__JSON') cppflags.append('-D__JSON')
fcflags += ['$(shell pkg-config --cflags json-fortran)'] fcflags += ['$(shell pkg-config --cflags json-fortran)']
libs += ['$(shell pkg-config --libs json-fortran)'] libs += ['$(shell pkg-config --libs json-fortran)']
if self.spec.satisfies('+cuda'):
cppflags += ['-D__ACC']
libs += ['-lcudart', '-lnvrtc', '-lcuda']
if self.spec.satisfies('+cuda_blas'):
cppflags += ['-D__DBCSR_ACC=2']
libs += ['-lcublas']
else:
cppflags += ['-D__DBCSR_ACC']
if self.spec.satisfies('+cuda_fft'):
cppflags += ['-D__PW_CUDA']
libs += ['-lcufft', '-lcublas']
cuda_arch = self.spec.variants['cuda_arch'].value
if cuda_arch:
gpuver = {
'35': 'K40',
'37': 'K80',
'60': 'P100',
}[cuda_arch]
if (cuda_arch == '35'
and self.spec.satisfies('+cuda_arch_35_k20x')):
gpuver = 'K20X'
if 'smm=libsmm' in spec: if 'smm=libsmm' in spec:
lib_dir = os.path.join( lib_dir = os.path.join(
'lib', self.makefile_architecture, self.makefile_version 'lib', self.makefile_architecture, self.makefile_version
@ -349,6 +406,7 @@ def edit(self, spec, prefix):
cflags.extend(cppflags) cflags.extend(cppflags)
cxxflags.extend(cppflags) cxxflags.extend(cppflags)
fcflags.extend(cppflags) fcflags.extend(cppflags)
nvflags.extend(cppflags)
with open(self.makefile, 'w') as mkf: with open(self.makefile, 'w') as mkf:
if '+plumed' in self.spec: if '+plumed' in self.spec:
@ -373,11 +431,16 @@ def edit(self, spec, prefix):
mkf.write('FC = {0}\n'.format(fc)) mkf.write('FC = {0}\n'.format(fc))
mkf.write('LD = {0}\n'.format(fc)) mkf.write('LD = {0}\n'.format(fc))
if self.spec.satisfies('+cuda'):
mkf.write('NVCC = {0}\n'.format(
os.path.join(self.spec['cuda'].prefix, 'bin', 'nvcc')))
# Write compiler flags to file # Write compiler flags to file
mkf.write('DFLAGS = {0}\n\n'.format(' '.join(dflags))) mkf.write('DFLAGS = {0}\n\n'.format(' '.join(dflags)))
mkf.write('CPPFLAGS = {0}\n\n'.format(' '.join(cppflags))) mkf.write('CPPFLAGS = {0}\n\n'.format(' '.join(cppflags)))
mkf.write('CFLAGS = {0}\n\n'.format(' '.join(cflags))) mkf.write('CFLAGS = {0}\n\n'.format(' '.join(cflags)))
mkf.write('CXXFLAGS = {0}\n\n'.format(' '.join(cxxflags))) mkf.write('CXXFLAGS = {0}\n\n'.format(' '.join(cxxflags)))
mkf.write('NVFLAGS = {0}\n\n'.format(' '.join(nvflags)))
mkf.write('FCFLAGS = {0}\n\n'.format(' '.join(fcflags))) mkf.write('FCFLAGS = {0}\n\n'.format(' '.join(fcflags)))
mkf.write('LDFLAGS = {0}\n\n'.format(' '.join(ldflags))) mkf.write('LDFLAGS = {0}\n\n'.format(' '.join(ldflags)))
if '%intel' in spec: if '%intel' in spec:
@ -385,6 +448,7 @@ def edit(self, spec, prefix):
' '.join(ldflags) + ' -nofor_main') ' '.join(ldflags) + ' -nofor_main')
) )
mkf.write('LIBS = {0}\n\n'.format(' '.join(libs))) mkf.write('LIBS = {0}\n\n'.format(' '.join(libs)))
mkf.write('GPUVER = {0}\n\n'.format(gpuver))
mkf.write('DATA_DIR = {0}\n\n'.format(self.prefix.share.data)) mkf.write('DATA_DIR = {0}\n\n'.format(self.prefix.share.data))
@property @property

View File

@ -0,0 +1,53 @@
From 4b51d07369b5972f3917cc8f2425caa814ae0975 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Tiziano=20M=C3=BCller?= <tiziano.mueller@chem.uzh.ch>
Date: Thu, 16 May 2019 10:53:04 +0200
Subject: [PATCH] cmake: fix shared library installation
fixes the error during `make install`:
TARGETS given no LIBRARY DESTINATION for shared library target
when building shared libraries.
... and respect the current OS/distro library dir.
---
src/CMakeLists.txt | 11 +++++++++--
1 file changed, 9 insertions(+), 2 deletions(-)
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 65307dd3..2b7a5279 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -2,6 +2,8 @@
# working correctly
# list(APPEND CUDA_NVCC_FLAGS "-Xcompiler -fPIC")
+include(GNUInstallDirs) # required to get a proper LIBDIR variable
+
# keep two libraries: libsirius and libsirius_f
if(USE_CUDA)
@@ -9,13 +11,18 @@ if(USE_CUDA)
file(GLOB_RECURSE CUFILES_KERNELS "Kernels/*.cu")
add_library(sirius_cu "${CUFILES_KERNELS};${CUFILES_SDDK}")
set_target_properties(sirius_cu PROPERTIES POSITION_INDEPENDENT_CODE ON)
- INSTALL (TARGETS sirius_cu ARCHIVE DESTINATION ${CMAKE_INSTALL_PREFIX}/lib/)
+ INSTALL (TARGETS sirius_cu
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ )
endif()
if(CREATE_FORTRAN_BINDINGS)
add_library(sirius_f "sirius_api.cpp;sirius.f90")
SIRIUS_SETUP_TARGET(sirius_f)
INSTALL (TARGETS sirius_f ARCHIVE DESTINATION
- ${CMAKE_INSTALL_PREFIX}/lib/)
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ LIBRARY DESTINATION "${CMAKE_INSTALL_LIBDIR}"
+ )
set_target_properties(sirius_f PROPERTIES POSITION_INDEPENDENT_CODE ON)
set_target_properties(sirius_f PROPERTIES Fortran_MODULE_DIRECTORY mod_files)
target_link_libraries(sirius_f PUBLIC OpenMP::OpenMP_CXX)
--
2.16.4

View File

@ -8,7 +8,7 @@
from spack import * from spack import *
class Sirius(CMakePackage): class Sirius(CMakePackage, CudaPackage):
"""Domain specific library for electronic structure calculations""" """Domain specific library for electronic structure calculations"""
homepage = "https://github.com/electronic-structure/SIRIUS" homepage = "https://github.com/electronic-structure/SIRIUS"
@ -38,12 +38,14 @@ class Sirius(CMakePackage):
depends_on('elpa~openmp', when='+elpa~openmp') depends_on('elpa~openmp', when='+elpa~openmp')
depends_on('libvdwxc+mpi', when='+vdwxc') depends_on('libvdwxc+mpi', when='+vdwxc')
depends_on('scalapack', when='+scalapack') depends_on('scalapack', when='+scalapack')
depends_on("cuda", when="+cuda")
# TODO: # TODO:
# add support for MKL, CUDA, MAGMA, CRAY_LIBSCI, Python bindings, testing # add support for MKL, MAGMA, CRAY_LIBSCI, Python bindings, testing
patch("strip-spglib-include-subfolder.patch") patch("strip-spglib-include-subfolder.patch")
patch("link-libraries-fortran.patch") patch("link-libraries-fortran.patch")
patch("cmake-fix-shared-library-installation.patch")
@property @property
def libs(self): def libs(self):
@ -52,12 +54,17 @@ def libs(self):
if self.spec.satisfies('+fortran'): if self.spec.satisfies('+fortran'):
libraries += ['libsirius_f'] libraries += ['libsirius_f']
if self.spec.satisfies('+cuda'):
libraries += ['libsirius_cu']
return find_libraries( return find_libraries(
libraries, root=self.prefix, libraries, root=self.prefix,
shared=self.spec.satisfies('+shared'), recursive=True shared=self.spec.satisfies('+shared'), recursive=True
) )
def cmake_args(self): def cmake_args(self):
spec = self.spec
def _def(variant, flag=None): def _def(variant, flag=None):
"""Returns "-DUSE_VARIANT:BOOL={ON,OFF}" depending on whether """Returns "-DUSE_VARIANT:BOOL={ON,OFF}" depending on whether
+variant is set. If the CMake flag differs from the variant +variant is set. If the CMake flag differs from the variant
@ -68,7 +75,7 @@ def _def(variant, flag=None):
flag if flag else "USE_{0}".format( flag if flag else "USE_{0}".format(
variant.strip('+~').upper() variant.strip('+~').upper()
), ),
"ON" if self.spec.satisfies(variant) else "OFF" "ON" if spec.satisfies(variant) else "OFF"
) )
args = [ args = [
@ -78,13 +85,42 @@ def _def(variant, flag=None):
_def('+vdwxc'), _def('+vdwxc'),
_def('+scalapack'), _def('+scalapack'),
_def('+fortran', 'CREATE_FORTRAN_BINDINGS'), _def('+fortran', 'CREATE_FORTRAN_BINDINGS'),
_def('+cuda')
] ]
if self.spec.satisfies('+elpa'): lapack = spec['lapack']
blas = spec['blas']
args += [
'-DLAPACK_FOUND=true',
'-DLAPACK_INCLUDE_DIRS={0}'.format(lapack.prefix.include),
'-DLAPACK_LIBRARIES={0}'.format(lapack.libs.joined(';')),
'-DBLAS_FOUND=true',
'-DBLAS_INCLUDE_DIRS={0}'.format(blas.prefix.include),
'-DBLAS_LIBRARIES={0}'.format(blas.libs.joined(';')),
]
if '+scalapack' in spec:
args += [
'-DSCALAPACK_FOUND=true',
'-DSCALAPACK_INCLUDE_DIRS={0}'.format(
spec['scalapack'].prefix.include),
'-DSCALAPACK_LIBRARIES={0}'.format(
spec['scalapack'].libs.joined(';')),
]
if spec.satisfies('+elpa'):
elpa_incdir = os.path.join( elpa_incdir = os.path.join(
self.spec['elpa'].headers.directories[0], spec['elpa'].headers.directories[0],
'elpa' 'elpa'
) )
args += ["-DELPA_INCLUDE_DIR={0}".format(elpa_incdir)] args += ["-DELPA_INCLUDE_DIR={0}".format(elpa_incdir)]
if spec.satisfies('+cuda'):
cuda_arch = spec.variants['cuda_arch'].value
if cuda_arch:
args += [
'-DCMAKE_CUDA_FLAGS=-arch=sm_{0}'.format(cuda_arch[0])
]
return args return args