Skip to content

EnergyNet / Energy Hatch performance: route cache invalidation + per-net handler caching (reduces TPS cost ~40% → ~16%) #4396

@barkerh4200-spec

Description

@barkerh4200-spec

Checked for existing issues

  • I have checked for existing issues, and have found none.

Tested latest version

  • I have checked that this occurs on the latest version.

GregTech CEu Version

gtceu-1.20.1-7.4.0.jar

Minecraft Version

1.20.1 Forge

Recipe Viewer Installed

None

Environment

Multiplayer - Dedicated Server

Cross-Mod Interaction

Yes

Other Installed Mods

AE2-Things-1.2.1.jar
AEAdditions-1.20.1-5.1.1.jar
AdvancedAE-1.3.2-1.20.1.jar
AdvancedPeripherals-1.20.1-0.7.44r.jar
ApothicAttributes-1.20.1-1.3.7.jar
BonsaiTrees3-1.20.1-3.3.2.jar
Bookshelf-Forge-1.20.1-20.2.13.jar
BotanyPots-Forge-1.20.1-13.0.41.jar
BrandonsCore-1.20.1-3.2.1.302-universal.jar
CodeChickenLib-1.20.1-4.4.0.516-universal.jar
Controlling-forge-1.20.1-12.0.2.jar.disabled
CraftPresence-2.7.0+1.20.1-forge.jar.disabled
Cucumber-1.20.1-7.0.16.jar
'DiceMC Money-1.20.1-0.0.1.jar'
Draconic-Additions-1.20.1-2.4.1.5-universal.jar
Draconic-Evolution-1.20.1-3.1.2.621-universal.jar
EnderIO-1.20.1-6.2.16-beta-all.jar
EuphoriaPatcher-1.7.8-r5.6.1-forge.jar.disabled
ExtendedAE-1.20-1.4.9-forge.jar
ExtendedCrafting-1.20.1-6.0.10.jar
ExtremeSoundMuffler-3.49.1-forge-1.20.1.jar
FastLeafDecay-32.jar
FluxNetworks-1.20.1-7.2.1.15.jar
FramedBlocks-9.4.2.jar
Glodium-1.20-1.5-forge.jar
HammerLib-1.20.1-20.1.50.jar
HardcoreDarkness-MC1.7.10-1.7.jar
HostileNeuralNetworks-1.20.1-5.3.3.jar
Jade-1.20.1-Forge-11.13.2.jar
JustEnoughResources-1.20.1-1.4.0.247.jar
'KubeJS Blood Magic-1.0.2-1.20.1.jar'
LibX-1.20.1-5.0.12.jar
LuckPerms-Forge-5.4.88.jar
Measurements-forge-1.20.1-2.0.1.jar
ModernUI-Forge-1.20.1-3.12.0.1-universal.jar.disabled
MouseTweaks-forge-mc1.20.1-2.25.1.jar.disabled
NoChatReports-FORGE-1.20.1-v2.2.2.jar
'Not Enough Recipe Book-FORGE-0.4.1+1.20.1.jar'
OctoLib-FORGE-0.5.0.1+1.20.1.jar
OverflowingBars-v8.0.1-1.20.1-Forge.jar.disabled
PackagedAuto-1.20.1-3.4.12.38.jar
PackagedAvaritia-Re-1.20.1-2.2.2.12.jar
Patchouli-1.20.1-84.1-FORGE.jar
PhoenixGregicAdditons-0.1.0.jar
Placebo-1.20.1-8.6.3.jar
PuzzlesLib-v8.1.33-1.20.1-Forge.jar
Re-Avaritia-forged-1.20.1-1.3.9.1-release.jar
Searchables-forge-1.20.1-1.0.3.jar
Shrink-1.20.1-1.4.5.jar
SimpleBackups-1.20.1-3.1.18.jar
SimpleStorageNetwork-1.20.1-1.12.2.jar
SkyGUIs-1.20.1-3.0.16.jar
SkyblockBuilder-1.20.1-5.1.28.jar
SolarFluxReborn-1.20.1-20.1.11.jar
'Stellar View-1.20.1-0.5.2-Forge.jar'
ToolBelt-1.20.1-1.20.02.jar
UniLib-1.2.0+1.20.1-forge.jar
VisualWorkbench-v8.0.1-1.20.1-Forge.jar
WarpOnJoin-1.0.0.jar
WitherSkeletonTweaks-1.20.1-9.1.0.jar
YungsApi-1.20-Forge-4.0.6.jar
YungsBetterEndIsland-1.20-Forge-2.0.6.jar
ad_astra-forge-1.20.1-1.15.20.jar
ad_extendra-forge-1.20.1-1.1.2.jar
ae2wtlib-15.3.3-forge.jar
aliascommands-1.0.0.jar
almostunified-forge-1.20.1-0.10.1.jar
angelring-1.20.1-2.3.1.jar
antiblocksrechiseled-0.4.8.jar
apikeymod-1.0.0.jar
appliedenergistics2-forge-15.4.10.jar
architectury-9.2.14-forge.jar
athena-forge-1.20.1-3.1.2.jar
badpackets-forge-0.4.3.jar
balm-forge-1.20.1-7.3.37-all.jar
bfcrmod-1.20.1-3.0.0.jar
bloodmagic-1.20.1-3.3.3-45.jar
botarium-forge-1.20.1-2.3.4.jar
buildinggadgets2-1.0.8.jar
buychunker-1.0.0.jar
cc-tweaked-1.20.1-forge-1.113.1.jar
chipped-forge-1.20.1-3.0.7.jar
cloth-config-11.1.136-forge.jar
collective-1.20.1-8.13.jar
configuration-forge-1.20.1-3.1.0.jar
configured-forge-1.20.1-2.2.3.jar.disabled
connectedglass-1.1.14-forge-mc1.20.1.jar
constructionwand-1.20.1-2.11.jar
cosmeticarmorreworked-1.20.1-v1a.jar
crafting-on-a-stick-1.20.1-1.1.5.jar
craftingstation-1.20.1-1.2.3.jar
craftingtweaks-forge-1.20.1-18.2.6.jar
cupboard-1.20.1-2.7.jar
curios-forge-5.14.1+1.20.1.jar
dcintegration-forge-3.0.7.1-1.20.1.jar
dicemc_ftbchunks_compat-1.0.0.jar
difficultylock-1.20.1-4.7.jar
dogeswap-1.0.0.jar
elevatorid-1.20.1-1.9.1-forge.jar
embeddium-0.3.31+mc1.20.1.jar.disabled
emi-1.1.22+1.20.1+forge.jar
enderchests-forge-1.20.1-1.4.jar
endertanks-forge-1.20.1-1.5.jar
exdeorum-1.46.jar
experimentalsettingsdisabler-1.20.1-3.0.jar
extractinator-forge-1.20.1-2.3.0.jar
fancymenu_forge_3.8.1_MC_1.20.1.jar.disabled
findme-3.2.2-forge.jar
flib-1.20.1-0.0.15.jar
forgivingvoid-forge-1.20.1-10.0.3.jar
ftb-chunks-forge-2001.3.6.jar
ftb-essentials-forge-2001.2.3.jar
ftb-filter-system-forge-20.0.1.jar
ftb-library-forge-2001.2.10.jar
ftb-quests-forge-2001.4.17.jar
ftb-teams-forge-2001.3.1.jar
ftb-ultimine-forge-2001.1.7.jar
ftb-xmod-compat-forge-2.1.3.jar
functionalstorage-1.20.1-1.2.10.jar
fusion-1.2.11a-forge-mc1.20.1.jar
geckolib-forge-1.20.1-4.8.2.jar
getitemid-1.0.0.jar
gravestone-forge-1.20.1-1.0.35.jar
gtceu-1.20.1-7.4.0.jar
gtceu-energynet-hotfix-1.0.0.jar
gtmthings-1.5.4.jar
gtmutils-2.4.0.jar
gtworldgenlayers-1.0.0.jar
guideme-20.1.14.jar
inventorysorter-1.20.1-23.0.11.jar
ironchest-1.20.1-14.4.4.jar
ironfurnaces-1.20.1-4.1.6.jar
item-filters-forge-2001.1.0-build.59.jar
itemblacklist-1.20.1-1.1.5.jar
jecalculation-forge-1.20.1-4.0.4.jar
jei-1.20.1-forge-15.20.0.127.jar
jobhook-1.0.0.jar
justzoom_forge_2.1.1_MC_1.20.1.jar.disabled
kjscc-2002-1.0.2-beta.jar
konkrete_forge_1.8.0_MC_1.20-1.20.1.jar
kotlinforforge-4.11.0-all.jar
kubejs-forge-2001.6.5-build.16.jar
kubejs_enderio-forge-1.20.1-0.6.0.jar
kubejs_extended_crafting-2001.5.jar
ldlib-forge-1.20.1-1.0.46.jar.disabled
libIPN-forge-1.20-4.0.2.jar.disabled
libnonymous-1.20.1-2.3.1.jar
mae2-2.0.0-beta.d.jar
megacells-forge-2.4.6-1.20.1.jar
melody_forge_1.0.3_MC_1.20.1-1.20.4.jar
merequester-forge-1.20.1-1.1.5.jar
nonetherportal-1.20.1-1.0.jar
observable-4.4.1.jar
oculus-mc1.20.1-1.8.0.jar.disabled
pingmod-1.0.0.jar
playershops-1.0.0.jar
polymorph-forge-0.49.10+1.20.1.jar
probejs-6.0.1-forge.jar
rankcommand-1.0.0.jar
rankupmod-1.0.0.jar
rechiseled-1.1.6-forge-mc1.20.jar
resourcefulconfig-forge-1.20.1-2.1.3.jar
resourcefullib-forge-1.20.1-2.1.29.jar
rhino-forge-2001.2.3-build.10.jar
shetiphiancore-forge-1.20.1-1.5.jar
simplylight-1.20.1-1.4.6-build.50.jar
sogcore-1.0.4-forge-1.20.1.jar
sophisticatedbackpacks-1.20.1-3.24.12.1411.jar
sophisticatedcore-1.20.1-1.2.107.1240.jar
spark-1.10.53-forge.jar
squatgrow-forge-5.3.0+mc1.20.1.jar
steamadditions-1.5.1.jar
structuretokubejsaisles-1.0.4-all.jar
supermartijn642configlib-1.1.8-forge-mc1.20.jar
supermartijn642corelib-1.1.18-forge-mc1.20.1.jar
titanium-1.20.1-3.8.32.jar
toofast-1.20-0.4.3.5.jar
torchmaster-20.1.9.jar
tpsmod-1.0.0.jar
trashcans-1.0.18b-forge-mc1.20.jar
trophymanager-1.20.1-2.1.3.jar
usclb-0.0.26.jar
water_sources_1.20.1_1.0.0.jar
worldedit-mod-7.2.15.jar
xtonesreworked-1.0.4-F_1.20.1-47.2.0.jar

Expected Behavior

Low TPS, not 40% TPS being spent on energy hatches / energynet recalculations every tick

EnergyNet should scale reasonably with machine count and network size.

In steady state (no topology changes), energy distribution should:

reuse cached route data

avoid repeated full network walks

avoid repeated capability/handler resolution for the same endpoints

Adding more machines to the same energy network should increase cost roughly linearly, not multiplicatively.

Actual Behavior

EnergyNet frequently clears its entire route cache on neighbor updates, even for local or unrelated changes.

This causes full network walks (PipeNetWalker.walk) to run repeatedly during normal ticking.

Energy distribution performs repeated per-machine, per-tick work across the same net:

route iteration

endpoint capability resolution

destination probing

On larger servers, energy hatches alone can consume a very large share of server tick time (≈40% observed), leading to poor scalability as machine count increases.

Steps to Reproduce

Build like 32 solar panel multiblocks and then connect like 100 single block machines to the output via directly connected wire

Set up a Forge 1.20.1 server with GTCEu and a modpack that includes a heap of energy-consuming machines.

Build a single large energy network (cables + energy hatches) supplying dozens of machines (≈50–100+).

Let the server run until it reaches a steady state (machines actively ticking, no recent restarts).

Use a profiler such as Spark to capture a 30–60 second CPU profile during normal operation.

Observe server tick usage:

EnergyNetHandler.acceptEnergyFromNetwork

EnergyNet.getNetData

EnergyNetWalker.createNetData

PipeNetWalker.walk

Note that even without topology changes, the EnergyNet repeatedly performs full network walks and per-machine endpoint probing, resulting in high TPS usage as machine count increases.

Additional Information

Description

On large GTCEu servers, the EnergyNet can become a major TPS bottleneck under realistic machine counts.
I investigated this with Spark profiling and implemented a correctness-preserving server-side hotpatch that significantly reduces the load without changing gameplay behavior.

I’m opening this issue to share findings and recommend an approach for an upstream optimization. I’m happy for the code to be used as reference rather than merged verbatim.

Observed problem

Spark profiling shows that EnergyNet cost is dominated by structural overhead, not energy logic itself:

EnergyNet.NET_DATA is globally cleared on every neighbor update, causing repeated full network walks (PipeNetWalker.walk) during normal ticking.

Energy distribution does repeated per-machine work across the same net:

route iteration

endpoint handler resolution (capability lookups)

per-destination probing

Effective complexity trends toward:
machines × ticks × routes × pathLength

On a production modpack, energy hatches alone consumed ~40% of server tick time.

What the patch changes (high level)

Using mixins (server-side only), I implemented the following optimizations:

Local route-cache invalidation
Replace NET_DATA.clear() with targeted invalidation of only the affected pipe position and its neighbors.
This eliminates repeated full net walks in steady state.

Per-net, multi-tick endpoint handler caching
Cache resolved IEnergyContainer handlers per EnergyNet and endpoint, validated by BlockEntity identity.
This avoids repeated capability resolution every tick.

Per-tick sink state caching
Cache remaining receivable amperage per endpoint per tick so multiple producers don’t re-probe the same sinks.

All caches are:

scoped to the EnergyNet instance (nets are replaced on rebuild)

locally invalidated on topology changes

correctness-preserving (no throttling, batching, or logic changes)

Results

Measured with Spark on the same server and load:

Energy hatch TPS usage reduced from ~40% → ~16%

PipeNetWalker.walk nearly eliminated from steady-state ticks

Remaining cost is dominated by actual energy transfer, not avoidable overhead

Recommendation

I strongly recommend reworking EnergyNet internals to:

Avoid global cache invalidation on neighbor updates

Treat endpoint handler resolution as a per-net, multi-tick concern, not per-producer per-tick

Separate static endpoint properties from per-tick dynamic energy state

I’m happy for the GTCEu team to use my patch as a reference implementation when redesigning the EnergyNet for better scalability.

Thanks for all the work on GTCEu — this optimization made a huge difference on our server.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions