Add intel-oneapi-runtime, allow injecting virtual dependencies#42062
Add intel-oneapi-runtime, allow injecting virtual dependencies#42062tgamblin merged 17 commits intospack:developfrom
intel-oneapi-runtime, allow injecting virtual dependencies#42062Conversation
|
@byrnHDF can you review this PR? This PR modifies the following package(s), for which you are listed as a maintainer:
|
579d704 to
e026365
Compare
e026365 to
3ad227e
Compare
3ad227e to
661f908
Compare
|
First benchmark as of 661f908
radiuss.develop.csv Adding more rules to the runtimes impacts the solve time |
|
On the other hand, with 661f908 we have: spack:
specs:
- hdf5%oneapi+fortran~mpi
packages:
cmake:
require: "%gcc"
view: true
concretizer:
unify: trueNot that in the graph we introduced |
661f908 to
eef4c70
Compare
intel-oneapi-runtime and language directive
|
@spackbot run pipeline |
|
I've started that pipeline for you! |
|
@spackbot run pipeline |
The intel-oneapi-runtime depends on gcc-runtime at link time. This dependency can be used later to dynamically select which GCC to use with the %oneapi compiler. intel-oneapi-runtime provides ifort for packages that need fortran
Also: provides sycl, add libiomp5 to the list of libraries
For now maintain a CompilerSpec, since it allows to avoid a double conversion from compiler name to pkg name and vice-versa
9f1ce19 to
4511679
Compare
intel-oneapi-runtime and language directiveintel-oneapi-runtime, allow injecting virtual dependencies
tgamblin
left a comment
There was a problem hiding this comment.
@alalazo I'm merging this as it is far enough along that I think we can merge without hurting anything, and it can be improved once compilers are full packages.
I am still not sure that the interface is 100% yet. Specifically, so we don't forget:
- The deptype of a
depends_on()on a language either shouldn't matter or should just be default. The deptype(s) is (are) entirely up to the compiler package... not the caller, so I don't see any point in forcing an arbitrary convention. Omitting is better. pkg("*").depends_on()shouldn't take a language parameter and we should not make languages special. They're just virtuals like any other... all we're adding is a means for dependencies to inject additional dependencies on their dependents. There is some fanciness I think we will need to do in solver setup to enable this but we should not force callers to know these special cases -- it should just work.- I think likewise we shouldn't need to special case languages in the solve, at least not after compilers are proper dependencies. That can change later, too.
More comments/details below, but this is looking better and is moving along!
|
|
||
| """ | ||
| if spack.spec.Spec(spec).name in SUPPORTED_LANGUAGES: | ||
| assert type == "build", "languages must be of 'build' type" |
There was a problem hiding this comment.
Why is this needed? It's not really a build dependency; it's a build dependency on the compiler and (maybe) a link dependency on the runtime, depending on what the compiler decides to do.
Languages should just omit the deptype. In practice, it doesn't matter b/c it's determined by the compiler's package (and some may not need a runtime). The caller of depends_on should not have to do anything based on how the language is implemented. they should just say they depend on it.
There was a problem hiding this comment.
Why is this needed? It's not really a build dependency; it's a build dependency on the compiler and (maybe) a link dependency on the runtime, depending on what the compiler decides to do.
Depending on a language just brings in the compiler, so as you say above it's a build dependency on the compiler. Then the compiler may or may not decide to inject further dependencies. If we don't make the language dependency a build dependency we won't be able to have duplicates (since link dependency virtuals are unified, whereas build are not).
Languages should just omit the deptype.
But depends_on have that argument, so a user may specify it. That was one of the reason for which I started implementing this using another directive. If we use depends_on I think people need to get used to adding type="build" as they do e.g. for cmake. If we use a wrapper directive we can take control of the type, and avoid exposing it.
There was a problem hiding this comment.
I think people need to get used to adding type="build" as they do e.g. for cmake. If we use a wrapper directive we can take control of the type, and avoid exposing it.
You can just do that with depends_on. No extra directive, no extra convention. Don't have them specify the deptype. It's the "default" deptype, and the machinery underneath should take care of the rest.
| provided_together: Dict["spack.spec.Spec", List[Set[str]]] | ||
| patches: Dict["spack.spec.Spec", List["spack.patch.Patch"]] | ||
| variants: Dict[str, Tuple["spack.variant.Variant", "spack.spec.Spec"]] | ||
| languages: Dict["spack.spec.Spec", Set[str]] |
There was a problem hiding this comment.
This should be TODO to remove later.
| if compiler.name not in ("gcc", "oneapi"): | ||
| continue | ||
|
|
||
| compiler_with_different_cls_names = {"oneapi": "intel-oneapi-compilers"} |
There was a problem hiding this comment.
This still needs to be consolidated - it should come from compilers/__init__.py
| if languages: | ||
| body_str += ",\n" | ||
| for language in languages: | ||
| body_str += f' attr("language", {node_variable}, "{language}")' |
There was a problem hiding this comment.
this, like depends_on() should be using SUPPORTED_LANGUAGES an not forcing extra parameters on the caller.
TODO: the final implementation of this should not have an extra languages parameter and should not have any special cases for "languages". There should be one general mechanism for packages to inject additional dependencies, and that's all we should need.
| attr("language", node(X, Package), Language) :- | ||
| condition_holds(ConditionID, node(X, Package)), | ||
| pkg_fact(Package,language(ConditionID, Language)). |
There was a problem hiding this comment.
This should eventually be unnecessary once we have compilers modeled as packages.
| runtime_pkgs = spack.repo.PATH.packages_with_tags("runtime") | ||
| runtime_virtuals = set() | ||
| for x in runtime_pkgs: | ||
| pkg_class = spack.repo.PATH.get_pkg_class(x) | ||
| runtime_virtuals.update(pkg_class.provided_virtual_names()) | ||
|
|
||
| self.specs = specs + [spack.spec.Spec(x) for x in runtime_pkgs] |
There was a problem hiding this comment.
This requires too much effort from the packager. They shouldn't have to tag runtimes.
I'm assuming the reason we do this is because we need the full set of possible virtuals before the solve, but you have that after you call runtime_constraints() on all the packages that have that method. You can just see if any of the global dependencies added with pkg("*").depends_on() are virtual, and get the same (actually, possibly smaller) list of runtime_virtuals that you have here. So this logic should go away and we should just look at what was injected.
There was a problem hiding this comment.
I can remove the tags for an extra method in e.g. gcc that returns what the package could possibly inject.
| gfortran_str = "libgfortran@4" | ||
|
|
||
| for fortran_virtual in ("fortran-rt", gfortran_str): | ||
| pkg("*").depends_on( |
There was a problem hiding this comment.
This depends_on() is the one that should alert the solver to the fact that libgfortran and fortran-rt are possible virtuals. I think the pkg object should keep track of that and we should use it once all runtime_constraints() have been called in setup.
| depends_on("cxx", type="build", when="+cxx") | ||
| depends_on("fortran", type="build", when="+fortran") |
There was a problem hiding this comment.
@alalazo Why do these have to be build dependencies? I think a default deptype is fine here, as this will eventually resolve to a build dependency on a compiler and link dependencies on libraries.
There was a problem hiding this comment.
Discussed in DMs. We might want to consider a new deptype. Currently the dependency maps to the compiler only, which needs to be build due to unification rules (once compilers are real dependencies).
…ck#42062) This PR adds: - A new runtime for `%oneapi` compilers, called `intel-oneapi-runtime` - Information to both `gcc-runtime` and `intel-oneapi-runtime`, to ensure that we don't mix compilers using different soname for either `libgfortran` or `libifcore` To do so, the following internal mechanisms have been implemented: - Possibility to inject virtual dependencies from the `runtime_constraints` callback on packages Information has been added to `gcc-runtime` to provide the correct soname under different conditions on its `%gcc`. Rules injected into the solver looks like: ```prolog % Add a dependency on 'gfortran@5' for nodes compiled with gcc@=13.2.0 and using the 'fortran' language attr("dependency_holds", node(ID, Package), "gfortran", "link") :- attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("virtual_node", node(RuntimeID, "gfortran")) :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("node_version_satisfies", node(RuntimeID, "gfortran"), "5") :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). ```
|
I'm seeing the following behavior with this PR change. Note the With the snapshot prior to this change - I get: Any idea if hdf5 needs a fix to restore this behavior? Alternative I'm having to use now: |
|
@balay I'll check if I can reproduce this default behavior, and why it happens. Thanks for reporting. |
…ck#42062) This PR adds: - A new runtime for `%oneapi` compilers, called `intel-oneapi-runtime` - Information to both `gcc-runtime` and `intel-oneapi-runtime`, to ensure that we don't mix compilers using different soname for either `libgfortran` or `libifcore` To do so, the following internal mechanisms have been implemented: - Possibility to inject virtual dependencies from the `runtime_constraints` callback on packages Information has been added to `gcc-runtime` to provide the correct soname under different conditions on its `%gcc`. Rules injected into the solver looks like: ```prolog % Add a dependency on 'gfortran@5' for nodes compiled with gcc@=13.2.0 and using the 'fortran' language attr("dependency_holds", node(ID, Package), "gfortran", "link") :- attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("virtual_node", node(RuntimeID, "gfortran")) :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("node_version_satisfies", node(RuntimeID, "gfortran"), "5") :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). ```
…ck#42062) This PR adds: - A new runtime for `%oneapi` compilers, called `intel-oneapi-runtime` - Information to both `gcc-runtime` and `intel-oneapi-runtime`, to ensure that we don't mix compilers using different soname for either `libgfortran` or `libifcore` To do so, the following internal mechanisms have been implemented: - Possibility to inject virtual dependencies from the `runtime_constraints` callback on packages Information has been added to `gcc-runtime` to provide the correct soname under different conditions on its `%gcc`. Rules injected into the solver looks like: ```prolog % Add a dependency on 'gfortran@5' for nodes compiled with gcc@=13.2.0 and using the 'fortran' language attr("dependency_holds", node(ID, Package), "gfortran", "link") :- attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("virtual_node", node(RuntimeID, "gfortran")) :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). attr("node_version_satisfies", node(RuntimeID, "gfortran"), "5") :- attr("depends_on", node(ID, Package), ProviderNode, "link"), provider(ProviderNode, node(RuntimeID, "gfortran")), attr("node", node(ID, Package)), attr("node_compiler", node(ID, Package), "gcc"), attr("node_compiler_version", node(ID, Package), "gcc", "13.2.0"), not external(node(ID, Package)), not runtime(Package), attr("language", node(ID, Package), "fortran"). ```
|
Ah, working now: #47806 |


This PR adds:
%oneapicompilers, calledintel-oneapi-runtimegcc-runtimeandintel-oneapi-runtime, to ensure that we don't mix compilers using different soname for eitherlibgfortranorlibifcoreTo do so, the following internal mechanisms have been implemented:
runtime_constraintscallback on packagesInformation has been added to
gcc-runtimeto provide the correct soname under different conditions on its%gcc.Rules injected into the solver looks like:
Injection of virtual dependency