-
Notifications
You must be signed in to change notification settings - Fork 2.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Concretizer: put build->run deps in parent unification set (fixes #46034) #46106
base: develop
Are you sure you want to change the base?
Concretizer: put build->run deps in parent unification set (fixes #46034) #46106
Conversation
1e9f035
to
4ef6ce5
Compare
BTW. the fail in After applying this, we end up with only two build-type versions of diff --git a/var/spack/repos/duplicates.test/packages/py-numpy/package.py b/var/spack/repos/duplicates.test/packages/py-numpy/package.py
index 42cb2aecc7..cfccb64b7e 100644
--- a/var/spack/repos/duplicates.test/packages/py-numpy/package.py
+++ b/var/spack/repos/duplicates.test/packages/py-numpy/package.py
@@ -16,5 +16,5 @@ class PyNumpy(Package):
version("1.25.0", md5="0123456789abcdef0123456789abcdef")
extends("python")
- depends_on("py-setuptools@=59", type=("build", "run"))
+ depends_on("py-setuptools@=59", type=("build"))
depends_on("gmake@4.1", type="build") I think we should also have a inverse test (aka make sure the concretization fails) on the previous state. |
@elenimath suggests this restructuring of the unification sets in order to:
diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 18c82474c9..923c195f35 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -95,12 +95,19 @@ unify(SetID, PackageName) :- unification_set(SetID, node(_, PackageName)).
unification_set("root", PackageNode) :- attr("root", PackageNode).
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type != "build", unification_set(SetID, ParentNode).
-unification_set(("build", node(X, Child)), node(X, Child))
+unification_set(("build", ParentNode), node(X, Child))
:- attr("depends_on", ParentNode, node(X, Child), Type),
Type == "build",
multiple_unification_sets(Child),
unification_set(SetID, ParentNode).
+unification_set(("build", ParentNode), node(X, Child))
+ :- attr("depends_on", ParentNode, NonDupeNode, "build"),
+ not multiple_unification_sets(NonDupeNode),
+ attr("depends_on", NonDupeNode, node(X, Child), "run"),
+ multiple_unification_sets(Child),
+ unification_set(_, ParentNode).
+
unification_set("generic_build", node(X, Child))
:- attr("depends_on", ParentNode, node(X, Child), Type),
Type == "build", ⇒ that looks like the complete solution to me (but I will stop spamming NOW… and wait for comments :) ). |
Brave to take on this concretizer stuff ;) @alalazo will take a look |
@muffgaga I was looking at the issue, and I think this is what I would apply to diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 18c82474c9..51dbba68c8 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -95,7 +95,7 @@ unify(SetID, PackageName) :- unification_set(SetID, node(_, PackageName)).
unification_set("root", PackageNode) :- attr("root", PackageNode).
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type != "build", unification_set(SetID, ParentNode).
-unification_set(("build", node(X, Child)), node(X, Child))
+unification_set(("build", ParentNode), node(X, Child))
:- attr("depends_on", ParentNode, node(X, Child), Type),
Type == "build",
multiple_unification_sets(Child),
There are two tests failing locally for me, I'll try to check them. As you said in #46106 (comment) I think we should have two tests.
|
@muffgaga diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index 18c82474c9..d0ad292beb 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -95,10 +95,9 @@ unify(SetID, PackageName) :- unification_set(SetID, node(_, PackageName)).
unification_set("root", PackageNode) :- attr("root", PackageNode).
unification_set(SetID, ChildNode) :- attr("depends_on", ParentNode, ChildNode, Type), Type != "build", unification_set(SetID, ParentNode).
-unification_set(("build", node(X, Child)), node(X, Child))
+unification_set(("build", ParentNode), node(X, Child))
:- attr("depends_on", ParentNode, node(X, Child), Type),
Type == "build",
- multiple_unification_sets(Child),
unification_set(SetID, ParentNode).
unification_set("generic_build", node(X, Child))
Rationale is:
|
This diff instead: diff --git a/var/spack/repos/duplicates.test/packages/py-numpy/package.py b/var/spack/repos/duplicates.test/packages/py-numpy/package.py
index 42cb2aecc7..e0ca7dfa32 100644
--- a/var/spack/repos/duplicates.test/packages/py-numpy/package.py
+++ b/var/spack/repos/duplicates.test/packages/py-numpy/package.py
@@ -16,5 +16,5 @@ class PyNumpy(Package):
version("1.25.0", md5="0123456789abcdef0123456789abcdef")
extends("python")
- depends_on("py-setuptools@=59", type=("build", "run"))
+ depends_on("py-setuptools@=59", type="build")
depends_on("gmake@4.1", type="build")
diff --git a/var/spack/repos/duplicates.test/packages/py-shapely/package.py b/var/spack/repos/duplicates.test/packages/py-shapely/package.py
index 091f8c9938..f5809d3341 100644
--- a/var/spack/repos/duplicates.test/packages/py-shapely/package.py
+++ b/var/spack/repos/duplicates.test/packages/py-shapely/package.py
@@ -15,4 +15,4 @@ class PyShapely(Package):
extends("python")
depends_on("py-numpy", type=("build", "link", "run"))
- depends_on("py-setuptools@=60", type="build")
+ depends_on("py-setuptools@=60", type=("build", "run"))
should make the current tests pass. Then we'd just need a test for the case that should fail. |
@alalazo Thanks for looking into this. I'm currently creating another test that checks some "build-tool with its own build deps" case, and I'm not yet sure that everything works there (we don't catch it in the tests, because |
@alalazo about #46106 (comment), I just assumed that smaller unification sets were better performance-wise, but I'm not sure what the actual impact would be :) |
I did a quick @alalazo's nice-and-clean patch:
@elenimath yours :P
|
4434880
to
0c22d87
Compare
0c22d87
to
f55a9af
Compare
Updated merge branch:
|
Looks good, thanks. I'll do some performance benchmark asap, and post it. |
I added another test (to cover "chains" of build tools) that looks like there's a problem with "strategy: full". The test should cover this case here:
But in I added another test (to cover "chains" of build tools) that shows that there's a problem with "strategy: full". The test should cover this case here:
But in
⇒ i.e.
⇒ I think this is an unrelated issue. |
ddecbee
to
9ac60b3
Compare
I removed the "full"-strategy related things from this PR as it is an unrelated issue → @elenimath did a deeper investigation and provided a fresh PR #46169 that covers this separate issue (including the initially failing test and maybe also a fix :) ). |
I just benchmarked on:
radiuss-pr.csv Using unification sets as "build environments" per node comes with a significant performance hit. I'll check later the patch in #46106 (comment), but it seems to me that this one is overly specific to this case (e.g. why only run dependencies and not link dependencies?). I'll try to think how to optimize this use case 🤔 |
true, it should be |
(
Some single
|
I think it was sensible to leave out type=link. Link deps roughly correspond to local search paths or no search at all, run deps have their global search But of course no reason to not be more restrictive if that improves performance... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm currently looking at performance vs. correctness.
I think the most correct change is the one in #46106 (comment) but it's really slow (due to an explosion of the rules for unification sets).
I'm fine with the heuristic in #46106 (comment). The limitation there is that it doesn't account for transitive dependencies of NonDupeNode
in the link/run subdag. It's also slower than develop
due to the same reason as above, but at a lower scale.
TL;DR I'm looking for some alternative heuristic to avoid slowing down the solve. If we can't find it, I'm fine with #46106 (comment). The request for change is for the comment on the test. Can you double check it?
9ac60b3
to
a87fca1
Compare
…fixes spack#46034) * Each parent gets its own "build environment" where the build deps are unified. * Things that don't allow multiple nodes are also thrown into the "generic_build" unification In spack#46034, a package X build-depends on a `build-tools`-tagged package, e.g., `py-setuptools`, as well as another package Y that itself depends (build+run) on the same `build-tools` tagged package. In this case, the concretizer puts the possibly two versions of the build tool into separate unification sets, but the run-type dependency requires the build environment of X to have both versions in its environment — which is illegal. With this fix, the concretizer puts the two build tool nodes into a new common unification set if there is a build→run-type dependency chain on the build tool ⇒ spack now reports the expected error about not being able to find a common concretization of the build tool. Change-Id: I99257b225602c21d4f270fe16e68c1f8bd4b1eba
This introduces `-fixed` packages for py-shapely and py-floating which depend on a `-fixed` py-numpy that does NOT run-depend on py-setuptools. If we allow run deps of build deps, it causes the tool to appear multiple times in the build environment ⇒ fail. Change-Id: I1ef1fa0b8636c23626c7e2ea521d3b5438f97d0a
This introduces a regression test to ensure that the concretizer fails when trying to solve a spec where we have a build tool in two versions and the "lower" (in the DAG) version being also a run-dependency. If this would be allowed, we could end up having multiple paths to different tool versions/variants in the build env. Change-Id: I050efc9471d89580f5546a1c56ab419891bcc792
a87fca1
to
57e563d
Compare
In #46034, a package X build-depends on a
build-tools
-tagged package, e.g.,py-setuptools
, as well as another package Y that itself depends (build+run) on the samebuild-tools
tagged package. In this case, the concretizer puts the possibly two versions of the build tool into separate unification sets, but the run-type dependency requires thebuild environment of X to have both versions in its environment — which is illegal.
With this fix, the concretizer puts the two build tool nodes into a new common unification set if there is a build→run-type dependency chain on the build tool ⇒ spack now reports the expected error about not being able to find a common concretization of the build tool.