-
Notifications
You must be signed in to change notification settings - Fork 187
Description
The org.eclipse.swt.widgets.Tree is slow on Linux. In particular TreeItem.getItemCount() and TreeItem.getItem(int) have linear complexity (the time of execution is proportional to the number of children).
To Reproduce
Run JUnit test or following snippet:
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeItem;
public class TreeTest {
private Shell shell = new Shell();
{
shell.setLayout(new FillLayout());
shell.open();
}
public void getItemShouldHaveConstantTime() {
for (int i = 0; i < 1000; i++) {
measureGetItemTime(100); // warmup
}
double elapsed_10 = measureGetItemTime(10);
double elapsed_100000 = measureGetItemTime(100000);
double ratio = elapsed_100000 / elapsed_10;
System.out.printf("Time for 10 elements: %f ns\nTime for 100000 elements: %f ns\nRatio: %f\n",elapsed_10, elapsed_100000, ratio);
}
private long measureGetItemTime(int count) {
Tree tree = createTree();
try {
TreeItem subject = new TreeItem(tree, SWT.NONE);
createChildren(subject, count);
readAndDispatch();
// warmup
for (int i = 0; i < 1000; i++) {
System.nanoTime();
subject.getItem(count - 1);
}
long start = System.nanoTime();
for (int i = 0; i < 10000; i++) {
subject.getItem(count - 1);
}
long stop = System.nanoTime();
long elapsed = stop-start;
return elapsed;
} finally {
tree.dispose();
}
}
private void createChildren(TreeItem subject, int count) {
for (int i = 0; i < count; i++) {
new TreeItem(subject, SWT.NONE);
}
}
private Tree createTree() {
Tree result = new Tree(shell, SWT.NONE);
return result;
}
private void readAndDispatch() {
for (int i = 0; i < 10; i++ ) {
while(shell.getDisplay().readAndDispatch()) {}
}
}
}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:
- Select the platform(s) on which the behavior is seen:
-
- All OS
-
- Windows
-
- Linux
-
- macOS
- Any GTK
- Any JRE
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):
static gint
gtk_tree_store_iter_n_children (GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
GNode *node;
gint i = 0;
g_return_val_if_fail (iter == NULL || iter->user_data != NULL, 0);
if (iter == NULL)
node = G_NODE (GTK_TREE_STORE (tree_model)->priv->root)->children;
else
node = G_NODE (iter->user_data)->children;
while (node)
{
i++;
node = node->next;
}
return i;
}