summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/spack/spack/solver/asp.py123
-rw-r--r--lib/spack/spack/solver/concretize.lp82
-rw-r--r--lib/spack/spack/solver/display.lp6
3 files changed, 145 insertions, 66 deletions
diff --git a/lib/spack/spack/solver/asp.py b/lib/spack/spack/solver/asp.py
index cc0616f24d..d85eae81bf 100644
--- a/lib/spack/spack/solver/asp.py
+++ b/lib/spack/spack/solver/asp.py
@@ -265,6 +265,8 @@ class AspGenerator(object):
def available_compilers(self):
"""Facts about available compilers."""
+
+ self.h2("Available compilers")
compilers = spack.compilers.all_compiler_specs()
compiler_versions = collections.defaultdict(lambda: set())
@@ -438,18 +440,18 @@ class AspGenerator(object):
# TODO: do this with consistent suffixes.
class Head(object):
node = fn.node
- arch_platform = fn.arch_platform_set
- arch_os = fn.arch_os_set
- arch_target = fn.arch_target_set
+ node_platform = fn.node_platform_set
+ node_os = fn.node_os_set
+ node_target = fn.node_target_set
variant = fn.variant_set
node_compiler = fn.node_compiler
node_compiler_version = fn.node_compiler_version
class Body(object):
node = fn.node
- arch_platform = fn.arch_platform
- arch_os = fn.arch_os
- arch_target = fn.arch_target
+ node_platform = fn.node_platform
+ node_os = fn.node_os
+ node_target = fn.node_target
variant = fn.variant_value
node_compiler = fn.node_compiler
node_compiler_version = fn.node_compiler_version
@@ -466,11 +468,11 @@ class AspGenerator(object):
arch = spec.architecture
if arch:
if arch.platform:
- clauses.append(f.arch_platform(spec.name, arch.platform))
+ clauses.append(f.node_platform(spec.name, arch.platform))
if arch.os:
- clauses.append(f.arch_os(spec.name, arch.os))
+ clauses.append(f.node_os(spec.name, arch.os))
if arch.target:
- clauses.append(f.arch_target(spec.name, arch.target))
+ clauses.append(f.node_target(spec.name, arch.target))
# variants
for vname, variant in sorted(spec.variants.items()):
@@ -528,13 +530,83 @@ class AspGenerator(object):
if dep.versions.concrete:
self.possible_versions[dep.name].add(dep.version)
+ def _supported_targets(self, compiler, targets):
+ """Get a list of which targets are supported by the compiler.
+
+ Results are ordered most to least recent.
+ """
+ supported = []
+
+ for target in targets:
+ compiler_info = target.compilers.get(compiler.name)
+ if not compiler_info:
+ # if we don't know, we assume it's supported and leave it
+ # to the user to debug
+ supported.append(target)
+ continue
+
+ if not isinstance(compiler_info, list):
+ compiler_info = [compiler_info]
+
+ for info in compiler_info:
+ version = ver(info['versions'])
+ if compiler.version.satisfies(version):
+ supported.append(target)
+
+ return sorted(supported, reverse=True)
+
def arch_defaults(self):
"""Add facts about the default architecture for a package."""
self.h2('Default architecture')
- default_arch = spack.spec.ArchSpec(spack.architecture.sys_type())
- self.fact(fn.arch_platform_default(default_arch.platform))
- self.fact(fn.arch_os_default(default_arch.os))
- self.fact(fn.arch_target_default(default_arch.target))
+ default = spack.spec.ArchSpec(spack.architecture.sys_type())
+ self.fact(fn.node_platform_default(default.platform))
+ self.fact(fn.node_os_default(default.os))
+ self.fact(fn.node_target_default(default.target))
+
+ uarch = default.target.microarchitecture
+
+ self.h2('Target compatibility')
+
+ # listing too many targets can be slow, at least with our current
+ # encoding. To reduce the number of options to consider, only
+ # consider the *best* target that each compiler supports, along
+ # with the family.
+ compatible_targets = [uarch] + uarch.ancestors
+ compilers = self.compilers_for_default_arch()
+
+ # this loop can be used to limit the number of targets
+ # considered. Right now we consider them all, but it seems that
+ # many targets can make things slow.
+ # TODO: investigate this.
+ best_targets = set([uarch.family.name])
+ for compiler in compilers:
+ supported = self._supported_targets(compiler, compatible_targets)
+ if not supported:
+ continue
+
+ for target in supported:
+ best_targets.add(target.name)
+ self.fact(fn.compiler_supports_target(
+ compiler.name, compiler.version, target.name))
+ self.fact(fn.compiler_supports_target(
+ compiler.name, compiler.version, uarch.family.name))
+
+ i = 0
+ for target in compatible_targets:
+ self.fact(fn.target(target.name))
+ self.fact(fn.target_family(target.name, target.family.name))
+ for parent in sorted(target.parents):
+ self.fact(fn.target_parent(target.name, parent.name))
+
+ # prefer best possible targets; weight others poorly so
+ # they're not used unless set explicitly
+ if target.name in best_targets:
+ self.fact(fn.target_weight(target.name, i))
+ i += 1
+ else:
+ self.fact(fn.target_weight(target.name, 100))
+
+ self.out.write("\n")
def virtual_providers(self):
self.h2("Virtual providers")
@@ -556,20 +628,13 @@ class AspGenerator(object):
specs (list): list of Specs to solve
"""
# get list of all possible dependencies
- pkg_names = set(spec.fullname for spec in specs)
-
- possible = set()
self.possible_virtuals = set()
- for name in pkg_names:
- pkg = spack.repo.path.get_pkg_class(name)
- possible.update(
- pkg.possible_dependencies(
- virtuals=self.possible_virtuals,
- deptype=("build", "link", "run")
- )
- )
-
- pkgs = set(possible) | set(pkg_names)
+ possible = spack.package.possible_dependencies(
+ *specs,
+ virtuals=self.possible_virtuals,
+ deptype=("build", "link", "run")
+ )
+ pkgs = set(possible)
# get possible compilers
self.possible_compilers = self.compilers_for_default_arch()
@@ -623,13 +688,13 @@ class ResultParser(object):
self._specs[pkg].architecture = arch
return arch
- def arch_platform(self, pkg, platform):
+ def node_platform(self, pkg, platform):
self._arch(pkg).platform = platform
- def arch_os(self, pkg, os):
+ def node_os(self, pkg, os):
self._arch(pkg).os = os
- def arch_target(self, pkg, target):
+ def node_target(self, pkg, target):
self._arch(pkg).target = target
def variant_value(self, pkg, name, value):
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 6f5b584dfa..9f0c09c701 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -107,40 +107,47 @@ variant_not_default(P, V, X, 0)
#defined variant_single_value/2.
%-----------------------------------------------------------------------------
-% Architecture semantics
+% Platform/OS semantics
%-----------------------------------------------------------------------------
-
-% one platform, os, target per node.
-1 { arch_platform(P, A) : arch_platform(P, A) } 1 :- node(P).
-1 { arch_os(P, A) : arch_os(P, A) } 1 :- node(P).
-1 { arch_target(P, T) : arch_target(P, T) } 1 :- node(P).
+% one platform, os per node
+% TODO: convert these to use optimization, like targets.
+1 { node_platform(P, A) : node_platform(P, A) } 1 :- node(P).
+1 { node_os(P, A) : node_os(P, A) } 1 :- node(P).
% arch fields for pkg P are set if set to anything
-arch_platform_set(P) :- arch_platform_set(P, _).
-arch_os_set(P) :- arch_os_set(P, _).
-arch_target_set(P) :- arch_target_set(P, _).
+node_platform_set(P) :- node_platform_set(P, _).
+node_os_set(P) :- node_os_set(P, _).
+
+% if no platform/os is set, fall back to the defaults
+node_platform(P, A)
+ :- node(P), not node_platform_set(P), node_platform_default(A).
+node_os(P, A) :- node(P), not node_os_set(P), node_os_default(A).
+
+% setting os/platform on a node is a hard constraint
+node_platform(P, A) :- node(P), node_platform_set(P, A).
+node_os(P, A) :- node(P), node_os_set(P, A).
% avoid info warnings (see variants)
-#defined arch_platform_set/2.
-#defined arch_os_set/2.
-#defined arch_target_set/2.
-
-% if architecture value is set, it's the value
-arch_platform(P, A) :- node(P), arch_platform_set(P, A).
-arch_os(P, A) :- node(P), arch_os_set(P, A).
-arch_target(P, A) :- node(P), arch_target_set(P, A).
-
-% if no architecture is set, fall back to the default architecture value.
-arch_platform(P, A) :- node(P), not arch_platform_set(P),
- arch_platform_default(A).
-arch_os(P, A) :- node(P), not arch_os_set(P), arch_os_default(A).
-arch_target(P, A) :- node(P), not arch_target_set(P), arch_target_default(A).
-
-% propagate platform, os, target downwards
-% TODO: handle multiple dependents and arch compatibility
-arch_platform_set(D, A) :- node(D), depends_on(P, D), arch_platform_set(P, A).
-arch_os_set(D, A) :- node(D), depends_on(P, D), arch_os_set(P, A).
-arch_target_set(D, A) :- node(D), depends_on(P, D), arch_target_set(P, A).
+#defined node_platform_set/2.
+#defined node_os_set/2.
+
+%-----------------------------------------------------------------------------
+% Target semantics
+%-----------------------------------------------------------------------------
+% one target per node -- optimization will pick the "best" one
+1 { node_target(P, T) : target(T) } 1 :- node(P).
+
+% can't use targets on node if the compiler for the node doesn't support them
+:- node_target(P, T), not compiler_supports_target(C, V, T),
+ node_compiler(P, C), node_compiler_version(P, C, V).
+
+% if a target is set explicitly, respect it
+node_target(P, T) :- node(P), node_target_set(P, T).
+
+% each node has the weight of its assigned target
+node_target_weight(P, N) :- node(P), node_target(P, T), target_weight(T, N).
+
+#defined node_target_set/2.
%-----------------------------------------------------------------------------
% Compiler semantics
@@ -212,14 +219,21 @@ root(D, 2) :- root(D), node(D).
root(D, 1) :- not root(D), node(D).
% prefer default variants
-#minimize { N*R@5,P,V,X : variant_not_default(P, V, X, N), root(P, R) }.
+#minimize { N*R@10,P,V,X : variant_not_default(P, V, X, N), root(P, R) }.
% pick most preferred virtual providers
-#minimize{ N*R@4,D : provider_weight(D, N), root(P, R) }.
+#minimize{ N*R@9,D : provider_weight(D, N), root(P, R) }.
% prefer more recent versions.
-#minimize{ N@3,P,V : version_weight(P, V, N) }.
+#minimize{ N@8,P,V : version_weight(P, V, N) }.
% compiler preferences
-#maximize{ N@2,P : compiler_match(P, N) }.
-#minimize{ N@1,P : compiler_weight(P, N) }.
+#maximize{ N@7,P : compiler_match(P, N) }.
+#minimize{ N@6,P : compiler_weight(P, N) }.
+
+% fastest target for node
+
+% TODO: if these are slightly different by compiler (e.g., skylake is
+% best, gcc supports skylake and broadweell, clang's best is haswell)
+% things seem to get really slow.
+#minimize{ N@5,P : node_target_weight(P, N) }.
diff --git a/lib/spack/spack/solver/display.lp b/lib/spack/spack/solver/display.lp
index e5be23b55c..e2eae00f79 100644
--- a/lib/spack/spack/solver/display.lp
+++ b/lib/spack/spack/solver/display.lp
@@ -7,8 +7,8 @@
#show depends_on/3.
#show version/2.
#show variant_value/3.
-#show arch_platform/2.
-#show arch_os/2.
-#show arch_target/2.
+#show node_platform/2.
+#show node_os/2.
+#show node_target/2.
#show node_compiler/2.
#show node_compiler_version/3.