Skip to content

[Performance] Run refresh work in the existing force runner - #5039

Open
soulomoon wants to merge 7 commits into
haskell:masterfrom
soulomoon:codex/remove-redundant-refresh-async
Open

[Performance] Run refresh work in the existing force runner#5039
soulomoon wants to merge 7 commits into
haskell:masterfrom
soulomoon:codex/remove-redundant-refresh-async

Conversation

@soulomoon

@soulomoon soulomoon commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Run refresh work directly in the existing force runner, removing the redundant asyncWithCleanUp layer and its extra async registration and wait. Notice we already have data Wait to handle possible thread spawning. We have 5% perf improvement with this simple deletion

@soulomoon soulomoon added the performance Issues about memory consumption, responsiveness, etc. label Aug 11, 2026
@soulomoon
soulomoon marked this pull request as ready for review August 11, 2026 22:17
@soulomoon
soulomoon requested a review from wz1000 as a code owner August 11, 2026 22:17
@soulomoon

soulomoon commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

here is the perf report from codex gather from the pipeline:

Performance report

Benchmarked exact head b2037b82f1 against master 16bf046629.

Metric Result versus master
Geometric-mean totalT −6.11%
Summed totalT −4.78%
Median totalT −4.42%
Faster benchmark cases 78 of 85

Results by configuration

Configuration Geometric-mean totalT Summed totalT Median
Cabal, GHC 9.12 −4.17% −3.95% −2.27%
Cabal, GHC 9.14 −9.40% −7.97% −10.34%
lsp-types, GHC 9.12 −6.63% −4.29% −5.46%
lsp-types, GHC 9.14 −4.26% −3.60% −4.03%

code actions after cradle edit

Configuration Result versus master
GHC 9.12 −6.30%
GHC 9.14 −4.96%

Conclusion: b2037b82f1 is faster than master across the benchmark suite, improving 78 of 85 successful benchmark cases.

@soulomoon soulomoon changed the title Run refresh work in the existing force runner [Performance] Run refresh work in the existing force runner Aug 12, 2026
@soulomoon
soulomoon requested a review from fendor August 13, 2026 06:07
@fendor
fendor requested a review from crtschin September 9, 2026 12:32
@fendor fendor added the status: needs review This PR is ready for review label Sep 9, 2026

@crtschin crtschin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Nice! The code looks correct to me, but this is a bit subtle so it would be nice to improve the docs a bit while we're here.

refresh db stack key result = case (addStack key stack, result) of
(Left e, _) -> throw e
(Right stack, Just me@Result{resultDeps = ResultDeps deps}) -> asyncWithCleanUp $ refreshDeps mempty db stack key me (reverse deps)
(Right stack, Just me@Result{resultDeps = ResultDeps deps}) -> refreshDeps mempty db stack key me (reverse deps)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The comment above refreshDeps still refers to this spawn, mind updating the comment?

@soulomoon soulomoon Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The builder would create a new thread for its deps ?

perhaps change it to Otherwise, new threads would be created to refresh the dirty deps (if any) and then compute the key itself in current thread ? WDYT

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Looks good!


-- | Refresh a key:
refresh :: Database -> Stack -> Key -> Maybe Result -> AIO (IO Result)
-- | Refresh a key in the existing force runner, which already owns its lifetime.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Could you elaborate this comment a bit, maybe write a Note about the ownership model?

See if you agree with how I read this currently:

  • A force runner refers to the first thread that evaluates the rule thunk in the database.
  • Refreshing refers to checking whether any dependencies changed and the key needs to be recomputed.
  • If a session restart occurs while a thread is refreshing a key, this is safe as the shake database increment invalidates outdated values as well.

@soulomoon soulomoon Sep 10, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

  1. By design, builder find out the rule is still Dirty and wrap it into Spawn(If Running, just wrap it into Wait) and then waitConcurrently_ create its force runner and run it.
  2. yes
  3. If session restart interrupt the proccess, since the step incre and the next run would consider it as Dirty again even though the Runningstate would not be altered. see viewDirty.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Do we have an existing note that captures this? If not, could you write one that explains how invalidation is structured and the invariants that hold?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

added. feel free to update the note if there is any problem there

@crtschin crtschin left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

component: hls-graph performance Issues about memory consumption, responsiveness, etc. status: needs review This PR is ready for review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants