Skip to content

Speed up dependency solver preparation - #803

Merged
f-f merged 7 commits into
masterfrom
solver-performance-clean
Oct 12, 2026
Merged

f-f merged 7 commits into
masterfrom
solver-performance-clean

Conversation

@thomashoneyman

@thomashoneyman thomashoneyman commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

While looking into #801, I started wondering if we've left easy solver performance improvements on the table. Indeed, we have! The previous PR made calculating the matrix cascade ~18x faster, and this PR makes solving an individual package considerably faster — anywhere from ~1.3x to ~80x faster. It doesn't require a lot of code; in fact, this is a small net reduction of the solver implementation, and the majority of the new code is improved tests and the benchmarking code.

In short, the solver previously found reachable versions by repeatedly merging dependency maps until they stopped changing. In this rework, we instead use a worklist, expanding each reachable package version once. It also waits until after pruning to initialize diagnostic data, and stops merging source information that would immediately be discarded.

Benchmarks

Solving the latest manifest's dependencies for every package in the most recent registry snapshot went from 82.92s to 37.62s, or 2.20× faster. All 1,176 complete plans were identical.

Seconds per batch of 1,176 solves Before After
Mean 82.92 37.62
Median 81.32 37.81
Observed range 78.87–90.19 36.74–38.14

The version index here is 5,573 manifests from the registry, and each package's dependencies are solved independently and without a compiler constraint. Individual workloads improve by different amounts. Halogen's dependency solve went from 72.56ms to 10.68ms; a synthetic batch with a propagation-heavy, 60-package chain only improved from 242.91ms to 227.98ms. (This at least shows we aren't regressing — there is no case I could put together in which the new implementation is slower).

Here are some benchmark results, visually:

Dependency solves against the fixed registry snapshot, before and after

Synthetic solver workloads, before and after

The charts are showing means from minibench from 40 solves per process, and two processes per variant. The whiskers in the chart are the two means. As stated before, the resulting plans are the same.

The fixed snapshot uses registry revision d51cb8e and registry-index revision 23d1e62.

Comment thread lib/test/Registry/Solver.purs Outdated
Comment thread lib/test/Registry/Solver.purs Outdated
Comment thread lib/test/Registry/Solver.purs Outdated
Comment thread lib/test/Registry/Solver.purs Outdated
Comment thread lib/test/Registry/Solver.purs
Comment thread lib/src/Solver.purs Outdated
Comment thread lib/src/Solver.purs
Comment thread lib/src/Solver.purs Outdated
@thomashoneyman
thomashoneyman requested a review from f-f October 12, 2026 11:13
@thomashoneyman

Copy link
Copy Markdown
Member Author

@f-f addressed your comments and updated the text of the PR accordingly; I didn't change the implementation besides bringing in the test helpers, so your original review still stands.

@thomashoneyman
thomashoneyman force-pushed the solver-performance-clean branch from 8d89bb4 to 0edfbc7 Compare October 12, 2026 16:08

@f-f f-f left a comment

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.

thank you!

@f-f
f-f merged commit 29f5ce4 into master Oct 12, 2026
7 checks passed
@f-f
f-f deleted the solver-performance-clean branch October 12, 2026 18:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants