Skip to content

Conversation

@haampie
Copy link
Member

@haampie haampie commented Jan 22, 2026

On top of #51869

This refactors the directive system to execute directives lazily. Directives
are now queued during class definition and only executed when the corresponding
dictionary on the package class is accessed (e.g., pkg.dependencies,
pkg.versions). This reduces overhead during cache population, and in non-forking
build subprocesses where spec.package is used and metadata isn't needed.

  • DirectiveDictDescriptor is a singleton descriptor shared across package
    classes. It handles the lazy initialization of package attributes.
  • For each dictionary, the set of directives affecting it is computed
    automatically. For example, accessing pkg.extendees automatically triggers
    the execution of both extends and depends_on directives.
  • The actual dictionary is now stored at pkg._dependencies and so on. It is
    initially set to None to indicate the directives have not run yet.
  • depends_on now applies nested patch directives immediately via
    _execute_patch. This prevents state corruption in the global directive
    queue when depends_on is evaluated lazily. In the lazy model, we cannot
    support directives executing directives, and besides, it's redundant.
  • maintainers directives remain eager to ensure backward compatibility with
    packages that define maintainers as a simple class-level list.
  • Added _has_nested_directives to PackageBase to optimize patch indexing by
    skipping dependency traversals for packages that don't need them.

The descriptor indirection does not seem to impact the "setup" phase of the
solver.

The first use of Spack is significantly faster. Below are results from a best of 3.

Before (855e07a):

$ spack clean -m && time spack list
0m15.371s

After (5ee3706):

$ spack clean -m && time spack list
0m8.452s

The list(spack.repo.PATH.all_package_classes()) benchmark is now useless. With
a few other PRs combined (#51875, #51836, #51879), the first-use time reduces
further to 0m7.802s, which is very close to 2x faster.

* Both `@when(...)` and `with when(...)` now use immutable Specs
* Avoid the `Spec -> str -> Spec` conversion between `when` and
  `directives_meta`
* Avoid copy of `kwargs` in the common case where there is no
  `default_args` set
* Remove vestigial `if isinstance(result, Sequence)` check on the return
  value of a directive -- it's always a callable.
* Avoid `constrain` call if there's only a single when condition.

Signed-off-by: Harmen Stoppels <me@harmenstoppels.nl>
Signed-off-by: Harmen Stoppels <me@harmenstoppels.nl>
Signed-off-by: Harmen Stoppels <me@harmenstoppels.nl>
@haampie haampie force-pushed the hs/fix/speedup-first-spack-load branch 3 times, most recently from d6eb6a6 to 5ee3706 Compare January 22, 2026 12:58
This refactors the directive system to execute directives lazily.
Directives are now queued during class definition and only executed when
the corresponding dictionary on the package class is accessed (e.g.,
`pkg.dependencies`, `pkg.versions`). This reduces overhead during
package discovery and cache population.

- `DirectiveDictDescriptor` is a singleton descriptor shared across
  package classes. It handles the lazy initialization of package
  attributes.
- For each dictionary, the set of directives affecting it is computed
  automatically. For example, accessing `pkg.extendees` automatically
  triggers the execution of both `extends` and `depends_on` directives.
- Refactored `depends_on` to apply nested `patch` directives immediately
  via `_execute_patch`. This prevents state corruption in the global
  directive queue when `depends_on` is evaluated lazily. In the lazy
  model, we cannot support directives executing directives, and besides,
  it's redundant.
- `maintainers` directives remain eager to ensure backward compatibility
  with packages that define maintainers as a simple class-level list.
- Added `_has_nested_directives` to `PackageBase` to optimize patch
  indexing by skipping dependency traversals for packages that don't
  need them.

Signed-off-by: Harmen Stoppels <me@harmenstoppels.nl>
@haampie haampie force-pushed the hs/fix/speedup-first-spack-load branch from f5d81df to 3a7bc08 Compare January 22, 2026 17:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants