fftw: simplify the recipe and make use of specific targets (#12889)

* fftw: grouped precisions in a single variant

* fftw: simd options are now based on target features and not on variants

* fftw: simplified computing the selected precisions
This commit is contained in:
Massimiliano Culpo 2019-10-04 05:32:42 +02:00 committed by Adam J. Stewart
parent 46e319ecd4
commit 2cd800306d

View file

@ -3,12 +3,12 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
from spack import *
from spack.spec import ConflictsInSpecError
import os
import os.path
import llnl.util.lang
# os is used for rename, etc in patch()
import os
from spack import *
class Fftw(AutotoolsPackage):
@ -35,84 +35,32 @@ class Fftw(AutotoolsPackage):
patch('pgi-3.3.6-pl2.patch', when="@3.3.6-pl2%pgi", level=0)
variant(
'float', default=True,
description='Produces a single precision version of the library')
variant(
'double', default=True,
description='Produces a double precision version of the library')
variant(
'long_double', default=True,
description='Produces a long double precision version of the library')
variant(
'quad', default=False,
description='Produces a quad precision version of the library '
'(works only with GCC and libquadmath)')
'precision', values=any_combination_of(
'float', 'double', 'long_double', 'quad'
).prohibit_empty_set().with_default('float,double'),
description='Build the selected floating-point precision libraries'
)
variant('openmp', default=False, description="Enable OpenMP support.")
variant('mpi', default=True, description='Activate MPI support')
variant(
'pfft_patches', default=False,
description='Add extra transpose functions for PFFT compatibility')
variant(
'simd',
default='generic-simd128,generic-simd256',
values=(
'sse', 'sse2', 'avx', 'avx2', 'avx512', # Intel
'avx-128-fma', 'kcvi', # Intel
'altivec', 'vsx', # IBM
'neon', # ARM
'generic-simd128', 'generic-simd256' # Generic
),
description='Optimizations that are enabled in this build',
multi=True
)
variant('fma', default=False, description='Activate support for fma')
depends_on('mpi', when='+mpi')
depends_on('automake', type='build', when='+pfft_patches')
depends_on('autoconf', type='build', when='+pfft_patches')
depends_on('libtool', type='build', when='+pfft_patches')
# https://github.com/FFTW/fftw3/commit/902d0982522cdf6f0acd60f01f59203824e8e6f3
conflicts('%gcc@8:8.9999', when="@3.3.7")
conflicts('precision=long_double', when='@2.1.5',
msg='Long double precision is not supported in FFTW 2')
conflicts('precision=quad', when='@2.1.5',
msg='Quad precision is not supported in FFTW 2')
provides('fftw-api@2', when='@2.1.5')
provides('fftw-api@3', when='@3:')
def flag_handler(self, name, flags):
arch = ""
spec = self.spec
target_simds = {
('x86_64',): ('sse', 'sse2', 'avx', 'avx2', 'avx512',
'avx-128-fma', 'kcvi'),
('ppc', 'ppc64le', 'power7'): ('altivec', 'vsx'),
('arm',): ('neon',)
}
if spec.satisfies("platform=cray"):
# FIXME; It is assumed that cray is x86_64.
# If you support arm on cray, you need to fix it.
arch = "x86_64"
for targets, simds in target_simds.items():
if (
(arch not in targets)
and str(spec.target.family) not in targets
):
if any(spec.satisfies('simd={0}'.format(x)) for x in simds):
raise ConflictsInSpecError(
spec,
[(
spec,
spec.architecture.target,
spec.variants['simd'],
'simd={0} are valid only on {1}'.format(
','.join(target_simds[targets]),
','.join(targets)
)
)]
)
return (flags, None, None)
@property
def libs(self):
@ -157,6 +105,11 @@ def autoreconf(self, spec, prefix):
autoreconf = which('autoreconf')
autoreconf('-ifv')
@property
def selected_precisions(self):
"""Precisions that have been selected in this build"""
return self.spec.variants['precision'].value
def configure(self, spec, prefix):
# Base options
options = [
@ -184,68 +137,60 @@ def configure(self, spec, prefix):
if '+mpi' in spec:
options.append('--enable-mpi')
# SIMD support
float_options, double_options = [], []
if spec.satisfies('@3:', strict=True):
for opts in (float_options, double_options):
opts += self.enable_or_disable('simd')
opts += self.enable_or_disable('fma')
# Specific SIMD support. Note there's SSE support too for float, but
# given that it can be activated only for float and that most machines
# are new enough to have SSE2 it has been skipped not to complicate the
# recipe further.
simd_features = ['sse2', 'avx', 'avx2', 'avx512', 'avx-128-fma',
'kcvi', 'altivec', 'vsx', 'neon']
simd_options = []
for feature in simd_features:
msg = '--enable-{0}' if feature in spec.target else '--disable-{0}'
simd_options.append(msg.format(feature))
# If no features are found, enable the generic ones
if not any(f in spec.target for f in simd_features):
simd_options += [
'--enable-generic-simd128',
'--enable-generic-simd256'
]
simd_options += [
'--enable-fma' if 'fma' in spec.target else '--disable-fma'
]
# Double is the default precision, for all the others we need
# to enable the corresponding option.
enable_precision = {
'float': ['--enable-float'],
'double': None,
'long_double': ['--enable-long-double'],
'quad': ['--enable-quad-precision']
}
# Different precisions must be configured and compiled one at a time
configure = Executable('../configure')
for precision in self.selected_precisions:
opts = (enable_precision[precision] or []) + options[:]
# Build double/float/long double/quad variants
if '+double' in spec:
with working_dir('double', create=True):
configure(*(options + double_options))
if '+float' in spec:
with working_dir('float', create=True):
configure('--enable-float', *(options + float_options))
if spec.satisfies('@3:+long_double'):
with working_dir('long-double', create=True):
configure('--enable-long-double', *options)
if spec.satisfies('@3:+quad'):
with working_dir('quad', create=True):
configure('--enable-quad-precision', *options)
# SIMD optimizations are available only for float and double
# starting from FFTW 3
if precision in ('float', 'double') and spec.satisfies('@3:'):
opts += simd_options
with working_dir(precision, create=True):
configure(*opts)
def for_each_precision_make(self, *targets):
for precision in self.selected_precisions:
with working_dir(precision):
make(*targets)
def build(self, spec, prefix):
if '+double' in spec:
with working_dir('double'):
make()
if '+float' in spec:
with working_dir('float'):
make()
if spec.satisfies('@3:+long_double'):
with working_dir('long-double'):
make()
if spec.satisfies('@3:+quad'):
with working_dir('quad'):
make()
self.for_each_precision_make()
def check(self):
spec = self.spec
if '+double' in spec:
with working_dir('double'):
make("check")
if '+float' in spec:
with working_dir('float'):
make("check")
if spec.satisfies('@3:+long_double'):
with working_dir('long-double'):
make("check")
if spec.satisfies('@3:+quad'):
with working_dir('quad'):
make("check")
self.for_each_precision_make('check')
def install(self, spec, prefix):
if '+double' in spec:
with working_dir('double'):
make("install")
if '+float' in spec:
with working_dir('float'):
make("install")
if spec.satisfies('@3:+long_double'):
with working_dir('long-double'):
make("install")
if spec.satisfies('@3:+quad'):
with working_dir('quad'):
make("install")
self.for_each_precision_make('install')