Skip to content
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

Improves item comparison performance #3258

Merged

Conversation

WalshyDev
Copy link
Member

Description

There are a lot of situations where SF items are CraftItemStacks not SlimefunItemStacks

This is most obvious with cargo and has been a big bottleneck there (~60%).

This PR addresses the cargo-specific point but will probably carry over to other parts of the code here and in addons.

In Cargo we wrap the items being used for comparison, these items can still be SF items just, they look like regular Bukkit items. So, the is item similar check should account for this.

With this change, it will check if it's wrapped and if it has item meta, if it does then it will try and get IDs to compare. Otherwise, fall back to the usual item meta comparison. This improves cargo performance by about 60% when filtering SF items.

The reason this change has such a big impact is simple, the display name code is terrible. It will decode JSON and create message components just for getting the name. It's very awkward and not nice to use. The ItemMeta#getDisplayName alone accounts for 60% of cargos #insert processing time in the numerous Spark reports we have received.

Call stack for this:

Proposed changes

Check if an item is an ItemStackWrapper and try to compare IDs there too. It will only do it currently if both items are SlimefunItemStacks but that isn't the case a lot of the time.

Related Issues (if applicable)

N/A

Checklist

  • I have fully tested the proposed changes and promise that they will not break everything into chaos.
  • I have also tested the proposed changes in combination with various popular addons and can confirm my changes do not break them.
  • I followed the existing code standards and didn't mess up the formatting.
  • I did my best to add documentation to any public classes or methods I added.
  • I have added Nonnull and Nullable annotations to my methods to indicate their behaviour for null values
  • I added sufficient Unit Tests to cover my code.

Requesting a review from @md5sha256 who initially introduced this wrapper code

There are a lot of situations where SF items are CraftItemStacks not SlimefunItemStacks

This is most obvious with cargo and has been a big bottleneck there (~60%).

This PR addresses the cargo specific point but will probably carry over to other parts of the code here and in addons.

In Cargo we wrap the items being used for comparison, these items can still be SF items just, they look like regular Bukkit items. So, the is item similar check should account for this.

With this change it will check if it's wrapped and if it has item meta, if it does then it will try and get IDs to compare. Otherwise, fall back to usual item meta comparison. This improves cargo performance by about 60% when filtering SF items.
@WalshyDev WalshyDev added the 💡 Performance Optimization This pull request improves performance. label Sep 15, 2021
@WalshyDev WalshyDev requested a review from a team as a code owner September 15, 2021 10:30
@github-actions
Copy link
Contributor

Your Pull Request was automatically labelled as: "💡 Performance Optimization"
Thank you for contributing to this project! ❤️

@sonarcloud
Copy link

sonarcloud bot commented Sep 15, 2021

Kudos, SonarCloud Quality Gate passed!    Quality Gate passed

Bug A 0 Bugs
Vulnerability A 0 Vulnerabilities
Security Hotspot A 0 Security Hotspots
Code Smell A 1 Code Smell

66.7% 66.7% Coverage
0.0% 0.0% Duplication

Copy link
Contributor

@md5sha256 md5sha256 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The optimisation makes a lot of sense; LGTM.

Copy link
Member

@svr333 svr333 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me

@WalshyDev
Copy link
Member Author

With the help of @Sefiraat I have done some timings on a HUGE base, here are the results:

Non optimized:

[14:44:08 INFO]: ===== Slimefun Lag Profiler =====
[14:44:08 INFO]: Total time: 75.05ms
[14:44:08 INFO]: Running every: 0.5s (10 ticks)
[14:44:08 INFO]: Performance: :::::::::::::::::::: - Severe (75%)
[14:44:08 INFO]: 
[14:44:08 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (65.2ms | avg: 0.16ms)

Optimized:

[14:49:26 INFO]: ===== Slimefun Lag Profiler =====
[14:49:26 INFO]: Total time: 39.2ms
[14:49:26 INFO]: Running every: 0.5s (10 ticks)
[14:49:26 INFO]: Performance: :::::::::::::::::::: - Moderate (39%)
[14:49:26 INFO]: 
[14:49:26 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (30.43ms | avg: 0.08ms)

50% reduction!!!

@J3fftw1
Copy link
Member

J3fftw1 commented Sep 16, 2021

With the help of @Sefiraat I have done some timings on a HUGE base, here are the results:

Non optimized:

[14:44:08 INFO]: ===== Slimefun Lag Profiler =====
[14:44:08 INFO]: Total time: 75.05ms
[14:44:08 INFO]: Running every: 0.5s (10 ticks)
[14:44:08 INFO]: Performance: :::::::::::::::::::: - Severe (75%)
[14:44:08 INFO]: 
[14:44:08 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (65.2ms | avg: 0.16ms)

Optimized:

[14:49:26 INFO]: ===== Slimefun Lag Profiler =====
[14:49:26 INFO]: Total time: 39.2ms
[14:49:26 INFO]: Running every: 0.5s (10 ticks)
[14:49:26 INFO]: Performance: :::::::::::::::::::: - Moderate (39%)
[14:49:26 INFO]: 
[14:49:26 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (30.43ms | avg: 0.08ms)

50% reduction!!!

Not even crediting me for running these test bish

@Sefiraat
Copy link
Member

With the help of @Sefiraat I have done some timings on a HUGE base, here are the results:

Non optimized:

[14:44:08 INFO]: ===== Slimefun Lag Profiler =====
[14:44:08 INFO]: Total time: 75.05ms
[14:44:08 INFO]: Running every: 0.5s (10 ticks)
[14:44:08 INFO]: Performance: :::::::::::::::::::: - Severe (75%)
[14:44:08 INFO]: 
[14:44:08 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (65.2ms | avg: 0.16ms)

Optimized:

[14:49:26 INFO]: ===== Slimefun Lag Profiler =====
[14:49:26 INFO]: Total time: 39.2ms
[14:49:26 INFO]: Running every: 0.5s (10 ticks)
[14:49:26 INFO]: Performance: :::::::::::::::::::: - Moderate (39%)
[14:49:26 INFO]: 
[14:49:26 INFO]: 1434 blocks
  CARGO_NODE_INPUT - 400x (30.43ms | avg: 0.08ms)

50% reduction!!!

Love it.... the owners of this server will, in advance, thank you greatly for this when it's all approved xD

Copy link
Member

@TheBusyBiscuit TheBusyBiscuit left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, I will merge this on the weekend.

Also, we really should focus on writing very extensive unit tests for this method soon.
It is so widely used, yet not even remotely covered by tests.

Comment on lines +291 to +292
// Slimefun items may be ItemStackWrapper's in the context of cargo so let's try to do
// an ID comparison before meta comparison
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

multiline comment 👀

Suggested change
// Slimefun items may be ItemStackWrapper's in the context of cargo so let's try to do
// an ID comparison before meta comparison
/*
* Slimefun items may be ItemStackWrapper's in the context of cargo so let's try to do
* an ID comparison before meta comparison
*/

Comment on lines +294 to +301
Optional<String> possibleSfItemId = Slimefun.getItemDataService().getItemData(possibleSfItemMeta);
Optional<String> itemId = Slimefun.getItemDataService().getItemData(itemMeta);

if (possibleSfItemId.isPresent() && itemId.isPresent()) {
return possibleSfItemId.get().equals(itemId.get());
} else {
return equalsItemMeta(itemMeta, possibleSfItemMeta, checkLore);
}
Copy link
Member

@TheBusyBiscuit TheBusyBiscuit Sep 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that I have time to look at this a little closer, I spot a way we can optimize this further.
If possibleSfItemMeta has no id, we don't need to extract the id from itemMeta, reducing it by one avoidable call.

Not the prettiest but you get the idea

Suggested change
Optional<String> possibleSfItemId = Slimefun.getItemDataService().getItemData(possibleSfItemMeta);
Optional<String> itemId = Slimefun.getItemDataService().getItemData(itemMeta);
if (possibleSfItemId.isPresent() && itemId.isPresent()) {
return possibleSfItemId.get().equals(itemId.get());
} else {
return equalsItemMeta(itemMeta, possibleSfItemMeta, checkLore);
}
Optional<String> possibleSfItemId = Slimefun.getItemDataService().getItemData(possibleSfItemMeta);
if (possibleSfItemId.isPresent()) {
Optional<String> itemId = Slimefun.getItemDataService().getItemData(itemMeta);
if (itemId.isPresent()) {
return possibleSfItemId.get().equals(itemId.get());
}
}
return equalsItemMeta(itemMeta, possibleSfItemMeta, checkLore);

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch the above.
To declutter this:

We should implement a CustomItemDataService#compare(...) method.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll make a follow-up commit.

@TheBusyBiscuit TheBusyBiscuit merged commit 4727b2a into master Sep 19, 2021
@TheBusyBiscuit TheBusyBiscuit deleted the performance/improve-item-comparison-performance branch September 19, 2021 16:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
💡 Performance Optimization This pull request improves performance.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants