Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Overview
Noticed that the eval of very simple watch expressions was a bit slower than expected and dug into it, found a quick fix and reduced the watch expression time for this particular case by 90%; should have similar speedups for any expressions with deep transitive dependencies.
I ran a test locally with a single top-level example expression that had a deep dependency tree, and a single watch expression.
Here's how the timings compare on a couple runs (after runtime warmup)
Implementation notes
There was a subtlety in the optimization of recursive dependency search in the runtime which meant that tree pruning wasn't shared amongst multiple branches. I swapped it to a state monad rather than explicit binding passing to ensure the 'seen' Set is propagated everywhere it needs to go.
Test coverage
Local testing using
UNISON_DEBUG=TIMING
Loose ends
Could probably do even better by only collecting dependencies of the watch expressions themselves, I don't think we need the dependencies of parts of the file that we don't actually touch. Would that work @dolio ?
I'd also be curious if we could delay the code lookup until execution time so we only load terms that are literally required by the exact evaluation of the watch expression, but I'm guessing this would be a pain to write because we'd need separate codepaths for the watch expr eval vs the version that runs from a file or .uc or w/e