-
Notifications
You must be signed in to change notification settings - Fork 139
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
TreeItem.getItemCount() and TreeItem.getItem(int) have linear complexity on Linux #882
Comments
I have not found a way to make |
…pse-platform#882 On Linux these methods have linear complexity over child count, that causes quadratic complexity for virtual tree navigation.
…pse-platform#882 On Linux these methods have linear complexity over child count, that causes quadratic complexity for virtual tree navigation.
Just wondering, why do we need to query gtk at all? should not SWT/JFace be the one creating items and keep track of the count? |
Indeed GTK Note that on Windows, SWT caches number of items: eclipse.platform.swt/bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Tree.java Lines 3340 to 3348 in eafdfbd
|
Naive caching helps with |
@basilevs what I mean is that SWT itself is creating native items, so how could it be it does not knows (or could know) the number of items or the n-th item... so if the native implementation is to slow we probably should store an array of items on the java side that allows fast retrieval of |
We don't need a whole copy of the model:
|
@laeubi as there no way to detect visible object going out of scope, it is impossible to clean the cache, which means we would store all the objects that had ever been shown indefinetly, which is not much better than whole model (indeed in context of Jface, this cache would have ALL items ever returned by content provider). |
We can avoid cache cleanup problem by only holding children of one item of interest, and repopulating it when interest shifts (Windows implementation does it for its caches). |
TreeItem.getItem(int) had linear complexity, full traversal had quadratic complexity. To alleviate this, we cache the result. Note: this only speeds up breadth-first traversal as cache operates on "item of interest" basis, dropping contents if another item is requested.
I was wrong - efemeral Java TreeItems were never an option - strong references to them are held on all platforms. |
@basilevs as slow Tree performance is a major concern I think it would be great to improve it even if it might be disruptive, if you can prepare things we can merge as soon as master is open and have a full cycle to test so don't worry as long as all tests pass 👍 |
datasets eclipse-platform#882 Test_org_eclipse_swt_widgets_Tree.test_getItemNoGrowth() was failing for virtual trees.
I went with my dumb caching approach and it works for the scenario I'm interested in. It fails to actually make children tracking sensible, in particular, depth-first traversal is slow. I suggest not to close this issue until someone volunteers to rework SWT GTK to actually make |
…-platform#882 As assertion now works with a time require for a single operation, we can't assume that non-constant operation will not fit in 100 ns window.
@SyntevoAlex : any chance you could look at #883 & remark there regarding the "complete" solution? |
Tests have been modified to use time limits instead of fixed iteration count. Now each test takes 7-14 seconds on Mac OS.
I could have a look on wednesday, if I don't forget. |
Any algorithm would be fast on a binary tree due to low count of items in each node. We need a wide tree to break traversal tests.
Wide tree traversal shows performance 4 times worse than optimal on wide trees.
The PR #883 is a failure. I've tested it on original testcase from eclipse-platform/eclipse.platform.ui#649 and the polynomial growth is 1.8 (approximation from three points) which for practical purposes is not different from the original 2.0. I give up for now. Sorry for all the noise! |
An example of ID use case:
Here GTK returns an iterator and we need a TreeItem it corresponds to. As iterator is not a key, Tree has to use additional user data stored natively. |
The ID addressing system associating every TreeItem with an unique key had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
This run PerformanceTests in GitHub actions for pull requests labeled "performance". Note, that the event of labeling itself is not handled. This implementation implies a contributor will have to push something to PR after labeling to start tests.
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…ipse-platform#882 TreeItem and Tree have been checking indexes for bounds during indexed access and traversal. Such checks are slow as node size computation is an O(N) operation. As Tree already does iteration when retrieving a TreeItem by its index, and such iteration detects out-of-bounds problems, preliminary model bounds check is redundant. Also, bounds check is avoidable during iteration over a node - instead of an index, GTK iterator applies directly. Performance improvement proved by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal(). In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 501_378_662ns -> 218_583_468ns 100_000 elements: 52_781_899_817ns -> 20_872_245_796ns (-60%)
This run PerformanceTests in GitHub actions for pull requests labeled "performance". Note, that the event of labeling itself is not handled. This implementation implies a contributor will have to push something to PR after labeling to start tests.
This run PerformanceTests in GitHub actions for pull requests labeled "performance". Note, that the event of labeling itself is not handled. This implementation implies a contributor will have to push something to PR after labeling to start tests.
…ipse-platform#882 TreeItem and Tree have been checking indexes for bounds during indexed access and traversal. Such checks are slow as node size computation is an O(N) operation. As Tree already does iteration when retrieving a TreeItem by its index, and such iteration detects out-of-bounds problems, preliminary model bounds check is redundant. Also, bounds check is avoidable during iteration over a node - instead of an index, GTK iterator applies directly. Performance improvement proved by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal(). In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 501_378_662ns -> 218_583_468ns 100_000 elements: 52_781_899_817ns -> 20_872_245_796ns (-60%)
TreeItem and Tree have been checking indexes for bounds during indexed access and traversal. Such checks are slow as node size computation is an O(N) operation. As Tree already does iteration when retrieving a TreeItem by its index, and such iteration detects out-of-bounds problems, preliminary model bounds check is redundant. Also, bounds check is avoidable during iteration over a node - instead of an index, GTK iterator applies directly. Performance improvement proved by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal(). In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 501_378_662ns -> 218_583_468ns 100_000 elements: 52_781_899_817ns -> 20_872_245_796ns (-60%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
Optional performance tests rely on prebuilt SWT components to be available. `mvn install` is essential for this.
Optional performance tests rely on prebuilt SWT components to be available. `mvn install` is essential for this.
Optional performance tests rely on prebuilt SWT components to be available. `mvn install` is essential for this.
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
Current status: #918 is ready for review. |
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
…tform#882 The ID system tracking association of every TreeItem with GTK model entry had been using GTK.gtk_tree_store_set() to persist a key in GTK model. This operation has linear execution time over model size. IDs were replaced with tree paths and strong references, which, if implemented right, have logarithmic execution time on balanced trees and constant execution time on wide trees. Performance improvement is proven by running org.eclipse.swt.tests.junit.performance.Test_org_eclipse_swt_widgets_Tree.jfaceReveal() In test jfaceReveal[Shape: STAR, virtual: true]: 10_000 elements: 141_061_117ns -> 4_369_889ns 100_000 elements: 10_761_449_641ns -> 181_898_611ns (-98%)
The org.eclipse.swt.widgets.Tree is slow on Linux. In particular
TreeItem.getItemCount()
andTreeItem.getItem(int)
have linear complexity (the time of execution is proportional to the number of children).To Reproduce
Run JUnit test or following snippet:
This test wrapped in a product:
testporduct.zip (sources)
slowGetItem.linux.gtk.x86_64.zip slowGetItem.linux.gtk.aarch64.zip (built product)
Expected behavior
Access time should not depend on the number of items.
Environment:
Version since
Was there always?
Workaround (or) Additional context
Initially reported in eclipse-platform/eclipse.platform.ui#649 Jface algorithms make navigation time proportional to a square of child count due to this problem.
Workaround: eclipse-platform/eclipse.platform.ui#810
GTK returns children count in O(N):
The text was updated successfully, but these errors were encountered: