diff options
author | Massimiliano Culpo <massimiliano.culpo@gmail.com> | 2019-10-19 22:19:29 +0200 |
---|---|---|
committer | Todd Gamblin <tgamblin@llnl.gov> | 2019-10-19 13:19:29 -0700 |
commit | 41fb0395a61093373eb8942b257308bbcc49c2dc (patch) | |
tree | 20c7c6d9ec377e6fc0220be35566ebfc1cabc13b /lib | |
parent | 0fb563f3d9f944f25f3badbf91d53754ef075aaa (diff) | |
download | spack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.gz spack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.bz2 spack-41fb0395a61093373eb8942b257308bbcc49c2dc.tar.xz spack-41fb0395a61093373eb8942b257308bbcc49c2dc.zip |
Microarchitecture specific optimizations for LLVM (#13250)
* Added architecture specific optimization flags for Clang / LLVM
* Disallow compiler optimizations for mixed toolchains
* We emit a warning when building for a mixed toolchain
* Fixed issues with suffixed versions of compilers; Apple's Clang will,
for the time being, fall back on x86-64 for every compilation.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/spack/llnl/util/cpu/microarchitecture.py | 3 | ||||
-rw-r--r-- | lib/spack/llnl/util/cpu/microarchitectures.json | 187 | ||||
-rw-r--r-- | lib/spack/spack/architecture.py | 16 | ||||
-rw-r--r-- | lib/spack/spack/compilers/__init__.py | 38 | ||||
-rw-r--r-- | lib/spack/spack/test/architecture.py | 18 | ||||
-rw-r--r-- | lib/spack/spack/test/compilers.py | 8 | ||||
-rw-r--r-- | lib/spack/spack/test/concretize.py | 4 | ||||
-rw-r--r-- | lib/spack/spack/test/data/compilers.yaml | 21 | ||||
-rw-r--r-- | lib/spack/spack/test/llnl/util/cpu.py | 7 |
9 files changed, 292 insertions, 10 deletions
diff --git a/lib/spack/llnl/util/cpu/microarchitecture.py b/lib/spack/llnl/util/cpu/microarchitecture.py index 319eec28c7..e14e1a8c66 100644 --- a/lib/spack/llnl/util/cpu/microarchitecture.py +++ b/lib/spack/llnl/util/cpu/microarchitecture.py @@ -224,7 +224,8 @@ class Microarchitecture(object): version, _, suffix = version.partition('-') # If the suffixes are not all equal there's no match - if suffix != min_suffix or suffix != max_suffix: + if ((suffix != min_suffix and min_version) or + (suffix != max_suffix and max_version)): return False # Assume compiler versions fit into semver diff --git a/lib/spack/llnl/util/cpu/microarchitectures.json b/lib/spack/llnl/util/cpu/microarchitectures.json index 88e2bb665f..02f507fa6d 100644 --- a/lib/spack/llnl/util/cpu/microarchitectures.json +++ b/lib/spack/llnl/util/cpu/microarchitectures.json @@ -60,7 +60,12 @@ "name": "x86-64", "flags": "-march={name} -mtune={name}" } - ] + ], + "clang": { + "versions": ":", + "family": "x86-64", + "flags": "-march={family} -mcpu=generic" + } } }, "nocona": { @@ -76,6 +81,11 @@ "gcc": { "versions": "4:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -92,6 +102,11 @@ "gcc": { "versions": "4:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -118,7 +133,12 @@ "name": "corei7", "flags": "-march={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + } } }, "westmere": { @@ -139,6 +159,11 @@ "gcc": { "versions": "4.9:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -168,7 +193,12 @@ "name": "corei7-avx", "flags": "-march={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + } } }, "ivybridge": { @@ -199,7 +229,12 @@ "name": "core-avx-i", "flags": "-march={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + } } }, "haswell": { @@ -235,7 +270,12 @@ "name": "core-avx2", "flags": "-march={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + } } }, "broadwell": { @@ -266,6 +306,11 @@ "gcc": { "versions": "4.9:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -300,6 +345,11 @@ "gcc": { "versions": "5.3:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -337,6 +387,12 @@ "versions": "5.1:", "name": "knl", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "knl", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -378,6 +434,12 @@ "name": "skylake-avx512", "versions": "5.3:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "skylake-avx512", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -421,6 +483,11 @@ "gcc": { "versions": "8:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -462,6 +529,11 @@ "gcc": { "versions": "9:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "8.0:", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -518,7 +590,20 @@ "name": "icelake-client", "versions": "8:", "flags": "-march={name} -mtune={name}" - } + }, + "clang": [ + { + "versions": "7.0:", + "name": "icelake-client", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + }, + { + "versions": "6.0:6.9", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" + } + ] } }, "bulldozer": { @@ -545,6 +630,12 @@ "name": "bdver1", "versions": "4.6:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "bdver1", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -576,6 +667,12 @@ "name": "bdver2", "versions": "4.7:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "bdver2", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -608,6 +705,12 @@ "name": "bdver3", "versions": "4.8:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "bdver3", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -643,6 +746,12 @@ "name": "bdver4", "versions": "4.9:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "name": "bdver4", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -681,6 +790,12 @@ "name": "znver1", "versions": "6:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "4.0:", + "name": "znver1", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -720,6 +835,12 @@ "name": "znver2", "versions": "9:", "flags": "-march={name} -mtune={name}" + }, + "clang": { + "versions": "9.0:", + "name": "znver2", + "family": "x86-64", + "flags": "-march={family} -mcpu={name}" } } }, @@ -732,6 +853,11 @@ "name": "powerpc64", "versions": "4:", "flags": "-mcpu={name} -mtune={name}" + }, + "clang": { + "versions": ":", + "family": "ppc64", + "flags": "-march={family} -mcpu=generic" } } }, @@ -744,6 +870,12 @@ "gcc": { "versions": "4.5:", "flags": "-mcpu={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "ppc64", + "name": "pwr7", + "flags": "-march={family} -mcpu={name}" } } }, @@ -763,7 +895,13 @@ "warnings": "Using GCC 4.8 to optimize for Power 8 might not work if you are not on Red Hat Enterprise Linux 7, where a custom backport of the feature has been done. Upstream support from GCC starts in version 4.9", "flags": "-mcpu={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "ppc64", + "name": "pwr8", + "flags": "-march={family} -mcpu={name}" + } } }, "power9": { @@ -775,6 +913,12 @@ "gcc": { "versions": "6:", "flags": "-mcpu={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "ppc64", + "name": "pwr9", + "flags": "-march={family} -mcpu={name}" } } }, @@ -787,6 +931,11 @@ "name": "powerpc64le", "versions": "4:", "flags": "-mcpu={name} -mtune={name}" + }, + "clang": { + "versions": ":", + "family": "ppc64le", + "flags": "-march={family} -mcpu=generic" } } }, @@ -808,7 +957,13 @@ "name": "power8", "flags": "-mcpu={name} -mtune={name}" } - ] + ], + "clang": { + "versions": "3.9:", + "family": "ppc64le", + "name": "pwr8", + "flags": "-march={family} -mcpu={name}" + } } }, "power9le": { @@ -821,6 +976,12 @@ "name": "power9", "versions": "6:", "flags": "-mcpu={name} -mtune={name}" + }, + "clang": { + "versions": "3.9:", + "family": "ppc64le", + "name": "pwr9", + "flags": "-march={family} -mcpu={name}" } } }, @@ -832,6 +993,11 @@ "gcc": { "versions": "4:", "flags": "-march=armv8-a -mtune=generic" + }, + "clang": { + "versions": ":", + "family": "aarch64", + "flags": "-march={family} -mcpu=generic" } } }, @@ -840,6 +1006,11 @@ "vendor": "generic", "features": [], "compilers": { + "clang": { + "versions": ":", + "family": "arm", + "flags": "-march={family} -mcpu=generic" + } } }, "ppc": { diff --git a/lib/spack/spack/architecture.py b/lib/spack/spack/architecture.py index 53cbc44ca5..dd99cfa1e3 100644 --- a/lib/spack/spack/architecture.py +++ b/lib/spack/spack/architecture.py @@ -58,6 +58,7 @@ will be responsible for compiler detection. """ import functools import inspect +import warnings import six @@ -184,6 +185,21 @@ class Target(object): return cpu_flag in self.microarchitecture def optimization_flags(self, compiler): + """Returns the flags needed to optimize for this target using + the compiler passed as argument. + + Args: + compiler (CompilerSpec or Compiler): object that contains both the + name and the version of the compiler we want to use + """ + if isinstance(compiler, spack.compiler.Compiler): + if spack.compilers.is_mixed_toolchain(compiler): + msg = ('microarchitecture specific optimizations are not ' + 'supported yet on mixed compiler toolchains [check' + ' {0.name}@{0.version} for further details]') + warnings.warn(msg.format(compiler)) + return '' + return self.microarchitecture.optimization_flags( compiler.name, str(compiler.version) ) diff --git a/lib/spack/spack/compilers/__init__.py b/lib/spack/spack/compilers/__init__.py index 206aa17e1b..bc2e4df391 100644 --- a/lib/spack/spack/compilers/__init__.py +++ b/lib/spack/spack/compilers/__init__.py @@ -676,6 +676,44 @@ def make_compiler_list(detected_versions): return compilers +def is_mixed_toolchain(compiler): + """Returns True if the current compiler is a mixed toolchain, + False otherwise. + + Args: + compiler (Compiler): a valid compiler object + """ + cc = os.path.basename(compiler.cc or '') + cxx = os.path.basename(compiler.cxx or '') + f77 = os.path.basename(compiler.f77 or '') + fc = os.path.basename(compiler.fc or '') + + toolchains = set() + for compiler_cls in all_compiler_types(): + # Inspect all the compiler toolchain we know. If a compiler is the + # only compiler supported there it belongs to that toolchain. + def name_matches(name, name_list): + # This is such that 'gcc' matches variations + # like 'ggc-9' etc that are found in distros + name, _, _ = name.partition('-') + return len(name_list) == 1 and name and name in name_list + + if any([ + name_matches(cc, compiler_cls.cc_names), + name_matches(cxx, compiler_cls.cxx_names), + name_matches(f77, compiler_cls.f77_names), + name_matches(fc, compiler_cls.fc_names) + ]): + tty.debug("[TOOLCHAIN] MATCH {0}".format(compiler_cls.__name__)) + toolchains.add(compiler_cls.__name__) + + if len(toolchains) > 1: + tty.debug("[TOOLCHAINS] {0}".format(toolchains)) + return True + + return False + + class InvalidCompilerConfigurationError(spack.error.SpackError): def __init__(self, compiler_spec): diff --git a/lib/spack/spack/test/architecture.py b/lib/spack/spack/test/architecture.py index b36219aa76..7e120000d4 100644 --- a/lib/spack/spack/test/architecture.py +++ b/lib/spack/spack/test/architecture.py @@ -169,3 +169,21 @@ def test_target_container_semantic(cpu_flag, target_name): def test_arch_spec_container_semantic(item, architecture_str): architecture = spack.spec.ArchSpec(architecture_str) assert item in architecture + + +@pytest.mark.parametrize('compiler_spec,target_name,expected_flags', [ + # Check compilers with version numbers from a single toolchain + ('gcc@4.7.2', 'haswell', '-march=core-avx2 -mtune=core-avx2'), + # Check mixed toolchains + ('clang@8.0.0', 'broadwell', ''), + # Check clang compilers with 'apple' suffix + ('clang@9.1.0-apple', 'x86_64', '-march=x86-64 -mcpu=generic') +]) +@pytest.mark.filterwarnings("ignore:microarchitecture specific") +def test_optimization_flags( + compiler_spec, target_name, expected_flags, config +): + target = spack.architecture.Target(target_name) + compiler = spack.compilers.compilers_for_spec(compiler_spec).pop() + opt_flags = target.optimization_flags(compiler) + assert opt_flags == expected_flags diff --git a/lib/spack/spack/test/compilers.py b/lib/spack/spack/test/compilers.py index dc104225f1..ac107170b0 100644 --- a/lib/spack/spack/test/compilers.py +++ b/lib/spack/spack/test/compilers.py @@ -469,3 +469,11 @@ def test_cce_version_detection(version_str, expected_version): def test_fj_version_detection(version_str, expected_version): version = spack.compilers.fj.Fj.extract_version_from_output(version_str) assert version == expected_version + + +@pytest.mark.parametrize('compiler_spec,expected_result', [ + ('gcc@4.7.2', False), ('clang@3.3', False), ('clang@8.0.0', True) +]) +def test_detecting_mixed_toolchains(compiler_spec, expected_result, config): + compiler = spack.compilers.compilers_for_spec(compiler_spec).pop() + assert spack.compilers.is_mixed_toolchain(compiler) is expected_result diff --git a/lib/spack/spack/test/concretize.py b/lib/spack/spack/test/concretize.py index 5243ba7681..f0c8e93bcf 100644 --- a/lib/spack/spack/test/concretize.py +++ b/lib/spack/spack/test/concretize.py @@ -585,7 +585,9 @@ class TestConcretize(object): @pytest.mark.parametrize('spec, best_achievable', [ ('mpileaks%gcc@4.8', 'haswell'), - ('mpileaks%gcc@5.3.0', 'skylake_avx512') + ('mpileaks%gcc@5.3.0', 'skylake_avx512'), + # Apple's clang always falls back to x86-64 for now + ('mpileaks%clang@9.1.0-apple', 'x86_64') ]) def test_adjusting_default_target_based_on_compiler( self, spec, best_achievable, current_host diff --git a/lib/spack/spack/test/data/compilers.yaml b/lib/spack/spack/test/data/compilers.yaml index d7092945d5..f619c8d351 100644 --- a/lib/spack/spack/test/data/compilers.yaml +++ b/lib/spack/spack/test/data/compilers.yaml @@ -114,3 +114,24 @@ compilers: cflags: -O3 cxxflags: -O3 modules: 'None' +- compiler: + spec: clang@8.0.0 + operating_system: redhat7 + paths: + cc: /path/to/clang-8 + cxx: /path/to/clang++-8 + f77: /path/to/gfortran-9 + fc: /path/to/gfortran-9 + flags: + cflags: -O3 + cxxflags: -O3 + modules: 'None' +- compiler: + spec: clang@9.1.0-apple + operating_system: elcapitan + paths: + cc: /path/to/clang + cxx: /path/to/clang++ + f77: None + fc: None + modules: 'None' diff --git a/lib/spack/spack/test/llnl/util/cpu.py b/lib/spack/spack/test/llnl/util/cpu.py index 9c65825a52..5713580a72 100644 --- a/lib/spack/spack/test/llnl/util/cpu.py +++ b/lib/spack/spack/test/llnl/util/cpu.py @@ -191,6 +191,7 @@ def test_target_json_schema(): @pytest.mark.parametrize('target_name,compiler,version,expected_flags', [ + # Test GCC ('x86_64', 'gcc', '4.9.3', '-march=x86-64 -mtune=generic'), ('x86_64', 'gcc', '4.2.0', '-march=x86-64 -mtune=generic'), ('x86_64', 'gcc', '4.1.1', '-march=x86-64 -mtune=x86-64'), @@ -198,6 +199,12 @@ def test_target_json_schema(): ('nehalem', 'gcc', '4.9.3', '-march=nehalem -mtune=nehalem'), ('nehalem', 'gcc', '4.8.5', '-march=corei7 -mtune=corei7'), ('sandybridge', 'gcc', '4.8.5', '-march=corei7-avx -mtune=corei7-avx'), + # Test Clang / LLVM + ('sandybridge', 'clang', '3.9.0', '-march=x86-64 -mcpu=sandybridge'), + ('icelake', 'clang', '6.0.0', '-march=x86-64 -mcpu=icelake'), + ('icelake', 'clang', '8.0.0', '-march=x86-64 -mcpu=icelake-client'), + ('zen2', 'clang', '9.0.0', '-march=x86-64 -mcpu=znver2'), + ('power9le', 'clang', '8.0.0', '-march=ppc64le -mcpu=pwr9'), # Test that an unknown compiler returns an empty string ('sandybridge', 'unknown', '4.8.5', ''), ]) |