Skip to content

Simple rewiring of spliced specs#26873

Merged
becker33 merged 47 commits intospack:developfrom
nhanford:features/splice-rewire
Apr 4, 2022
Merged

Simple rewiring of spliced specs#26873
becker33 merged 47 commits intospack:developfrom
nhanford:features/splice-rewire

Conversation

@nhanford
Copy link
Copy Markdown
Contributor

@nhanford nhanford commented Oct 21, 2021

Rewiring is an operation on concrete, installed, spliced specs which carefully relocates any relevant prefixes throughout all the specs in a spliced DAG and then performs necessary operations for the spliced spec to be seen as "installed." This operation remains somewhat "dangerous" and can lead to ABI breaks and other unexpected behavior. It should be used with caution.
Rewiring extends splicing (#20262) and honors all the semantics therein. For example, when a transitive splice is rewired, it will bring in all the dependencies of the newly-spliced dependency. Like splicing, rewiring is not destructive--it creates a new spec that conforms to the new spec from the splice.

@spackbot-app spackbot-app bot added the tests General test capability(ies) label Oct 21, 2021
@nhanford nhanford marked this pull request as ready for review October 28, 2021 15:19
@nhanford nhanford requested review from becker33 and tgamblin October 28, 2021 15:19
Comment on lines +91 to +92
shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix,
ignore=shutil.ignore_patterns('.spack/spec.json'))
Copy link
Copy Markdown
Member

@vsoch vsoch Nov 11, 2021

Choose a reason for hiding this comment

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

This is going to get angry if the prefix already exists - if it does and has the same hash I think we already have the spec and don't need to do again?

Suggested change
shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix,
ignore=shutil.ignore_patterns('.spack/spec.json'))
if not os.path.exists(spec.prefix):
shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix,
ignore=shutil.ignore_patterns('.spack/spec.json'))

but if it's the case that the relocations are different (and the hash is the same) then you'd instead want to do:

Suggested change
shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix,
ignore=shutil.ignore_patterns('.spack/spec.json'))
if os.path.exists(spec.prefix):
shutil.rmtree(spec.prefix)
shutil.copytree(os.path.join(tempdir, spec.dag_hash()), spec.prefix,
ignore=shutil.ignore_patterns('.spack/spec.json'))

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.

If the relocations are different the hash has to be different too -- the hash contains all of the information on all of the splices.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yup sorry for not resolving this earlier. We wound up fixing the issue with the check to install missing specs.

@vsoch
Copy link
Copy Markdown
Member

vsoch commented Nov 24, 2021

Are we going to be able to splice different specs in? E.g., openmpi or mpich or vice versa - is that going to be another PR?

@nhanford
Copy link
Copy Markdown
Contributor Author

nhanford commented Dec 2, 2021

Sorry for missing this question: It will be in an upcoming PR.

spec.package.do_install(force=True)
dep.package.do_install(force=True)
spliced_spec = spec.splice(dep, transitive=transitive)
assert spec is not spliced_spec
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.

Is this checking for something in particular?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Removed per our discussion; this is already tested elsewhere.

manifest_file_path = os.path.join(node.prefix,
spack.store.layout.metadata_dir,
spack.store.layout.manifest_file_name)
assert os.path.exists(manifest_file_path)
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.

Is this just checking that the manifest file exists? Should we check that it reflects the new information?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

A new test, test_rewire_writes_new_metadata has been added with the described check.

Comment on lines +80 to +85
# test install manifest
spack.store.layout.ensure_installed(node)
manifest_file_path = os.path.join(node.prefix,
spack.store.layout.metadata_dir,
spack.store.layout.manifest_file_name)
assert os.path.exists(manifest_file_path)
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.

This seems to be covered by the previous test?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This duplicated code has been eliminated.


manifest = bindist.get_buildfile_manifest(spec.build_spec)
platform = spack.platforms.by_name(spec.platform)
if manifest.get('text_to_relocate'):
Copy link
Copy Markdown
Member

@becker33 becker33 Feb 24, 2022

Choose a reason for hiding this comment

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

Suggested change
if manifest.get('text_to_relocate'):
text_to_relocate = manifest.get('text_to_relocate', None):
if text_to_relocate:

Then you can use it inside the block wiithout needing a separate lookup

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This has been changed accordingly in both the text and binary cases.

@becker33 becker33 merged commit 88d8ca9 into spack:develop Apr 4, 2022
iarspider pushed a commit to iarspider/spack that referenced this pull request Apr 6, 2022
* tests for rewiring pure specs to spliced specs

* relocate text, binaries, and links

* using llnl.util.symlink for windows compat.

Note: This does not include CLI hooks for relocation.

Co-authored-by: Nathan Hanford <[email protected]>
RikkiButler20 pushed a commit to RikkiButler20/spack that referenced this pull request Apr 6, 2022
* tests for rewiring pure specs to spliced specs

* relocate text, binaries, and links

* using llnl.util.symlink for windows compat.

Note: This does not include CLI hooks for relocation.

Co-authored-by: Nathan Hanford <[email protected]>
becker33 added a commit that referenced this pull request Oct 10, 2024
This PR allows users to configure explicit splicing replacement of an abstract spec in the concretizer.

concretizer:
  splice:
    explicit:
    - target: mpi
      replacement: mpich/abcdef
      transitive: true

This config block would mean "for any spec that concretizes to use mpi, splice in mpich/abcdef in place of the mpi it would naturally concretize to use. See #20262, #26873, #27919, and #46382 for PRs enabling splicing in the Spec object. This PR will be the first place the splice method is used in a user-facing manner. See https://spack.readthedocs.io/en/latest/spack.html#spack.spec.Spec.splice for more information on splicing.

This will allow users to reuse generic public binaries while splicing in the performant local mpi implementation on their system.

In the config file, the target may be any abstract spec. The replacement must be a spec that includes an abstract hash `/abcdef`. The transitive key is optional, defaulting to true if left out.

Two important items to note:

1. When writing explicit splice config, the user is in charge of ensuring that the replacement specs they use are binary compatible with whatever targets they replace. In practice, this will likely require either specific knowledge of what packages will be installed by the user's workflow, or somewhat more specific abstract "target" specs for splicing, to ensure binary compatibility.
2. Explicit splices can cause the output of the concretizer not to satisfy the input. For example, using the config above and consider a package in a binary cache `hdf5/xyzabc` that depends on mvapich2. Then the command `spack install hdf5/xyzabc` will instead install the result of splicing `mpich/abcdef` into `hdf5/xyzabc` in place of whatever mvapich2 spec it previously depended on. When this occurs, a warning message is printed `Warning: explicit splice configuration has caused the the concretized spec {concrete_spec} not to satisfy the input spec {input_spec}".

Highlighted technical details of implementation:

1. This PR required modifying the installer to have two separate types of Tasks, `RewireTask` and `BuildTask`. Spliced specs are queued as `RewireTask` and standard specs are queued as `BuildTask`. Each spliced spec retains a pointer to its build_spec for provenance. If a RewireTask is dequeued and the associated `build_spec` is neither available in the install_tree nor from a binary cache, the RewireTask is requeued with a new dependency on a BuildTask for the build_spec, and BuildTasks are queued for the build spec and its dependencies.
2. Relocation is modified so that a spack binary can be simultaneously installed and rewired. This ensures that installing the build_spec is not necessary when splicing from a binary cache.
3. The splicing model is modified to more accurately represent build dependencies -- that is, spliced specs do not have build dependencies, as spliced specs are never built. Their build_specs retain the build dependencies, as they may be built as part of installing the spliced spec.
4. There were vestiges of the compiler bootstrapping logic that were not removed in #46237 because I asked alalazo to leave them in to avoid making the rebase for this PR harder than it needed to be. Those last remains are removed in this PR.

Co-authored-by: Nathan Hanford <[email protected]>
Co-authored-by: Gregory Becker <[email protected]>
Co-authored-by: Tamara Dahlgren <[email protected]>
arezaii pushed a commit to arezaii/spack that referenced this pull request Oct 22, 2024
This PR allows users to configure explicit splicing replacement of an abstract spec in the concretizer.

concretizer:
  splice:
    explicit:
    - target: mpi
      replacement: mpich/abcdef
      transitive: true

This config block would mean "for any spec that concretizes to use mpi, splice in mpich/abcdef in place of the mpi it would naturally concretize to use. See spack#20262, spack#26873, spack#27919, and spack#46382 for PRs enabling splicing in the Spec object. This PR will be the first place the splice method is used in a user-facing manner. See https://spack.readthedocs.io/en/latest/spack.html#spack.spec.Spec.splice for more information on splicing.

This will allow users to reuse generic public binaries while splicing in the performant local mpi implementation on their system.

In the config file, the target may be any abstract spec. The replacement must be a spec that includes an abstract hash `/abcdef`. The transitive key is optional, defaulting to true if left out.

Two important items to note:

1. When writing explicit splice config, the user is in charge of ensuring that the replacement specs they use are binary compatible with whatever targets they replace. In practice, this will likely require either specific knowledge of what packages will be installed by the user's workflow, or somewhat more specific abstract "target" specs for splicing, to ensure binary compatibility.
2. Explicit splices can cause the output of the concretizer not to satisfy the input. For example, using the config above and consider a package in a binary cache `hdf5/xyzabc` that depends on mvapich2. Then the command `spack install hdf5/xyzabc` will instead install the result of splicing `mpich/abcdef` into `hdf5/xyzabc` in place of whatever mvapich2 spec it previously depended on. When this occurs, a warning message is printed `Warning: explicit splice configuration has caused the the concretized spec {concrete_spec} not to satisfy the input spec {input_spec}".

Highlighted technical details of implementation:

1. This PR required modifying the installer to have two separate types of Tasks, `RewireTask` and `BuildTask`. Spliced specs are queued as `RewireTask` and standard specs are queued as `BuildTask`. Each spliced spec retains a pointer to its build_spec for provenance. If a RewireTask is dequeued and the associated `build_spec` is neither available in the install_tree nor from a binary cache, the RewireTask is requeued with a new dependency on a BuildTask for the build_spec, and BuildTasks are queued for the build spec and its dependencies.
2. Relocation is modified so that a spack binary can be simultaneously installed and rewired. This ensures that installing the build_spec is not necessary when splicing from a binary cache.
3. The splicing model is modified to more accurately represent build dependencies -- that is, spliced specs do not have build dependencies, as spliced specs are never built. Their build_specs retain the build dependencies, as they may be built as part of installing the spliced spec.
4. There were vestiges of the compiler bootstrapping logic that were not removed in spack#46237 because I asked alalazo to leave them in to avoid making the rebase for this PR harder than it needed to be. Those last remains are removed in this PR.

Co-authored-by: Nathan Hanford <[email protected]>
Co-authored-by: Gregory Becker <[email protected]>
Co-authored-by: Tamara Dahlgren <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

binary-packages tests General test capability(ies)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants