Use Spack target architecture to determine OpenBLAS target (#14380)
Openblas target is now determined automatically upon inspection of `TargetList.txt`. If the spack target is a generic architecture family (like x86_64 or aarch64) the DYNAMIC_ARCH setting is used instead of targeting a specific microarchitecture.
This commit is contained in:
parent
b0fce56d5b
commit
ca6e75c9f6
@ -278,3 +278,14 @@ def test_version_components(version, expected_number, expected_suffix):
|
||||
number, suffix = llnl.util.cpu.version_components(version)
|
||||
assert number == expected_number
|
||||
assert suffix == expected_suffix
|
||||
|
||||
|
||||
def test_invalid_family():
|
||||
targets = llnl.util.cpu.targets
|
||||
multi_parents = Microarchitecture(
|
||||
name='chimera', parents=[targets['pentium4'], targets['power7']],
|
||||
vendor='Imagination', features=[], compilers={}, generation=0
|
||||
)
|
||||
with pytest.raises(AssertionError,
|
||||
matches='a target is expected to belong'):
|
||||
multi_parents.family
|
||||
|
@ -4,10 +4,10 @@
|
||||
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
from spack import *
|
||||
from spack.package_test import compare_output_file, compile_c_and_execute
|
||||
import spack.architecture
|
||||
|
||||
|
||||
class Openblas(MakefilePackage):
|
||||
@ -33,17 +33,9 @@ class Openblas(MakefilePackage):
|
||||
version('0.2.16', sha256='766f350d0a4be614812d535cead8c816fc3ad3b9afcd93167ea5e4df9d61869b')
|
||||
version('0.2.15', sha256='73c40ace5978282224e5e122a41c8388c5a19e65a6f2329c2b7c0b61bacc9044')
|
||||
|
||||
variant(
|
||||
'shared',
|
||||
default=True,
|
||||
description='Build shared libraries as well as static libs.'
|
||||
)
|
||||
variant('ilp64', default=False, description='64 bit integers')
|
||||
variant('ilp64', default=False, description='Force 64-bit Fortran native integers')
|
||||
variant('pic', default=True, description='Build position independent code')
|
||||
|
||||
variant('cpu_target', default='auto',
|
||||
description='Set CPU target architecture (leave empty for '
|
||||
'autodetection; GENERIC, SSE_GENERIC, NEHALEM, ...)')
|
||||
variant('shared', default=True, description='Build shared libraries')
|
||||
|
||||
variant(
|
||||
'threads', default='none',
|
||||
@ -52,24 +44,6 @@ class Openblas(MakefilePackage):
|
||||
multi=False
|
||||
)
|
||||
|
||||
variant(
|
||||
'virtual_machine',
|
||||
default=False,
|
||||
description="Adding options to build openblas on Linux virtual machine"
|
||||
)
|
||||
|
||||
variant(
|
||||
'avx2',
|
||||
default=True,
|
||||
description='Enable use of AVX2 instructions'
|
||||
)
|
||||
|
||||
variant(
|
||||
'avx512',
|
||||
default=False,
|
||||
description='Enable use of AVX512 instructions'
|
||||
)
|
||||
|
||||
# virtual dependency
|
||||
provides('blas')
|
||||
provides('lapack')
|
||||
@ -142,14 +116,80 @@ def check_compilers(self):
|
||||
'OpenBLAS @:0.2.19 does not support OpenMP with clang!'
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def _read_targets(target_file):
|
||||
"""Parse a list of available targets from the OpenBLAS/TargetList.txt
|
||||
file.
|
||||
"""
|
||||
micros = []
|
||||
re_target = re.compile(r'^[A-Z0-9_]+$')
|
||||
for line in target_file:
|
||||
match = re_target.match(line)
|
||||
if match is not None:
|
||||
micros.append(line.strip().lower())
|
||||
|
||||
return micros
|
||||
|
||||
@staticmethod
|
||||
def _microarch_target_args(microarch, available_targets):
|
||||
"""Given a spack microarchitecture and a list of targets found in
|
||||
OpenBLAS' TargetList.txt, determine the best command-line arguments.
|
||||
"""
|
||||
args = [] # Return value
|
||||
|
||||
# List of available architectures, and possible aliases
|
||||
openblas_arch = set(['alpha', 'arm', 'ia64', 'mips', 'mips64',
|
||||
'power', 'sparc', 'zarch'])
|
||||
openblas_arch_map = {
|
||||
'amd64': 'x86_64',
|
||||
'powerpc64': 'power',
|
||||
'i386': 'x86',
|
||||
'aarch64': 'arm64',
|
||||
}
|
||||
openblas_arch.update(openblas_arch_map.keys())
|
||||
openblas_arch.update(openblas_arch_map.values())
|
||||
|
||||
# Add spack-only microarchitectures to list
|
||||
skylake = set(["skylake", "skylake_avx512"])
|
||||
available_targets = set(available_targets) | skylake | openblas_arch
|
||||
|
||||
# Find closest ancestor that is known to build in blas
|
||||
if microarch.name not in available_targets:
|
||||
for microarch in microarch.ancestors:
|
||||
if microarch.name in available_targets:
|
||||
break
|
||||
|
||||
arch_name = microarch.family.name
|
||||
if arch_name in openblas_arch:
|
||||
# Apply possible spack->openblas arch name mapping
|
||||
arch_name = openblas_arch_map.get(arch_name, arch_name)
|
||||
args.append('ARCH=' + arch_name)
|
||||
|
||||
if microarch.vendor == 'generic':
|
||||
# User requested a generic platform, or we couldn't find a good
|
||||
# match for the requested one. Allow OpenBLAS to determine
|
||||
# an optimized kernel at run time.
|
||||
args.append('DYNAMIC_ARCH=1')
|
||||
elif microarch.name in skylake:
|
||||
# Special case for renaming skylake family
|
||||
args.append('TARGET=SKYLAKEX')
|
||||
if microarch.name == "skylake":
|
||||
# Special case for disabling avx512 instructions
|
||||
args.append('NO_AVX512=1')
|
||||
else:
|
||||
args.append('TARGET=' + microarch.name.upper())
|
||||
|
||||
return args
|
||||
|
||||
@property
|
||||
def make_defs(self):
|
||||
spec = self.spec
|
||||
|
||||
# Configure fails to pick up fortran from FC=/abs/path/to/fc, but
|
||||
# works fine with FC=/abs/path/to/gfortran.
|
||||
# When mixing compilers make sure that
|
||||
# $SPACK_ROOT/lib/spack/env/<compiler> have symlinks with reasonable
|
||||
# names and hack them inside lib/spack/spack/compilers/<compiler>.py
|
||||
|
||||
make_defs = [
|
||||
'CC={0}'.format(spack_cc),
|
||||
'FC={0}'.format(spack_fc),
|
||||
@ -161,23 +201,15 @@ def make_defs(self):
|
||||
else:
|
||||
make_defs.append('MAKE_NB_JOBS=0') # flag provided by OpenBLAS
|
||||
|
||||
if self.spec.variants['virtual_machine'].value:
|
||||
make_defs += [
|
||||
'DYNAMIC_ARCH=1',
|
||||
'NUM_THREADS=64', # OpenBLAS stores present no of CPUs as max
|
||||
]
|
||||
# Add target and architecture flags
|
||||
targetlist_name = join_path(self.stage.source_path, "TargetList.txt")
|
||||
if os.path.exists(targetlist_name):
|
||||
with open(targetlist_name) as f:
|
||||
avail_targets = self._read_targets(f)
|
||||
else:
|
||||
avail_targets = []
|
||||
make_defs += self._microarch_target_args(spec.target, avail_targets)
|
||||
|
||||
if self.spec.variants['cpu_target'].value != 'auto':
|
||||
make_defs += [
|
||||
'TARGET={0}'.format(self.spec.variants['cpu_target'].value)
|
||||
]
|
||||
# invoke make with the correct TARGET for aarch64
|
||||
elif 'aarch64' in spack.architecture.sys_type():
|
||||
make_defs += [
|
||||
'TARGET=ARMV8'
|
||||
]
|
||||
if self.spec.satisfies('%gcc@:4.8.4'):
|
||||
make_defs += ['NO_AVX2=1']
|
||||
if '~shared' in self.spec:
|
||||
if '+pic' in self.spec:
|
||||
make_defs.extend([
|
||||
@ -201,11 +233,9 @@ def make_defs(self):
|
||||
if '+ilp64' in self.spec:
|
||||
make_defs += ['INTERFACE64=1']
|
||||
|
||||
if self.spec.target.family == 'x86_64':
|
||||
if '~avx2' in self.spec:
|
||||
make_defs += ['NO_AVX2=1']
|
||||
if '~avx512' in self.spec:
|
||||
make_defs += ['NO_AVX512=1']
|
||||
# Prevent errors in `as` assembler from newer instructions
|
||||
if self.spec.satisfies('%gcc@:4.8.4'):
|
||||
make_defs.append('NO_AVX2=1')
|
||||
|
||||
return make_defs
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user