perf(light): resolve the opposite face once in the chunk propagator - #32
Merged
Conversation
Same change as in LightPropagator, on the loop that walks a whole chunk. Measurement follows in the pull request.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Applies the change from #28 to the second propagator.
ChunkLightPropagatorwalks a whole chunkrather than a single section, so its inner loop runs the same
face.opposite()call — a switch overthe enum — once per face per queued position, six times for every block the light reaches. Resolving
it once at class load turns that into an array read.
The loop becomes indexed so the face and its opposite share an index. Nothing else changes; no
behaviour is affected, and the change cannot be slower than what it replaces.
What was measured
ChunkLightPropagatorBenchmark, both methods, all six parameter combinations, on two jars thatdiffer in this commit alone:
origin/mainat a09c71f (#26) against the same tree with this change.#28 is absent from both, so the figures isolate this commit rather than the pair.
Two independent repeats per jar. A row counts as established only where both repeats of both jars
agree and the intervals do not overlap.
propagatepropagatepropagatepropagateSkypropagateSkypropagatepropagateSkyAll figures µs/op, lower is better.
What the numbers do not say
The saving is a function of source density, not of chunk size. Where a section holds one light
source the queue is short and the per-neighbour work is a large share of the pass, and the change
shows between −9.5 % and −16.1 % across every section count. At eight sources per section more of
the pass goes into spreading light and the effect drops into the noise —
propagateat 8 sourcesand 16 sections measures no difference at all. The headline figure is one corner of the parameter
space, and quoting −16.1 % without the density it belongs to would be wrong.
Five of the twelve rows were discarded, not omitted.
propagateat 8/4 and 8/24, andpropagateSkyat 1/16, 1/24 and 8/4, each had one repeat whose interval exceeded a tenth of its ownscore — up to ± 324 µs on a 966 µs score, and ± 1140 µs on one
propagateSkyrun. Those repeatsmeasure the machine, not the code, and none of them is in the table above. They neither support nor
contradict it.
The machine was not idle. Load average during the series ran between 4 and 6 on 16 hardware
threads, from a browser, a file indexer and three language servers. That is the source of the five
discarded repeats, and it is why this is presented as a ratio between two jars measured under the
same conditions rather than as absolute microseconds. The five rows above survived that noise across
four independent runs each, which is the reason to believe them.
Where these numbers should come from instead
#29 and #31 landed after this branch was cut. The
customprofile recordscores,load_beforeand
load_after— precisely the conditions whose absence produced a false reading during this work,before a re-measurement caught it. It cannot replace this particular comparison, because it builds
one jar from one commit and an A/B needs two, and its own provenance text is right that absolute
microseconds from a shared runner do not belong in a published table. But once a
self-hostedrunner exists, running each side there and comparing within a runner is a better instrument than
this desktop.
Nothing here is proposed for
Measured Results. The rows in the table are an argument for thechange, measured under conditions stated in full; they are not a published figure.
ChunkLightPropagatorBenchmark, 3 forks, 5 × 1 s warmup, 5 × 1 s measurement,-Xms512m -Xmx512m, JMH 1.37, JVM 25.0.3+9-LTS, AMD Ryzen 7 5800X (8 cores / 16 threads), load average 4–6during the series — not idle, run on 2026-08-02, two repeats per jar. Raw JMH JSON available on
request.