-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
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
Hopper Performance - Research and Suggestions #392
Comments
Interestingly I still only get ~3 TPS when I set the following options in spigot.yml: ticks-per:
hopper-transfer: 512
hopper-check: 512
hopper-amount: 64 Does this mean that the hopper based pushers bypasses the |
I'm sure that since the push-based hopper patch the hopper-check setting is ignored |
@sgdc3 The push-based hopper makes hopper-check unnecessary. |
I will look into this. But yes cloning is a huge issue, as there are a few more clones going on beyond what you listed too. I got rid of those on my server and received major gains. Just, I completely stripped the InventoryMoveItemEvent, making it easier for me to get rid of the unnecessary clones, which makes it harder to port my change. but when I Get time im gonna try. |
I also tested caching the hashcode - almost completely eliminates those from any noticeable effect when I profile. |
After a little investigation - not all of the event.getItem() calls can be converted to itemstack. This is because InventoryMoveItemEvent allows you to manually set the item. But we can eliminate all except the first - as things like "event.getItem().getAmount()" can be performed from 1 initial event.getItem(). Will investigate further to implement the changes that @aikar talked about. |
You could add an option to disable InventoryMoveItemEvent like I do in TacoSpigot. |
Someone has opened a PR: #394 |
Not all of the event.getItem() calls can be replaced with oitemstack - but what can be done is one of two things: Since event.getItem() returns a clone, we can make event.setItem() set a boolean field to true. If true, then we can use 1 event.getItem() call - but if false we can simply use oitemstack. If the above solution is out of scope we can just replace a lot of event.getItem() calls with 1 and use the temporary itemstack. |
@AlfieC - I see your point. We don't need to clone however. How about creating a method |
@oloflarsson I tested this out and it appears to work perfectly. Will PR it tonight/tomorrow, along with some cloning reductions. @aikar mentioned that he has some hopper work that he's working on, so I'll wait for him to push those first. |
The suggested improvements to BlockStateEnum have been made, with multiple people saying that the Event improvements are on the way. |
I'm still waiting for @aikar to show me some of the hopper stuff he was talking about - not sure what to PR until then. No point me PRing stuff if it'll be reverted/changed a few days later. |
I apparently lost the work, hit me up on irc for link to my patch and ill discuss my goal. |
I'm really glad to see this is being worked on 😸. Better hopper performance is going to make a lot of server owners happy 👍. |
Without removing the event, I've managed to make hoppers almost entirely disappear from timings. Now I just have to do a little more bug testing and then I can PR and start working on redstone :) |
I opened a pr (#445) that adds the ability to configure how the InventoryMoveItemEvent behaves. The major problem with it is that it gets called even when no item can move into the destination inventory when it is full. This results in protection plugins needing to check protections on every attempt to move even when no move occurs. From the three settings the patch adds I prefer the one enabled by default which is calling the InventoryMoveItemEvent as cancelled if no move can occur. This is in line with other events that fire as cancelled if the Vanilla behaviour is to do nothing. Most protection plugins already listen on the event with ignoreCancelled set to true and will therefor never know about if if the item wouldn't move. (There are two other options: completely disabling calling of the event on all moves or only for moves that wouldn't occur) You could potentially get even more performance out of these options if you completely rewrite the move logic as my current solution checks the target inventory twice (once for the original item before the event and the potentially modified after). Regarding "Idea 1" in the original post from @oloflarsson:
This solution would result in the issue that event.getItem().equals(oitemstack) would always compare the exact same object. (Which is why a clone is passed to the InventoryMoveItemEvent instead of the reference to the original CraftItemStack) In short: We would loose the information about the original item. |
This will be resolved with #976 |
Introduction
Thank you for the recent work on push based hoppers! They are great. Sadly we still get around 3 TPS on MassiveCraft due to huge hopper contraptions. I figured it must be possible to optimize hoppers further and did some research.
I tested on a brand new server with just WorldEdit to paste a schematic. This schematic contain 10 repetition of an actual hopper contraption built by a player on our server. After pasting the TPS drops to ~3.
Then I used VisualVM to find bottlenecks and it turns out that just by changing two small things, the performance impact of hopper transfers can be cut in half (approximately).
How to create hopper lag
/
./plugins
./plugins/WorldEdit
./plugins/WorldEdit/schematics
./
./plugins
./plugins/WorldEdit/schematics
.java -Xmx2G -Dcom.mojang.eula.agree=true -jar paperclip.jar
.op <yourname>
./schematic load hoppers
.//paste
./tps
.Idea 1
Saves: ~13% CPU
Fix Complexity: Very Easy
Short Description: Avoid calls to
org.bukkit.event.inventory.InventoryMoveItemEvent.getItem()
since it clones in vain.Long Description: The method
org.bukkit.event.inventory.InventoryMoveItemEvent.getItem()
is used three times innet.minecraft.server.TileEntityHopper.a(IHopper ihopper, IInventory iinventory, int i, EnumDirection enumdirection)
. In none of those thee cases is a clone operation required. The source code pieceevent.getItem()
could simply be replaced withoitemstack
. The same mistake is also made two times innet.minecraft.server.TileEntityHopper.H()
.Screenshots:
Idea 2
Saves: ~40% CPU
Fix Complexity: Easy
Short Description: BlockStateEnum is an immutable class. Cache or precalculate the hash code.
Long Description: Updating adjecent comparators uses loads of CPU. This is caused by hashCode recalculation of the MODE field in BlockRedstuneComparator. Luckily the BlockStateEnum is immutable and we can precalculate or cache the hash codes of this class after the first calculation.
Screenshots:
The text was updated successfully, but these errors were encountered: