-
Notifications
You must be signed in to change notification settings - Fork 171
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
AnnotationModel uses inefficient iteration over map #892
Comments
AnnotationModel.cleanup(boolean, boolean) iterates over map with keyset iterator and does lookup for every value from iterator. With ~10_000 annotations this is not fun anymore. Similar code in other places. That can be improved by using entryset iterator. See https://github.com/eclipse-platform/eclipse.platform.text/issues/21
AnnotationModel.cleanup(boolean, boolean) iterates over map with keyset iterator and does lookup for every value from iterator. With ~10_000 annotations this is not fun anymore. Similar code in other places. That can be improved by using entryset iterator. See https://github.com/eclipse-platform/eclipse.platform.text/issues/21
This reverts commit db6a3b4 because this change may cause inconsistent model state in case of parallel operations on the annotations map (key set iterator was working on a snapshot, but entry set is not). See discussion on eclipse-platform#22
The patch that was merged in 4.24 was reverted in 4.25 M1 due possible MT issues. In order to fix that properly, a new IAnnotationMap2 interface is needed which provides "safe" entrySetIterator() over the map, and AnnotationModel should check if the (internal) IAnnotationMap used allows "fast" iteration or not. I do not plan to work on this, feel free to take over. |
Hi all, First of all I agree that the current implementation could be improved, but I just can't really grasp how severe the problem is. I did some simple testing (see below) and it looks "good enough" for me. Maybe you could provide some reference values to compare with to help size this issue? How I tested
My observations
My environmentMachine
sdk.product
|
We face some performance problems in JDT which are also related to the I have two question to better understand and maybe fix this issue. Maybe @iloveeclipse you still have some further insights, even though you do not plan to work on the issue?
Thanks in advance for following up on the issue! |
@HeikoKlare even if lookup is constant it takes a constant time (in the described case 10.000 x C), while iterating using entryset would perform the iteration+lookup in one step with only the overhead of creating Entry objects (if they are not already entries). This can even be improved by using |
That's true, it would definitely be more efficient. I was just wondering whether that improvement would be noticable since everything else done with a single annotation during |
Just put this file (rename it to java) to java project, let generate it "huge" Java file and move generated file to the source folder. After that, open it in Java editor and try to fix compilation error by opening find/replace dialog and replace all On Linux it freezes for me for ~30 seconds. With this patch applied wait time reduced to ~15 seconds. Unfortunately the patch is not thread safe / breaking AnnotationModel contract, see discussion on eclipse-platform/eclipse.platform.text#22 Note, this is purely platform UI issue, eclipse-jdt/eclipse.jdt.ui#677 doesn't change anything here. Update |
Perfect, thank you very much for sharing the information for reproduction @iloveeclipse! |
Introduced new IAnnotationMap2 interface that overrides default forEach() to synchronize on lock object. This halves iteration time spent in cleanup() on huge annotation models. Fixes eclipse-platform#892
Please check #980 |
Thank you both for the input! I will take a look at it and report back. |
Introduced new IAnnotationMap2 interface that overrides default forEach() to synchronize on lock object. This halves iteration time spent in cleanup() on huge annotation models. Fixes eclipse-platform#892
AnnotationMap will overrides default forEach() to synchronize on lock object and AnnotationModel will use that method to iterate over map instead to iterate over keys id possible. This halves iteration time spent in cleanup() on huge annotation models. Fixes eclipse-platform#892
AnnotationModel.cleanup() will lock on the map while iterating over map and iterate via forEach() instead to iterate over keys if possible. This halves iteration time spent in cleanup() on huge annotation models. Fixes eclipse-platform#892
I took a look at the performance using the steps described above and I noticed the following:
Regarding point number 3., I will run the sampler again once #980 is merged and see if there are some other potential improvements that can be applied. |
AnnotationModel.cleanup() will lock on the map while iterating over map and iterate via forEach() instead to iterate over keys if possible. This halves iteration time spent in cleanup() on huge annotation models. Fixes #892
Yes please. In my old (internal) notes I saw search/replace code would also hang in:
|
So, I ran the same search-and-replace operation with the improved version from this PR and this a snapshot from the sampling: My observations
I also noticed that but I haven't had time to pursue it. I'll look into it this week and report back :-) |
You have my attention :) |
So I tried changing the if (mapLock == null) {
...
} else {
synchronized (mapLock) {
// get the ones where the position is null
annotations.entrySet().parallelStream()//
.filter(e -> e.getValue() == null)//
.forEach(e -> deleted.add(e.getKey()));
// get the ones where the position is deleted
annotations.entrySet().parallelStream()//
.filter(e -> e.getValue() != null)//
.filter(e -> e.getValue().isDeleted)//
.forEach(e -> deleted.add(e.getKey()));
}
} As you can see, the I'd say the trick didn't perform as expected so I would leave this one out. |
Any chance to share more information about the s&r that you do there? How many open editors? How many hits? How big is the file / are the files? Anything that allows to reproduce these numbers? |
Sure thing! It's just the generated Java file with 12K inner classes (see previous comment from Andrey), I have only 4 editors open, a bunch of projects and compilation errors in my WS and I'm replacing This is how it looks like: |
Please note that your current implementation, even if executed in parallel might give better performance if you make your parallel stream unordered (I assume order does not really matter here). Beside that I'm not sure why iterating the stream twice should be faster than one iteration using |
Another thing: Instead of adding it with for each you can collect the stream into a list/set what also has optimizations in parallel mode. |
I'd assume the forEach is no longer measurable in isolation with 100k annotations present. The loop in the FindReplaceDialog.replaceAll seems to perform an awful lot of UI work instead of replacing all matches and working with annotations only once. |
AnnotationModel.cleanup(boolean, boolean)
iterates over map with keyset iterator and does lookup for every value from iterator. With ~10_000 annotations this is not fun anymore. Similar code in other places. That can be improved by using entryset iterator.I plan to push the fix after eclipse-platform/eclipse.platform.text#19 is done.
The text was updated successfully, but these errors were encountered: