Bug 1890 - Task List View performance problem (1G9VFMK)
Summary: Task List View performance problem (1G9VFMK)
Status: RESOLVED FIXED
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 2.0   Edit
Hardware: All Windows NT
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Ian Petersen CLA
QA Contact:
URL:
Whiteboard:
Keywords: performance
Depends on:
Blocks:
 
Reported: 2001-10-10 22:21 EDT by Erich Gamma CLA
Modified: 2002-05-30 20:18 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Erich Gamma CLA 2001-10-10 22:21:39 EDT
EG (2/28/01 8:44:40 PM)
	building a project with many errors (> 1000) takes several minutes
	due to the bad task list update performance.

	This problem is severe, when self hosting you can easily create
	a workbench with many errors.

NOTES:

NE (3/5/01 6:08:45 PM)
	Problem is that TableViewer updates are O(N), resulting in O(N^2) performance for N marker additions.
	Should optimize TableViewer.

	In the meantime, try changing TaskListContentProvider.processDelta() to:

/**
 * Process a resource delta.  Updates the TaskList viewer with any
 * relevant marker changes.
 */
protected void processDelta(IResourceDelta delta) {

	//gather all marker changes from the delta
	List additions = new ArrayList();
	List removals = new ArrayList();
	List changes = new ArrayList();
	getMarkerDeltas(delta, additions, removals, changes);

	//update the viewer based on the marker changes.
	if (removals.size() + additions.size() + changes.size() > 0) {
		// Just do a complete refresh for now if there are any changes to markers.
		fViewer.refresh();
	}
}

EG (3/6/01 7:38:46 PM)
	It is only a marginal improvement. Without the patch 35s with the patch 30s.
	My test case is to load JavaUI Plugin project into an empty workspace and build.

NE (03/06/01 3:14:07 PM)
	Did some timings on a text resource with 1000 tasks, in VA/Java.
	Full refresh took ~25 seconds.

	getSortedChildren(getRoot): 6025ms

	For an item at the start, the timings were:
		TableViewer.doUpdateItem(widget, element, true): 21.4 ms
		  - just getting text and image from label provider, without setText(), getImage() or setImage(): 0.9ms
		  - difference: 20.5ms

	For an item at the end, the timings were:
		Table.getColumnCount(): 0.5ms
		Table.indexOf(TableItem): 0.5ms
		TableItem.setText(column, text): 3.4ms
		TableItem.setImage(column, image): 1.9ms
		TableViewer.doUpdateItem(widget, element, true): 28.1ms
		  - just getting text and image from label provider, without setText(), getImage() or setImage(): 6.9ms
		  - difference: 21.2ms

	The reason getText() and getImage() take longer for the item at the end is that
	MarkerManager.findMarkerInfo() is O(N) in the number of markers on a resource.
	See 1GA6OQT: ITPCORE:WIN2000 - Marker access performance can be improved

	But there's still ~20ms per item accounted for just in setting the text and image on the TableItem,
	which accounts for ~20 seconds of the above 25, just in talking to SWT.

	Most performance problems in the task view will have to be addressed by improving incremental
	updates in TableViewer, where there is a lot of room for improvement.
	However, basic refresh, e.g. when toggling filters, will still take a long time, unless major improvements
	are made to SWT.  It may not even be possible due to OS widget performance.

	As an example of what optimizations are possible in SWT, I tried optimizing TableItem.setText(String[])
	and using it in doUpdateItem().  It improved the time for doUpdateItem() from 28ms to 17.5ms.
	But this is still slow when there are many items.
	Even basic redrawing of the Table widget a few seconds when there are this many entries.

SN (3/7/01 10:51:50 AM)
	Here is the code for TableViewer.doUpdateItem ():

protected void doUpdateItem(Widget widget, Object element, boolean fullMap) {
	if (widget instanceof TableItem) {
		TableItem item = (TableItem) widget;
	
		// remember element we are showing
		if (fullMap) {
			associate(element, item);
		} else {
			item.setData(element);
			mapElement(element, item);	
		}
	
		IBaseLabelProvider prov = getLabelProvider();
		ITableLabelProvider tprov = null;
		ILabelProvider lprov = null;
		if (prov instanceof ITableLabelProvider) {
			tprov = (ITableLabelProvider) prov;
		}
		else {
			lprov = (ILabelProvider) prov;
		}
		int columnCount = table.getColumnCount();
		String[] texts = new String[columnCount];
	    TableItem ti = (TableItem) item;
		for (int column = 0; column < columnCount; column++) {
			// Similar code in TableTreeViewer.doUpdateItem()
			String text = "";
			Image image = null;
			if (tprov != null) {
				text = tprov.getColumnText(element, column);
				image = tprov.getColumnImage(element, column);
			}
			else {
				if (column == 0) {
					text = lprov.getText(element);
					image = lprov.getImage(element);
				}
			}
			texts[column] = text;
			// Apparently a problem to setImage to null if already null
			if (image != null || ti.getImage(column) != null) {
				ti.setImage(column, image);
			}
		}
		ti.setText(texts);
	}
}

SN (3/7/01 10:52:28 AM)
	Here is a benchmark based on the above code:

import com.ibm.swt.*;
import com.ibm.swt.widgets.*;
import com.ibm.swt.graphics.*;
import java.io.*;

public class PR_1G9VFMK {

public static void main(String[] args){
	
	/* Set up */
	int rows = 1000, columns = 4;
	Display display = new Display ();
	Shell shell = new Shell();
	Table table = new Table(shell, SWT.NULL);
	table.setHeaderVisible (true);
	table.setBounds (10, 10, 400, 200);
	shell.open();
	for(int i = 0; i < columns; i++){
		TableColumn column = new TableColumn(table, 0);
		column.setWidth (64);
	}
	TableItem [] items = new TableItem [rows];
	for(int i = 0; i < rows; i++){
		items [i] = new TableItem(table, SWT.NULL);
	}
	Image image = new Image (display, 16, 16);
	GC gc = new GC (image);
	gc.setBackground (display.getSystemColor (SWT.COLOR_RED));
	gc.fillRectangle (image.getBounds ());
	gc.dispose ();
	String text = "Hello";
	
	/* Benchmark */
	long start_time = System.currentTimeMillis();
	for(int x = 0; x < rows; x++){
		Widget widget = items [x];
		if (widget instanceof TableItem) {
			TableItem item = (TableItem) widget;	
//			// remember element we are showing
//			if (fullMap) {
//				associate(element, item);
//			} else {
//				item.setData(element);
//				mapElement(element, item);	
//			}
//		
//			IBaseLabelProvider prov = getLabelProvider();
//			ITableLabelProvider tprov = null;
//			ILabelProvider lprov = null;
//			if (prov instanceof ITableLabelProvider) {
//				tprov = (ITableLabelProvider) prov;
//			}
//			else {
//				lprov = (ILabelProvider) prov;
//			}
			int columnCount = table.getColumnCount();
			String[] texts = new String[columnCount];
			TableItem ti = (TableItem) item;
			for (int column = 0; column < columnCount; column++) {
				// Similar code in TableTreeViewer.doUpdateItem()
//				String text = "";
//				Image image = null;
//				if (tprov != null) {
//					text = tprov.getColumnText(element, column);
//					image = tprov.getColumnImage(element, column);
//				}
//				else {
//					if (column == 0) {
//						text = lprov.getText(element);
//						image = lprov.getImage(element);
//					}
//				}
				texts[column] = text;
				// Apparently a problem to setImage to null if already null
				if (image != null || ti.getImage(column) != null) {
					ti.setImage(column, image);
				}
			}
			ti.setText(texts);
		}
	}	
	long end_time = System.currentTimeMillis();
	long elapsed = end_time - start_time;
	
	System.out.println("Columns="+columns+ " Rows=" + rows);
	System.out.println("Timed: "+elapsed+"ms");
	while (!shell.isDisposed ()) {
		if (!display.readAndDispatch ()) display.sleep ();
	}
	image.dispose ();
}
}

SN (3/7/01 1:57:37 PM)
	The results on J9, P2-400-128M:

Columns=4 Rows=1000
Timed: 2850ms

SN (3/7/01 2:49:53 PM)
	Need to try the above code on VA/Java

EJP/SN (3/7/01 3:06:26 PM)
	Under JDK - P3-300 - 256M
		Columns=4 Rows=1000
		Timed: 1161ms.

	Under VAJ (same machine)
		Columns=4 Rows=1000
		Timed: 11927ms

EJP (03/07/01 03:29:58 PM)
	Under VAJ Linux
		Columns=4 Rows=1000
		Timed: 72075ms

KR (3/8/01 4:43:26 PM)
	Linux, emulated  Table on Windows:
	J9 - P3-550-256M
		Columns=4 Rows=1000
		Timed: 16213ms
 	on Linux:
		Timed: 20702ms

	Windows, native Table (same setup):
		Columns=4 Rows=1000
		Timed: 2504ms

	SWT for Linux is > 20% slower.
	Linux Table needs to be 85% faster just to achieve same performance as Windows 
	native widget (which apparently is still not good enough).

	Note: Benchmarks are without JIT

KR (3/9/01 4:59:09 PM)
	Released new SWT code. Performance as follows (without JIT).
	J9 - P3-550-256M Windows (emulated Table):
	Columns=4 Rows=1000
	Timed: 1943ms

	J9 - P3-550-128M Linux:
	Columns=4 Rows=1000
	Timed: 2111ms
	
	With JIT on Windows (emulated Table):
	Columns=4 Rows=1000
	Timed: 280ms

	With JIT on Linux:
	Columns=4 Rows=1000
	Timed: 640ms
Comment 1 Kevin Haaland CLA 2002-01-21 19:53:58 EST
It would be great if there was a benchmark for this case. Randy, does your 
student have time to write one?
Comment 2 Kevin Haaland CLA 2002-05-30 20:18:16 EDT
Improvements were made by the Java Core team to generate fewer errors. In 
addition, the TaskList now has a limit to the number of tasks it will display.