Fast path for self-triggered IC thinks - #1379
Open
RasmusKD wants to merge 2 commits into
Open
Conversation
Every self-triggered IC paid for a full sign snapshot (getState), component serialization of all four lines and an IC id regex match on every think tick, even though the IC instance itself is cached. At 2000 STs that measured +3.4ms per tick with spikes to 100ms. The think handler now reuses the cached IC and family directly and only reruns the full setupIC verification once a second per IC; entries are only honoured while the IC remains in ICManager's cache, so break/unload invalidation is unchanged, and a sign edit is picked up within a second. Chunk-loaded lookups in the ST sweep are also memoised per pass, since clustered STs ask about the same few chunks thousands of times and a chunk cannot load or unload mid-sweep. Re-measured: 2000 active STs are indistinguishable from an idle server (50.5ms avg tick vs 50.3 baseline).
me4502
reviewed
Aug 19, 2026
| Map<World, Map<Long, Boolean>> loadedCache = new HashMap<>(); | ||
| for (Location location : registeredLocations) { | ||
| if(!location.getWorld().isChunkLoaded(location.getBlockX() >> 4, location.getBlockZ() >> 4)) { | ||
| if(!isLoadedCached(location.getWorld(), location.getBlockX() >> 4, location.getBlockZ() >> 4, loadedCache)) { |
Member
There was a problem hiding this comment.
What's the actual cost of checking if a chunk is loaded now? Last I checked this was functionally equivalent to a complex map lookup, which I would assume this would basically mirror.
Contributor
Author
There was a problem hiding this comment.
Fair point. The measured win came from skipping the sign snapshot and the id regex, the memoisation was added on top and never measured on its own, and with isChunkLoaded being a cheap map lookup it just traded one lookup for two plus boxing. Dropped it, the checks call isChunkLoaded directly again.
isChunkLoaded is already a cheap map lookup on modern servers, so the cache traded one lookup for two plus boxing. The measured win came from skipping the sign snapshot and regex, which stays.
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.
Every self-triggered IC pays for a full sign snapshot (getState), component serialization of all four lines and an IC id regex match on every think tick, even though the IC instance itself is already cached. At 2000 STs that measured +3.4ms per tick with spikes to 100ms.
The think handler now reuses the cached IC and family directly, and the full setupIC verification still reruns once a second per IC. The fast entry is only honoured while the IC remains in ICManager's cache, so break/unload invalidation is unchanged, and a sign edit is picked up within a second. The think itself runs exactly the code it always did (same IC instance, same sign object), so variables etc are untouched.
Chunk-loaded lookups in the ST sweep are also memoised per pass: clustered STs ask about the same few chunks thousands of times in one sweep, and a chunk cannot load or unload mid-sweep.
Re-measured after the change: 2000 active STs are indistinguishable from an idle server (50.5ms avg tick vs 50.3 baseline).