Compare commits
1 Commits
hs/fix/sho
...
minimal-co
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3985b307a1 |
@@ -15,22 +15,38 @@ concretizer:
|
|||||||
# as possible, rather than building. If `false`, we'll always give you a fresh
|
# as possible, rather than building. If `false`, we'll always give you a fresh
|
||||||
# concretization.
|
# concretization.
|
||||||
reuse: true
|
reuse: true
|
||||||
|
|
||||||
|
# If `true`, Spack will consider minimizing builds its *topmost* priority.
|
||||||
|
# Note that this can result in weird package configurations. In particular,
|
||||||
|
# Spack will disable variants and might downgrade versions to avoid building
|
||||||
|
# new packages for an install. By default, Spack respects defaults from
|
||||||
|
# packages and preferences *before* minimizing the number of builds.
|
||||||
|
#
|
||||||
|
# Example for intuition: `cmake` can optionally build without openssl, but
|
||||||
|
# it's enabled by default because many builds use that functionality. Using
|
||||||
|
# `minimal: true` will build `cmake~openssl` unless the user asks for
|
||||||
|
# `cmake+openssl` explicitly.
|
||||||
|
minimal: false
|
||||||
|
|
||||||
# Options that tune which targets are considered for concretization. The
|
# Options that tune which targets are considered for concretization. The
|
||||||
# concretization process is very sensitive to the number targets, and the time
|
# concretization process is very sensitive to the number targets, and the time
|
||||||
# needed to reach a solution increases noticeably with the number of targets
|
# needed to reach a solution increases noticeably with the number of targets
|
||||||
# considered.
|
# considered.
|
||||||
targets:
|
targets:
|
||||||
|
|
||||||
# Determine whether we want to target specific or generic microarchitectures.
|
# Determine whether we want to target specific or generic microarchitectures.
|
||||||
# An example of the first kind might be for instance "skylake" or "bulldozer",
|
# An example of the first kind might be for instance "skylake" or "bulldozer",
|
||||||
# while generic microarchitectures are for instance "aarch64" or "x86_64_v4".
|
# while generic microarchitectures are for instance "aarch64" or "x86_64_v4".
|
||||||
granularity: microarchitectures
|
granularity: microarchitectures
|
||||||
|
|
||||||
# If "false" allow targets that are incompatible with the current host (for
|
# If "false" allow targets that are incompatible with the current host (for
|
||||||
# instance concretize with target "icelake" while running on "haswell").
|
# instance concretize with target "icelake" while running on "haswell").
|
||||||
# If "true" only allow targets that are compatible with the host.
|
# If "true" only allow targets that are compatible with the host.
|
||||||
host_compatible: true
|
host_compatible: true
|
||||||
|
|
||||||
# When "true" concretize root specs of environments together, so that each unique
|
# When "true" concretize root specs of environments together, so that each unique
|
||||||
# package in an environment corresponds to one concrete spec. This ensures
|
# package in an environment corresponds to one concrete spec. This ensures
|
||||||
# environments can always be activated. When "false" perform concretization separately
|
# environments can always be activated. When "false" perform concretization separately
|
||||||
# on each root spec, allowing different versions and variants of the same package in
|
# on each root spec, allowing different versions and variants of the same package in
|
||||||
# an environment.
|
# an environment.
|
||||||
unify: false
|
unify: false
|
||||||
|
@@ -380,6 +380,11 @@ def add_concretizer_args(subparser):
|
|||||||
const=False, default=None,
|
const=False, default=None,
|
||||||
help='do not reuse installed deps; build newest configuration'
|
help='do not reuse installed deps; build newest configuration'
|
||||||
)
|
)
|
||||||
|
subgroup.add_argument(
|
||||||
|
'--minimal', action=ConfigSetAction, dest="concretizer:minimal",
|
||||||
|
const=True, default=None,
|
||||||
|
help='minimize builds (disables default variants, may choose older versions)'
|
||||||
|
)
|
||||||
subgroup.add_argument(
|
subgroup.add_argument(
|
||||||
'--reuse', action=ConfigSetAction, dest="concretizer:reuse",
|
'--reuse', action=ConfigSetAction, dest="concretizer:reuse",
|
||||||
const=True, default=None,
|
const=True, default=None,
|
||||||
|
@@ -15,6 +15,7 @@
|
|||||||
'additionalProperties': False,
|
'additionalProperties': False,
|
||||||
'properties': {
|
'properties': {
|
||||||
'reuse': {'type': 'boolean'},
|
'reuse': {'type': 'boolean'},
|
||||||
|
'minimal': {'type': 'boolean'},
|
||||||
'targets': {
|
'targets': {
|
||||||
'type': 'object',
|
'type': 'object',
|
||||||
'properties': {
|
'properties': {
|
||||||
|
@@ -654,7 +654,7 @@ def stringify(x):
|
|||||||
class SpackSolverSetup(object):
|
class SpackSolverSetup(object):
|
||||||
"""Class to set up and run a Spack concretization solve."""
|
"""Class to set up and run a Spack concretization solve."""
|
||||||
|
|
||||||
def __init__(self, reuse=False, tests=False):
|
def __init__(self, reuse=None, minimal=None, tests=False):
|
||||||
self.gen = None # set by setup()
|
self.gen = None # set by setup()
|
||||||
|
|
||||||
self.declared_versions = {}
|
self.declared_versions = {}
|
||||||
@@ -679,10 +679,11 @@ def __init__(self, reuse=False, tests=False):
|
|||||||
# Caches to optimize the setup phase of the solver
|
# Caches to optimize the setup phase of the solver
|
||||||
self.target_specs_cache = None
|
self.target_specs_cache = None
|
||||||
|
|
||||||
# whether to add installed/binary hashes to the solve
|
# Solver paramters that affect setup -- see Solver documentation
|
||||||
self.reuse = reuse
|
self.reuse = spack.config.get(
|
||||||
|
"concretizer:reuse", False) if reuse is None else reuse
|
||||||
# whether to add installed/binary hashes to the solve
|
self.minimal = spack.config.get(
|
||||||
|
"concretizer:minimal", False) if minimal is None else minimal
|
||||||
self.tests = tests
|
self.tests = tests
|
||||||
|
|
||||||
def pkg_version_rules(self, pkg):
|
def pkg_version_rules(self, pkg):
|
||||||
@@ -827,7 +828,7 @@ def package_compiler_defaults(self, pkg):
|
|||||||
pkg.name, cspec.name, cspec.version, -i * 100
|
pkg.name, cspec.name, cspec.version, -i * 100
|
||||||
))
|
))
|
||||||
|
|
||||||
def pkg_rules(self, pkg, tests):
|
def pkg_rules(self, pkg):
|
||||||
pkg = packagize(pkg)
|
pkg = packagize(pkg)
|
||||||
|
|
||||||
# versions
|
# versions
|
||||||
@@ -1809,10 +1810,14 @@ def setup(self, driver, specs):
|
|||||||
self.gen.h1("Concrete input spec definitions")
|
self.gen.h1("Concrete input spec definitions")
|
||||||
self.define_concrete_input_specs(specs, possible)
|
self.define_concrete_input_specs(specs, possible)
|
||||||
|
|
||||||
|
self.gen.h1("Concretizer options")
|
||||||
|
if self.reuse:
|
||||||
|
self.gen.fact(fn.optimize_for_reuse())
|
||||||
|
if self.minimal:
|
||||||
|
self.gen.fact(fn.minimal_installs())
|
||||||
|
|
||||||
if self.reuse:
|
if self.reuse:
|
||||||
self.gen.h1("Installed packages")
|
self.gen.h1("Installed packages")
|
||||||
self.gen.fact(fn.optimize_for_reuse())
|
|
||||||
self.gen.newline()
|
|
||||||
self.define_installed_packages(specs, possible)
|
self.define_installed_packages(specs, possible)
|
||||||
|
|
||||||
self.gen.h1('General Constraints')
|
self.gen.h1('General Constraints')
|
||||||
@@ -1833,7 +1838,7 @@ def setup(self, driver, specs):
|
|||||||
self.gen.h1('Package Constraints')
|
self.gen.h1('Package Constraints')
|
||||||
for pkg in sorted(pkgs):
|
for pkg in sorted(pkgs):
|
||||||
self.gen.h2('Package rules: %s' % pkg)
|
self.gen.h2('Package rules: %s' % pkg)
|
||||||
self.pkg_rules(pkg, tests=self.tests)
|
self.pkg_rules(pkg)
|
||||||
self.gen.h2('Package preferences: %s' % pkg)
|
self.gen.h2('Package preferences: %s' % pkg)
|
||||||
self.preferred_variants(pkg)
|
self.preferred_variants(pkg)
|
||||||
self.preferred_targets(pkg)
|
self.preferred_targets(pkg)
|
||||||
@@ -2191,6 +2196,10 @@ class Solver(object):
|
|||||||
``reuse (bool)``
|
``reuse (bool)``
|
||||||
Whether to try to reuse existing installs/binaries
|
Whether to try to reuse existing installs/binaries
|
||||||
|
|
||||||
|
``minimal (bool)``
|
||||||
|
If ``True`` make minimizing nodes the top priority, even higher
|
||||||
|
than defaults from packages and preferences.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.driver = PyclingoDriver()
|
self.driver = PyclingoDriver()
|
||||||
@@ -2198,6 +2207,7 @@ def __init__(self):
|
|||||||
# These properties are settable via spack configuration, and overridable
|
# These properties are settable via spack configuration, and overridable
|
||||||
# by setting them directly as properties.
|
# by setting them directly as properties.
|
||||||
self.reuse = spack.config.get("concretizer:reuse", False)
|
self.reuse = spack.config.get("concretizer:reuse", False)
|
||||||
|
self.minimal = spack.config.get("concretizer:minimal", False)
|
||||||
|
|
||||||
def solve(
|
def solve(
|
||||||
self,
|
self,
|
||||||
@@ -2228,7 +2238,7 @@ def solve(
|
|||||||
continue
|
continue
|
||||||
spack.spec.Spec.ensure_valid_variants(s)
|
spack.spec.Spec.ensure_valid_variants(s)
|
||||||
|
|
||||||
setup = SpackSolverSetup(reuse=self.reuse, tests=tests)
|
setup = SpackSolverSetup(reuse=self.reuse, minimal=self.minimal, tests=tests)
|
||||||
return self.driver.solve(
|
return self.driver.solve(
|
||||||
setup,
|
setup,
|
||||||
specs,
|
specs,
|
||||||
|
@@ -962,26 +962,36 @@ impose(Hash) :- hash(Package, Hash).
|
|||||||
% if we haven't selected a hash for a package, we'll be building it
|
% if we haven't selected a hash for a package, we'll be building it
|
||||||
build(Package) :- not hash(Package, _), node(Package).
|
build(Package) :- not hash(Package, _), node(Package).
|
||||||
|
|
||||||
% Minimizing builds is tricky. We want a minimizing criterion
|
% Minimizing builds is tricky. We want a minimizing criterion because we want to reuse
|
||||||
|
% what is avaialble, but we also want things that are built to stick to *default
|
||||||
% because we want to reuse what is avaialble, but
|
% preferences* from the package and from the user. We therefore treat built specs
|
||||||
% we also want things that are built to stick to *default preferences* from
|
% differently and apply a different set of optimization criteria to them. Spack's first
|
||||||
% the package and from the user. We therefore treat built specs differently and apply
|
% priority is to reuse what it can, but if it builds something, the built specs will
|
||||||
% a different set of optimization criteria to them. Spack's *first* priority is to
|
% respect defaults and preferences.
|
||||||
% reuse what it *can*, but if it builds something, the built specs will respect
|
%
|
||||||
% defaults and preferences. This is implemented by bumping the priority of optimization
|
% This is implemented by bumping the priority of optimization criteria for built specs
|
||||||
% criteria for built specs -- so that they take precedence over the otherwise
|
% -- so that they take precedence over the otherwise topmost-priority criterion to reuse
|
||||||
% topmost-priority criterion to reuse what is installed.
|
% what is installed.
|
||||||
|
%
|
||||||
|
% If the user explicitly asks for *minimal* installs, we don't differentiate between
|
||||||
|
% built and reused specs - the top priority is just minimizing builds.
|
||||||
%
|
%
|
||||||
% The priority ranges are:
|
% The priority ranges are:
|
||||||
% 200+ Shifted priorities for build nodes; correspond to priorities 0 - 99.
|
% 200+ Shifted priorities for build nodes; correspond to priorities 0 - 99.
|
||||||
% 100 - 199 Unshifted priorities. Currently only includes minimizing #builds.
|
% 100 - 199 Unshifted priorities. Currently only includes minimizing #builds.
|
||||||
% 0 - 99 Priorities for non-built nodes.
|
% 0 - 99 Priorities for non-built nodes.
|
||||||
build_priority(Package, 200) :- build(Package), node(Package), optimize_for_reuse().
|
build_priority(Package, 200) :- node(Package), build(Package), optimize_for_reuse(),
|
||||||
build_priority(Package, 0) :- not build(Package), node(Package), optimize_for_reuse().
|
not minimal_installs().
|
||||||
|
build_priority(Package, 0) :- node(Package), not build(Package), optimize_for_reuse().
|
||||||
|
|
||||||
% don't adjust build priorities if reuse is not enabled
|
% Don't adjust build priorities if reusing, or if doing minimal installs
|
||||||
|
% With minimal, minimizing builds is the TOP priority
|
||||||
build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
|
build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
|
||||||
|
build_priority(Package, 0) :- node(Package), minimal_installs().
|
||||||
|
|
||||||
|
% Minimize builds with both --reuse and with --minimal
|
||||||
|
minimize_builds() :- optimize_for_reuse().
|
||||||
|
minimize_builds() :- minimal_installs().
|
||||||
|
|
||||||
% don't assign versions from installed packages unless reuse is enabled
|
% don't assign versions from installed packages unless reuse is enabled
|
||||||
% NOTE: that "installed" means the declared version was only included because
|
% NOTE: that "installed" means the declared version was only included because
|
||||||
@@ -1000,6 +1010,7 @@ build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
|
|||||||
not optimize_for_reuse().
|
not optimize_for_reuse().
|
||||||
|
|
||||||
#defined installed_hash/2.
|
#defined installed_hash/2.
|
||||||
|
#defined minimal_installs/0.
|
||||||
|
|
||||||
%-----------------------------------------------------------------
|
%-----------------------------------------------------------------
|
||||||
% Optimization to avoid errors
|
% Optimization to avoid errors
|
||||||
@@ -1029,7 +1040,7 @@ build_priority(Package, 0) :- node(Package), not optimize_for_reuse().
|
|||||||
% Try hard to reuse installed packages (i.e., minimize the number built)
|
% Try hard to reuse installed packages (i.e., minimize the number built)
|
||||||
opt_criterion(100, "number of packages to build (vs. reuse)").
|
opt_criterion(100, "number of packages to build (vs. reuse)").
|
||||||
#minimize { 0@100: #true }.
|
#minimize { 0@100: #true }.
|
||||||
#minimize { 1@100,Package : build(Package), optimize_for_reuse() }.
|
#minimize { 1@100,Package : build(Package), minimize_builds() }.
|
||||||
#defined optimize_for_reuse/0.
|
#defined optimize_for_reuse/0.
|
||||||
|
|
||||||
% Minimize the number of deprecated versions being used
|
% Minimize the number of deprecated versions being used
|
||||||
|
@@ -120,11 +120,19 @@ def test_concretizer_arguments(mutable_config, mock_packages):
|
|||||||
spec = spack.main.SpackCommand("spec")
|
spec = spack.main.SpackCommand("spec")
|
||||||
|
|
||||||
assert spack.config.get("concretizer:reuse", None) is None
|
assert spack.config.get("concretizer:reuse", None) is None
|
||||||
|
assert spack.config.get("concretizer:minimal", None) is None
|
||||||
|
|
||||||
spec("--reuse", "zlib")
|
spec("--reuse", "zlib")
|
||||||
|
|
||||||
assert spack.config.get("concretizer:reuse", None) is True
|
assert spack.config.get("concretizer:reuse", None) is True
|
||||||
|
assert spack.config.get("concretizer:minimal", None) is None
|
||||||
|
|
||||||
spec("--fresh", "zlib")
|
spec("--fresh", "zlib")
|
||||||
|
|
||||||
assert spack.config.get("concretizer:reuse", None) is False
|
assert spack.config.get("concretizer:reuse", None) is False
|
||||||
|
assert spack.config.get("concretizer:minimal", None) is None
|
||||||
|
|
||||||
|
spec("--minimal", "zlib")
|
||||||
|
|
||||||
|
assert spack.config.get("concretizer:reuse", None) is False
|
||||||
|
assert spack.config.get("concretizer:minimal", None) is True
|
||||||
|
Reference in New Issue
Block a user