perf: pack subscription edges to remove parallel slot arrays - #3358
Priyansh4444 wants to merge 1 commit into
Conversation
🦋 Changeset detectedLatest commit: 8696fd8 The changes in this PR will be included in the next version bump. This PR includes changesets to release 2 packages
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 |
|
As mentioned before, this was created by an agent, while trying to test a performance skill I made. What the skill did was simulate what the bytecode would look like, then ACTUALLY compile what the bytecode is and see what the difference would be. I think this is a reasonable change considering, let's say this code is hot (i.e. the runtime has hit this section of the code multiple times and therefore compiles the code JIT). It would benefit for cache locality (ofc this depends on the Cache architechture and the amount of cache in the register) since things that live together are easier to fetch together. This is also almost purely speculative and my assumptions are based on the actual benchmark for the speed improvement! This does sacrifice readability for the tiny bit of performance. I would love to know if this PR is useful and if it is useless feel free to close it without guilt, this is mainly a learning experience for me too! |
|
Once again sorry for the review burden! |
Update: bytecode and per-scenario regression checkAdding the machine-level evidence behind this representation change. Bytecode ( The last subscriber's computation sits at Per-scenario check (repo benchmark; pooled medians from 11 interleaved pairs, plus focused 20 to 30 pair reruns for the two scenarios that looked positive when sessions were pooled):
No credible regression. The two positive pooled entries were bimodal noise from 5 to 20 ms scenarios; focused sampling with more pairs shows both improve. Correctness: repo tests 487 + 4 pass; an independent 200-seed differential over conditional dependencies, duplicate reads, disposal and cleanup, batch, untrack and memo equality produced byte-identical logs (5,235 logged computation runs). All numbers on Node 26 / V8 14.6. The evidence above was produced by an AI agent following a documented optimization protocol, and the benchmark result was independently reproduced before this draft. |
|
Stuff against Solid 1.x at this point are taken with extra scrutiny because of where it is in its lifecycle. We actually started on some improvements of this nature in a 1.10.x beta branch but weren't suffciiently testing it. I know from my 2.x work there is definitely some perf on the table, but it might take a little bit before I get back to reviewing this given the state of Solid 1.x and and the focus on the 2.0 release. |
What
Solid's signal graph stores each subscription edge as two parallel arrays on both sides:
observers[i]= computation,observerSlots[i]= that computation's index in itssourcesarraysources[j]= signal/memo,sourceSlots[j]= that computation's index in the signal'sobserversarrayThis packs each edge into one array (
[other, slot, other, slot, ...]), removing one array and one property per edge side.Why
Every computation subscription currently allocates or grows two arrays (
sourcesandsourceSlots). On the repo's ownpackages/solid/bench/bench.cjsworkload (1e5 signals and computations), interleaved A/B pairs show:The counterbalanced subset also favors the change when it runs first, so this is not arm order. Bundle: 53,614 to 53,447 bytes.
Correctness
pnpm --filter solid-js test: 487 tests pass, plus 4 in the server suite.Notes for reviewers
packages/solid/bench/bench.cjsin this tree aborts on V8 14.6 because%OptimizeFunctionOnNextCallnow requires%PrepareFunctionForOptimizationfirst. Adding that call before the optimize call is enough to run the benchmark. The harness change is not part of this PR.