-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
8302818: Optimize wrapper sets and immutable sets of Enums #12498
Conversation
👋 Welcome back yuantj! A progress list of the required criteria for merging this PR into |
Just curious, how does this enum set change affect the performance of construction of regular sets via Set.of calls? |
On the JBS there's https://bugs.openjdk.org/browse/JDK-8145048 which appears to fit your changes. |
See |
I only enhanced |
src/java.base/share/classes/java/util/ImmutableCollections.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/util/ImmutableCollections.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/util/ImmutableCollections.java
Outdated
Show resolved
Hide resolved
Just took a peek again. Besides the critical error of not throwing IAE for duplicate inputs (which you should probably add new test cases for), I think the 2 implementations share the same |
src/java.base/share/classes/java/util/ImmutableCollections.java
Outdated
Show resolved
Hide resolved
src/java.base/share/classes/java/util/JumboEnumSetCompatible.java
Outdated
Show resolved
Hide resolved
@liach Thanks for reviewing. I've fixed the issues you've mentioned. |
Have you submitted an issue at https://bugreport.java.com/bugreport/ ? It will show up a few days later on the JBS. If not, I can create an issue on the JBS for you too as long as you provide a prompt. |
No I haven't. Submit one for me please. Thanks! |
Webrevs
|
result.addAll(c); // optimized for compatible sets | ||
} else { | ||
while (i.hasNext()) | ||
result.add(i.next()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we just use addAll in all cases?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why the original code didn't use addAll
, so I didn't change it. 😂
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder why the original code didn't use
addAll
, so I didn't change it. 😂
It seems to be okay to use addAll
in all cases. Do we need extra test cases for this?
It seems to be okay to use `addAll` in all cases.
@yuantj This pull request has been inactive for more than 4 weeks and will be automatically closed if another 4 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
I'm wary of the impact of adding new wrapper classes. It may make the factory methods slightly slower due additional checks, but also risks increasing the number of classes at various call-sites which might upset call site inlining. An alternative design which would avoid adding more classes could be to add package-private accessors to the existing |
Another alternative, in cases where |
Thanks again for reviewing. Correct me if I'm wrong. @cl4es I need to add these new wrapper classes @pavelrappo |
The interface WrapperCollection {
Collection<?> getBacking();
} and thus: interface RegularEnumSetCompatible {
static RegularEnumSetCompatible tryConvert(Collection<?> coll) {
if (coll instanceof RegularEnumSetCompatible compat) return compat;
if (coll instanceof WrapperCollection wrap) return tryConvert(wrap.getBacking());
return null;
}
} Adding extra |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, in JEP 441, there is pattern matching support for different enums implementing one interface in one switch, see the enum constants section there. I wonder how useful this is, and how often do we have interfaces with more than one enum implementations (e.g. StandardOptions/ExtendedOptions)
@Stable | ||
final long[] elements; | ||
|
||
@Stable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless
implements Serializable permits ImmutableRegularEnumSet, ImmutableJumboEnumSet { | ||
static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess(); | ||
|
||
@Stable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless
@jdk.internal.ValueBased | ||
static final class ImmutableRegularEnumSet<E extends Enum<E>> extends AbstractImmutableEnumSet<E> | ||
implements RegularEnumSetCompatible<E>, Serializable { | ||
@Stable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Useless
If this level of complexity is indeed needed to get whatever improvement you're after then I don't see how this can be worth its weight. Microbenchmarking might help support your case here, but assessing the potential performance costs from gradually increasing the number of classes floating around at various call sites in arbitrary applications is hard. Thus it is something we need to be very careful not to do without solid evidence. |
I have deleted `{Regular,Jumbo}EnumSetCompatible` interfaces and introduced some package-private methods in `AbstractCollection`. This avoids rarely-used checks from static factories in `Collections` and does not reduce much performance compared against the previous implementation.
I have deleted |
Mailing list message from - on core-libs-dev: Hello Stuart Marks, would you be able to take a look at this patch, On Mon, Feb 20, 2023 at 9:40?PM Tingjun Yuan <duke at openjdk.org> wrote: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Immutable*ESIterator.lastReturned*
fields can be made into locals of Immutable*ESIterator::next()
, as the only reason those fields exist in RegularEnumSet.EnumSetIterator
and JumboEnumSet.EnumSetIterator
is to support Iterator::remove()
, which is not a valid operation on immutable enum sets:
|
||
private final class ImmutableRESIterator implements Iterator<E> { | ||
long unseen = elements; | ||
long lastReturned = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
long lastReturned = 0; |
public E next() { | ||
if (unseen == 0) | ||
throw new NoSuchElementException(); | ||
lastReturned = unseen & -unseen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastReturned = unseen & -unseen; | |
long lastReturned = unseen & -unseen; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastReturned = unseen & -unseen; | |
long lastReturned = Long.lowestOneBit(unseen); |
More descriptive. Same for below.
long lastReturned = 0; | ||
int lastReturnedIndex = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
long lastReturned = 0; | |
int lastReturnedIndex = 0; |
lastReturned = unseen & -unseen; | ||
lastReturnedIndex = unseenIndex; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
lastReturned = unseen & -unseen; | |
lastReturnedIndex = unseenIndex; | |
long lastReturned = unseen & -unseen; | |
int lastReturnedIndex = unseenIndex; |
I agree with Claes here in my skepticism of the usefulness of this sort of change. It seems like it's adding lots of complexity. In addition, it also seems like there's a lot of churn in the design. I'd suggest returning this PR to draft status until it can be determined that there's a clear, net improvement. |
@cl4es @stuart-marks Thanks for reviewing and commenting. I'm converting this PR to draft until I finish evaluating whether these changes are necessary or not. |
@yuantj This pull request has been inactive for more than 8 weeks and will be automatically closed if another 8 weeks passes without any activity. To avoid this, simply add a new comment to the pull request. Feel free to ask for assistance if you need help with progressing this pull request towards integration! |
@yuantj This pull request has been inactive for more than 16 weeks and will now be automatically closed. If you would like to continue working on this pull request in the future, feel free to reopen it! This can be done using the |
Currently, the two subclasses of
java.util.EnumSet
optimize bulk operations when the argument is also aEnumSet
, but there is no such optimization for wrapper sets (returned byCollections.unmodifiableSet
,Collections.synchronizedSet
, etc.) and immutable sets (returned bySet.of
methods) ofEnum
s.This PR introduces optimization classes for these situations. No public APIs are changed.
Progress
Issue
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/12498/head:pull/12498
$ git checkout pull/12498
Update a local copy of the PR:
$ git checkout pull/12498
$ git pull https://git.openjdk.org/jdk.git pull/12498/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 12498
View PR using the GUI difftool:
$ git pr show -t 12498
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/12498.diff
Webrev
Link to Webrev Comment