-
-
Notifications
You must be signed in to change notification settings - Fork 2.4k
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
[Feature request] Reordering of comparison in @EqualsAndHashCode for better performance #1543
Comments
I'm not sure about the usefulness of such an optimization. Obviously, testing the string before the list is better if only the former differs. It's probably also better in the average real use case, but what if the string is megabytes long and the list differ already in their size? I always order my fields accordingly; not as an optimization, but placing the simple things first makes sense to me. There's a proposal for generating |
My proposal is only about primitives and wrappers like |
@stsypanov You're right, somehow I "saw" Anyway, I guess, the primitive comparison is so cheap that moving primitives up sounds like a good idea. I'd place wrappers next because of the two memory indirections (which may be much more costly than the comparison itself). Everything else then in the last group. Disclaimer: I'm just a random commenter here, so whatever I say, doesn't matter. ;) |
@Maaartinus your comment is useful as it helped me to clarify what is expected from requested change. |
Strings are ubiquitous and are reasonably fast to compare if their hashCode()'s do not collide nor happens to be zero. So, I propose that we should use four groups: primitives first, wrappers second, strings third and everything else last. |
I think primitives and primitive wrappers first is a good idea. Regarding Strings, I'm a bit on the fence here. There could be many other objects that are even faster, and with upcoming value types, if their fields are primitives, they are probably faster. And if we give Strings special treatment, there is no way for a user to optimize their code. Currently, they can do that by reordering their fields. |
@victorwss String are only fast to compare if they hash codes differ. When the hash codes are equal (either by collision or because of the strings being equal), then you're out of luck and need to compare their arrays. Another problem: In order to use the hash code, you have to call Java itself uses neither @rspilker I guess, we could use a benchmark. I'd bet, primitives are the fastest with a large margin as they require no indirection and method call. Primitive wrappers could IMHO profit most from testing
and avoiding the call. All objects might profit from testing
instead of
The added tests are redundant, but avoid the indirection and the call in some common cases. The added cost in case the call is necessary is probably negligible (it'd get eliminated completely with inlining, but I guess, this doesn't happen).
Sure, imagine a value class starting with an |
Hello Folks, an up in this thread... I do have the same needs that are to be able to order the equals intentionally. Even we know that primitive is cheaper and would be first, for my business scenario I do have two String fields, basically: I captured this test scenario in a simple example just to compare with Lombok and creating one equals manually with the "right" ordination for my scenario. https://gist.github.com/samukce/38d1f58a43e670a3c70d361daa80ba1b Benchmark Mode Cnt Score Error Units
HashCodeSimulation.compareIntelliJ avgt 15 251.713 ± 5.123 ms/op
HashCodeSimulation.compareLombok avgt 15 270.360 ± 6.523 ms/op if the folks are ok I can submit a PR with some idea, How is it sounds? @Maaartinus |
I think reordering the fields in the class still also affects comparison
order. Is that enough for your needs?
…On Thu, Jun 4, 2020, 05:12 Samuel P. ***@***.***> wrote:
Hello Folks, an up in this thread... I do have the same needs that are to
be able to order the equals intentionally. Even we know that primitive is
cheaper and would be first, for my business scenario I do have two String
fields, basically: { String name; String value; } . If the equals are
built checking fist the name and I have the value one that is the one
that really changes frequently its content, the performance is hugely
impacted. Sure that I'm talking about thousands of objects been compared,
that is the scenario that I have and those more ms have an impact on the
business flow that I need to achieve.
I captured this test scenario in a simple example just to compare with
Lombok and creating one equals manually with the "right" ordination for my
scenario.
https://gist.github.com/samukce/38d1f58a43e670a3c70d361daa80ba1b
Benchmark Mode Cnt Score Error Units
HashCodeSimulation.compareIntelliJ avgt 15 251.713 ± 5.123 ms/op
HashCodeSimulation.compareLombok avgt 15 270.360 ± 6.523 ms/op
if the folks are ok I can submit a PR with some idea, How is it sounds?
@Maaartinus <https://github.com/Maaartinus>
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#1543 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABIERNGHCCZB5CLO5LLODDRU4GJRANCNFSM4EI6ENCA>
.
|
Yeap, I thought this idea but this is really implicit, right? if any other person gives some maintenance in this class is almost impossible to figure out it @randakar . I thought that we would have the same approach that we do for |
That doesn't sound like a bad idea.
The best way to go about it is sane defaults with some measure of manual
control as a possibility. Users should not need to fiddle with this kind of
thing to get decent performance normally, but in special cases where
performance is critical ...
That said, maintenance burden is a thing. The maintainers said they won't
accept features with a high maintenance cost to (boilerplate reduction) win
ratio, and in this case developers are always free to roll their own equals
methods.
So there's a risk here.
Don't let that stop you though, more people working on this project is good.
…On Thu, Jun 4, 2020, 08:10 Samuel P. ***@***.***> wrote:
Yeap, I thought this idea but this is really implicit, right? if any other
person gives some maintenance in this class is almost impossible to figure
out it @randakar <https://github.com/randakar> .
I thought that we would have the same approach that we do for @tostring
where we can inform the rank number for the field.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#1543 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AABIERJZQX35NIQWT4UMTQLRU43F7ANCNFSM4EI6ENCA>
.
|
@samukce I'm afraid, your benchmark is broken: You've excluded Additionally, the class is not final, so There are other differences like
I'm not a project owner, so I can't decide anything. Anyway, before you start, have a look at #512 discussing the syntax for an annotation joining I guess, you'd like something like I could actually imagine that splitt tests for a field can be better, e.g., like for strings s1 and s2
However, this is most probably nothing for Lombok (too complicated, unsure gain).
Sure, and probably nobody would like the order "(value, name)", especially as it's used also in If I were to hack on Lombok (unfortunately no time), I'd start with
|
FYI, IDEA does similar reordering as a result of https://youtrack.jetbrains.com/issue/IDEA-170178. The issue is still open, but in fact when you take example snippet and generate P. S. however this is not relevant for wrappers, they are not reordered |
@Maaartinus that was a second test that I did but, to compare with that field vs without that field. So, yeah, I agree with the approaches that you proposed. The rank looks the most simple and the flexible option, given then for each case the order can impact differently depending on the business code flow. For instance, I can have one object with 5x int fields and one String, but for instance, I can have this String field 90% changing in the time and the ints fields almost fixed value, so for this case, even primitive firsts what will make difference, in this case, will be the String field first. I will open a PR for the rank idea, and we can see the acceptance. I would like to add this in my project and remove the manual equals method that I needed to add in many different classes. |
@stsypanov it can help you. ;) PR: #2485 |
I've closed this issue, because we now have two improvements:
So everyone get the added performance boost of the primitives, and customization is possible. Regarding primitive wrappers, it's not completely off the table yet. Although we can never be sure that |
Update: primitives default to 1000, "primitive wrappers" to 800, references to 0. The caveat is that the primitive wrapper detection could be off, but then:
|
Consider simple class:
It generates this code:
Then the same code generated by IDEA (for Java 7+):
IDEA-generated code reorders comparison (primitives and wrappers first) yielding better performance for the case when
count
orid
fields are mutually different and we can immediately returnfalse
skipping more complicated comparison of strings and collections.It'd be nice if Lombok could do the same.
The text was updated successfully, but these errors were encountered: