Skip to content

fix: update untracked writes for BLOCK_EFFECTs too #16110

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

paoloricciuti
Copy link
Member

Closes #16090
Closes #16104

This fixes both of this and all the test are actually green. However I'm not convinced this is the right fix because it's a bit greedy: the problem is the following.

  1. a derived of a derived returns a component
  2. that component is read by the component function (and is marked as CLEAN)
  3. mounting that component update a value of that triggers the original derived
  4. this triggers the derived of derived which is marked as MAYBE_DIRTY
  5. since that derived was already read it's not read again so it stays MAYBE_DIRTY
  6. when the value changes the original derived is updated but since the derived of derived is MAYBE_DIRTY his reactions are not marked/scheduled

Now including MAYBE_DIRTY in the flags to mark/schedule fixes it but i think it will schedule more than necessary and i don't know if this could have performance issues. The best action would be to mark the derived as clean if we can somehow detect that it was marked after being read but it's a bit of a weird situation (becuase if you, for example, read it again in an effect the bug it's not present)

Before submitting the PR, please make sure you do the following

  • It's really useful if your PR references an issue where it is discussed ahead of time. In many cases, features are absent for a reason. For large changes, please create an RFC: https://github.com/sveltejs/rfcs
  • Prefix your PR title with feat:, fix:, chore:, or docs:.
  • This message body should clearly illustrate what problems it solves.
  • Ideally, include a test that fails without this PR but passes with it.
  • If this PR changes code within packages/svelte/src, add a changeset (npx changeset).

Tests and linting

  • Run the tests with pnpm test and lint the project with pnpm lint

Copy link

changeset-bot bot commented Jun 8, 2025

🦋 Changeset detected

Latest commit: 9b3677d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
svelte Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

Copy link
Contributor

github-actions bot commented Jun 8, 2025

Playground

pnpm add https://pkg.pr.new/svelte@16110

@dummdidumm
Copy link
Member

Looking at the benchmark the overall time spent with GC has more than doubled, so as you say this is likely not the right fix (also because what would even be the difference between maybe dirty and dirty now?)

@paoloricciuti
Copy link
Member Author

paoloricciuti commented Jun 8, 2025

Yeah to be fair I was even surprised no test failed but I guess it's just removing an optimization.

I guess the right fix would be to find a way to set back this kind of MAYBE_DIRTY to CLEAN even if it's not executed again.

Mmm...I guess technically the derived should be executed again since the value might change 🤔

@paoloricciuti
Copy link
Member Author

Ok i tried a bit more, it's getting late: so I think the actual problem is that when we mark the reactions of the derived of derived the first time it's reactions are not yet populated because we are within the function call in update_reaction...so basically we update the block effect in the component function, that invalidate the derived through the $effect.pre which should mark the block for a rerun but it doesn't because block is not going to be added as a reaction until the function finishes to run.

Still need to find a proper solution.

@paoloricciuti
Copy link
Member Author

Ok this is a different fix: it's basically extending the logic for untracked writes to BLOCK_EFFECT's too (since the get_component function runs there...not sure of the performance implication, let's see what the benchmark say.

@paoloricciuti
Copy link
Member Author

@dummdidumm looking at the benchmarks on main i see gc_time fluctuate a bit (i've seen times up to 400)...this branch currently shows 487 which is worse but not terribly worse maybe?

I wonder if this could be the fix.

@paoloricciuti paoloricciuti changed the title fix: mark reactions of MAYBE_DIRTY reactions too fix: update untracked writes for BLOCK_EFFECTs too Jun 9, 2025
@paoloricciuti
Copy link
Member Author

paoloricciuti commented Jun 9, 2025

Tbf they seems pretty similar running compare

sbench_create_signals
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   403.54ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 438.36ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    178.47ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 206.05ms
sbench_create_0to1
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  4.50ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 4.74ms
sbench_create_1to1
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  20.19ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 20.77ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   2.29ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.48ms
sbench_create_2to1
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  17.34ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 18.36ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   2.18ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.40ms
sbench_create_4to1
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  16.63ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 17.17ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    2.12ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.46ms
sbench_create_1000to1
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 15.27ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 15.23ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.34ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   2.15ms
sbench_create_1to2
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  9.51ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 10.05ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  0.50ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.54ms
sbench_create_1to4
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   7.69ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 8.48ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    0.43ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.50ms
sbench_create_1to8
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   6.35ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 6.96ms
sbench_create_1to1000
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  5.02ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 5.28ms
kairo_avoidable_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 273.14ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 271.49ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 5.73ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  5.39ms
kairo_avoidable_unowned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 364.04ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 367.89ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 5.67ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 5.66ms
kairo_broad_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 407.80ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 405.03ms
kairo_broad_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 407.99ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 407.22ms
kairo_deep_owned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 180.61ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 182.64ms
kairo_deep_unowned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 888.63ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 891.04ms
kairo_diamond_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 302.86ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   274.38ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 3.44ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   3.15ms
kairo_diamond_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 384.47ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 383.55ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 3.65ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   3.21ms
kairo_triangle_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 101.15ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   89.68ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.51ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    0.44ms
kairo_triangle_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 209.01ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 207.17ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼    0.52ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.60ms
kairo_mux_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 307.59ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 306.99ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  1.85ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 1.96ms
kairo_mux_unowned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 460.08ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 462.24ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  2.03ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 2.19ms
kairo_repeated_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 44.79ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 44.09ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.19ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   0.17ms
kairo_repeated_unowned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 45.48ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 44.72ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.18ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  0.17ms
kairo_unstable_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 76.36ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  74.33ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.64ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼     0.52ms
kairo_unstable_unowned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 92.72ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 92.87ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼      0.61ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.82ms
mol_bench_owned
  time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 232.39ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 230.48ms
  gc_time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼  0.22ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.23ms
mol_bench_unowned
  time: fastest is a (derived-reactions-maybe-dirty-marked)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 246.80ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 247.90ms
  gc_time: fastest is b (main)
    a: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼ 0.25ms
    b: ◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼◼   0.22ms

@trueadm
Copy link
Contributor

trueadm commented Jun 9, 2025

I'm not even sure the benchmark makes use of blocks. However, this looks like the right fix to me.

@raythurnvoid
Copy link
Contributor

raythurnvoid commented Jun 9, 2025

Hey I was also working on #16090 and i just found out running in production mode behaves correctly without any changes from the main branch.

@paoloricciuti
Copy link
Member Author

Hey I was also working on #16090 and i just found out running in production mode behaves correctly without any changes from the main branch.

Yeah however the other bug this closes is still present even in production builds

@raythurnvoid
Copy link
Contributor

I'm closing my other PR ^^.

But will spend some time investigating why prod mode fixes that thing, might be revealing something odd

@tBuLi12
Copy link

tBuLi12 commented Jun 10, 2025

running in production mode behaves correctly without any changes from the main branch

Not quite unfortunately, I've updated #16090 with info on how to observe the issue in prod as well. Hopefully this PR fixes that either way.

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.

Reactivity breaks due to an assignment in $effect.pre Derived value not receiving updates
5 participants