Skip to content

Package requirements: support cflags#37180

Closed
scheibelp wants to merge 13 commits intospack:developfrom
scheibelp:bugfix/cflags-pkg-requirements
Closed

Package requirements: support cflags#37180
scheibelp wants to merge 13 commits intospack:developfrom
scheibelp:bugfix/cflags-pkg-requirements

Conversation

@scheibelp
Copy link
Copy Markdown
Member

@scheibelp scheibelp commented Apr 25, 2023

Fixes #37163
Fixes #34241

This addresses a specific problem in a generic way. Essentially compiler flags introduced as possible package constraints were unsatisfiable, since the concretizer had no means to include them in the solution (another good explanation in the issue thread). This PR attempts to resolve the issue generally by allowing the solver to impose anything that is mentioned as a possible constraint (I anticipate that this would mitigate future issues of a similar nature).

Looking at the overall .lp

attr(Name, A1, A2, A3) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3).

...

condition_holds(ID) :-
  condition(ID, _);
  attr(Name, A1) : condition_requirement(ID, Name, A1);

...

impose(ID) :- condition_holds(ID), not do_not_impose(ID).

so we have impose -> attr -> condition_holds -> impose

and generally the cycle is broken when either

  • an attr is defined
  • a condition is triggered

You can see this in action by comparing the facts that are generated by the various methods for assigning cflags=-g:

% spack spec zlib cflags="-g"

literal(0).
literal(0,"root","zlib").
literal(0,"node","zlib").
literal(0,"node_flag_set","zlib","cflags","-g").
literal(0,"node_flag_source","zlib","cflags","zlib").

% set cflags=-g in compilers.yaml

compiler_id(8).
compiler_name(8,"apple-clang").
compiler_version(8,"12.0.0-flags").
compiler_os(8,"catalina").
compiler_target(8,"x86_64").
compiler_flag(8,"cflags","-g").

% set zlib:require:cflags="-g" in packages.yaml, before this PR
% this fails

requirement_group("zlib",0).
requirement_policy("zlib",0,"one_of").
condition(7,"None").
condition_requirement(7,"node","zlib").
condition_requirement(7,"node_flag","zlib","cflags","-g").
condition_requirement(7,"node_flag_source","zlib","cflags","zlib").
imposed_constraint(7,"node_flag_set","zlib","cflags","-g").
imposed_constraint(7,"node_flag_source","zlib","cflags","zlib").
requirement_group_member(7,"zlib",0).
requirement_has_weight(7,0).

at its core, this allows another mechanism for breaking the cycle by adding a choice rule for impose().

@spackbot-app spackbot-app bot added core PR affects Spack core functionality tests General test capability(ies) labels Apr 25, 2023
@scheibelp scheibelp changed the title [WIP] Package requirements: support cflags Package requirements: support cflags Apr 25, 2023
@alalazo alalazo self-assigned this Apr 28, 2023
@alalazo
Copy link
Copy Markdown
Member

alalazo commented May 2, 2023

@spackbot run pipeline

@spackbot-app
Copy link
Copy Markdown

spackbot-app bot commented May 2, 2023

I've started that pipeline for you!

@alalazo alalazo added this to the v0.20.0 milestone May 3, 2023
Comment on lines +2079 to +2082
for spec in specs:
if not spec.virtual:
for provided in spec.package_class.provided:
self.possible_virtuals.add(provided.name)
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll give a thorough review tomorrow, but curious why this was needed.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When I introduced a choice rule for impose, it gave the concretizer the power to impose selective attributes about nodes without them being part of the dag, which was nonsensical, so I introduced

error(1, "Unexpected attribute {0}/{1}", Package, X) :- attr(X, Package), not attr("virtual_node", Package), not external(Package), not attr("node", Package).

i.e. things must be part of the dag for anny attribute to be set on them. Interestingly, this led to the discovery that in some circumstances there are "entities" in our DAG which are not nodes or virtual nodes but still have attributes set on them. I think specifically it is providers that are specified as root specs (but you can know for sure by removing this, which will cause test faulures), so logic like this was added to ensure that everything that we set attrs on is in fact a node or virtual node (or external).

@alalazo
Copy link
Copy Markdown
Member

alalazo commented May 5, 2023

The PR seem to slow-down by 10% the solver, at least on the benchmark below. I'll double check whether this is due to the choice rules or errors (more likely), or both.

Benchmark data:

radiuss-impose.csv
radiuss.csv
radiuss.txt

radiuss

Total time and speed-up
Spec solved Total time [develop, secs.] Total time [PR, secs.] Speedup [%]
aluminum 15.0649 16.6028 -10.2085
ascent 31.9149 33.4457 -4.79654
axom 32.0465 33.2385 -3.71942
blt 14.4723 15.316 -5.82961
caliper 15.1162 16.9095 -11.8634
care 16.2227 18.4255 -13.5785
chai 15.2874 17.423 -13.97
conduit 15.7304 17.5429 -11.5224
dihydrogen 16.4319 17.7396 -7.95787
flux-core 15.2664 16.8225 -10.193
flux-sched 15.3939 16.7809 -9.00981
glvis 30.2646 32.2964 -6.71346
hydrogen 16.1125 17.2174 -6.85757
hypre 16.8599 18.596 -10.2971
lbann 32.2317 35.4613 -10.0198
lvarray 20.717 23.1621 -11.8021
mfem 28.1074 30.6445 -9.0265
py-hatchet 19.6084 21.6834 -10.5821
py-maestrowf 15.8156 17.1211 -8.25471
py-merlin 17.5331 19.246 -9.76937
py-shroud 14.2045 15.7292 -10.7343
raja 14.6756 16.9222 -15.3084
samrai 14.5209 16.3314 -12.4676
scr 15.8858 17.4389 -9.77664
sundials 25.0954 28.3312 -12.8939
umpire 14.4404 16.6018 -14.968
visit 31.1969 33.4768 -7.30807
xbraid 14.9129 15.9965 -7.26601
zfp 14.2441 15.9826 -12.2053

@alalazo
Copy link
Copy Markdown
Member

alalazo commented May 5, 2023

After a few experiments, it seems that the main cause of slow-down are the choice rules.

With more specific choice rules:

diff --git a/lib/spack/spack/solver/concretize.lp b/lib/spack/spack/solver/concretize.lp
index c38b67da62..836147c511 100644
--- a/lib/spack/spack/solver/concretize.lp
+++ b/lib/spack/spack/solver/concretize.lp
@@ -193,18 +193,15 @@ attr(Name, A1, A2)         :- impose(ID), imposed_constraint(ID, Name, A1, A2).
 attr(Name, A1, A2, A3)     :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3).
 attr(Name, A1, A2, A3, A4) :- impose(ID), imposed_constraint(ID, Name, A1, A2, A3, A4).
 
-% If something is mentioned as a possible constraint, allow for the possibility
-% of imposing it
-{impose(ID)} :- imposed_constraint(ID, Name, A1).
-{impose(ID)} :- imposed_constraint(ID, Name, A1, A2).
-{impose(ID)} :- imposed_constraint(ID, Name, A1, A2, A3).
-{impose(ID)} :- imposed_constraint(ID, Name, A1, A2, A3, A4).
-
-% Packages can only set attrs if they are part of the DAG
-error(1, "Unexpected attribute {0}/{1}", Package, X) :- attr(X, Package), not attr("virtual_node", Package), not external(Package), not attr("node", Package).
-error(1, "Unexpected attribute {0}/{1}: {2}", Package, X1, X2) :- attr(X1, Package, X2), not attr("virtual_node", Package), not external(Package), not attr("node", Package).
-error(1, "Unexpected attribute {0}/{1}: {2}, {3}", Package, X1, X2, X3) :- attr(X1, Package, X2, X3), not attr("virtual_node", Package), not external(Package), not attr("node", Package).
-error(1, "Unexpected attribute {0}/{1}: {2}, {3}, {4}", Package, X1, X2, X3, X4) :- attr(X1, Package, X2, X3, X4), not attr("virtual_node", Package), not external(Package), not attr("node", Package).
+{ attr("node_flag", A1, A2, A3) } :-
+  requirement_group_member(Y, Package, _),
+  activate_requirement_rules(Package),
+  condition_requirement(Y,"node_flag", A1, A2, A3).
+
+{ attr("node_flag_source", A1, A2, A3) } :-
+  requirement_group_member(Y, Package, _),
+  activate_requirement_rules(Package),
+  condition_requirement(Y,"node_flag_source", A1, A2, A3).
 
 virtual(Virtual) :- possible_provider(Package, Virtual).
 attr("virtual_node", Virtual) :- provider(Package, Virtual).

I get a smaller impact (2-5%) on performance:

radiuss-impose3.csv
radiuss.csv
radiuss.txt

radiuss

Total time and speed-up
Spec solved Total time [develop, secs.] Total time [PR, secs.] Speedup [%]
aluminum 15.0649 15.7482 -4.53549
ascent 31.9149 32.9653 -3.29142
axom 32.0465 32.3511 -0.950554
blt 14.4723 15.0964 -4.31283
caliper 15.1162 16.1584 -6.89405
care 16.2227 16.466 -1.49966
chai 15.2874 15.8492 -3.67483
conduit 15.7304 16.6268 -5.69896
dihydrogen 16.4319 16.8438 -2.50636
flux-core 15.2664 15.8176 -3.61062
flux-sched 15.3939 15.8823 -3.17297
glvis 30.2646 31.4113 -3.78878
hydrogen 16.1125 16.3474 -1.45789
hypre 16.8599 17.3858 -3.1189
lbann 32.2317 32.809 -1.79105
lvarray 20.717 21.3319 -2.96797
mfem 28.1074 29.4035 -4.61149
py-hatchet 19.6084 20.2004 -3.01888
py-maestrowf 15.8156 16.2221 -2.57001
py-merlin 17.5331 18.3603 -4.7178
py-shroud 14.2045 14.8497 -4.54247
raja 14.6756 15.0973 -2.87313
samrai 14.5209 15.3308 -5.57753
scr 15.8858 16.4901 -3.80382
sundials 25.0954 26.2121 -4.45001
umpire 14.4404 14.9514 -3.53894
visit 31.1969 32.5137 -4.22116
xbraid 14.9129 15.2802 -2.46262
zfp 14.2441 14.9741 -5.12457

Copy link
Copy Markdown
Member

@alalazo alalazo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the performance benchmarks above and a proposed improvement. I have also a question on self.possible_virtuals.

@scheibelp
Copy link
Copy Markdown
Member Author

(closing as these issues are now articulated in #39880)

@scheibelp scheibelp closed this Oct 20, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core PR affects Spack core functionality tests General test capability(ies)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Package requirements: failure with compiler flags require does not work with cflags=

2 participants