Hello,
Firstly my setup details: GWT 2.1, SmartGWT 3.0, browser = FireFox 13.0.1
Version lower left corner of dev console: SmartClient Version: 8.2/LGPL Development Only (built 2011-12-05)
Pre-amble:
We have an engine that allows users to build their own UI screen templates and a renderer which currently outputs HTML in line with the screen templates created by the user.
We are in the process of rewriting our renderer to target SmartGWT 3.0, moving rendering to the client in order to take load off the server, amongst other benefits. For this purpose GWT/SmartGWT is a great fit.
When a user builds a screen with a table component, they can configure it to be paginated, or more importantly not, and specify exactly what
is shown in each cell of the row within the table. It should also be noted that we require all rows to be rendered upon
initial table display and so do not use the "incremental rendering" associated with setShowAllRecords(false).
To render the users defined table, i have been using ListGrid with the following configuration:
setShowRecordComponents(true) with setShowRecordComponentsByCell(true)
- to force createRecordComponent to be called for every cell
setShowAllRecords(true);
- to ensure all records are rendered when the table is first displayed
ListGrid.createRecordComponent override
- creating the widget for each cell
However, I have run into an issue regarding rendering performance when overriding ListGrid.createRecordComponent.
I have created a test class below which i hope you will be able to use to reproduce the results i have observed.
The test class contains a ListGrid implementation FxTestTable which switches, via the FxTestTable.useSuper flag, between 2 rendering modes within the createRecordComponent method override:
Mode 1 - a call to super.createRecordComponent
Mode 2 - creating a very simple widget directly and returning it
When running the test class in both modes for different numbers of records i observed the following results:
(adjust numRecords int in TestDS.executeFetch to ammend the test data set size)
Al timings were made manually with a stop watch so not entirely accurate but you get the idea.
100 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.1 ,1.2, 1.2, 1.1, 1.0
Mode 2 (5 runs, time in seconds) = 5.1, 5.0, 5.1, 5.0, 5.0 (approx 5x slower)
200 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.3, 1.4, 1.3, 1.2, 1.3
Mode 2 (5 runs, time in seconds) = 13.0, 13.2, 13.0, 13.1, 13.2 (approx 10x slower)
500 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.9, 2.0, 2.0, 1.9, 2.0
Mode 2 (3 runs, time in mins:seconds) = 1:03, 1:04, 1:04 (approx 30x slower)
1000 records (9 columns)
Mode 1 (5 runs, time in seconds) = 3.0, 3.2, 3.1, 3.0, 3.1
Mode 2 (3 runs, time in mins:seconds) = 4:20, 4:28, 4:02 (approx 80x slower)
2500 records (9 columns)
Mode 1 (5 runs, time in seconds) = 6.8, 7.0, 6.9, 7.2, 7.1
Mode 2 = not tested
(but based on non linear mode 2 performance degrade from 100 through 200, 500 and 1000 records i estimate somewhere around 15 - 20 minutes)
So my questions are.....
Q. Why is returning even a simple widget so much more time consuming than a call to super.createRecordComponent?
Where is this extra time spent? Surely at some point super.createRecordComponent creates the default widget used for a ListGrid cell.
Q. Why does performance degrade non linearly, unlike that observed using mode 1?
ps i have tried upgrading to GWT 2.4 with SmartGWT 3.1p but my timings were almost identical in all data set sizes for mode 2.
Any light you can shed on this will be greatly appreciated. At the moment this is a show stopper for us and our new renderer.
Many thanks
manny31
Firstly my setup details: GWT 2.1, SmartGWT 3.0, browser = FireFox 13.0.1
Version lower left corner of dev console: SmartClient Version: 8.2/LGPL Development Only (built 2011-12-05)
Pre-amble:
We have an engine that allows users to build their own UI screen templates and a renderer which currently outputs HTML in line with the screen templates created by the user.
We are in the process of rewriting our renderer to target SmartGWT 3.0, moving rendering to the client in order to take load off the server, amongst other benefits. For this purpose GWT/SmartGWT is a great fit.
When a user builds a screen with a table component, they can configure it to be paginated, or more importantly not, and specify exactly what
is shown in each cell of the row within the table. It should also be noted that we require all rows to be rendered upon
initial table display and so do not use the "incremental rendering" associated with setShowAllRecords(false).
To render the users defined table, i have been using ListGrid with the following configuration:
setShowRecordComponents(true) with setShowRecordComponentsByCell(true)
- to force createRecordComponent to be called for every cell
setShowAllRecords(true);
- to ensure all records are rendered when the table is first displayed
ListGrid.createRecordComponent override
- creating the widget for each cell
However, I have run into an issue regarding rendering performance when overriding ListGrid.createRecordComponent.
I have created a test class below which i hope you will be able to use to reproduce the results i have observed.
Code:
public class FxTestEntryPoint implements EntryPoint { public static int recordCount = 0; public static int cellRendererCount = 0; public void onModuleLoad() { FxTestTable fxtt = new FxTestTable(); fxtt.setWidth100(); fxtt.setHeight100(); String[] colNames = new String[] {"id","text1","text2","text3","text4","num1","num2","num3","num4"}; ListGridField[] fields = new ListGridField[9]; for (int count = 0; count < 9; count++) { String colName = colNames[count]; String columnLabel = colNames[count]; ListGridField field = new ListGridField(colName, columnLabel); fields[count] = field; } fxtt.setFields(fields); fxtt.setDataSource(new TestDS()); fxtt.draw(); } private class TestDS extends GwtRpcDataSource { public TestDS() { DataSourceField primaryKey = new DataSourceField("id", FieldType.TEXT); primaryKey.setPrimaryKey(true); primaryKey.setHidden(true); addField(primaryKey); String[] colNames = new String[] {"id","text1","text2","text3","text4","num1","num2","num3","num4"}; for (int count = 0; count < 9; count++) { String propertyName = colNames[count]; String columnLabel = colNames[count]; DataSourceField field = new DataSourceTextField(propertyName, columnLabel); addField(field); } } @Override protected void executeFetch(String requestId, DSRequest request, DSResponse response) { int numRecords = 200; recordCount = 0; ListGridRecord[] records = new ListGridRecord[numRecords]; for (int i = 0; i < numRecords; i++) { ListGridRecord rec = new ListGridRecord(); rec.setAttribute("id", "id_" + recordCount); rec.setAttribute("text1", "text1_" + recordCount); rec.setAttribute("text2", "text2_" + recordCount); rec.setAttribute("text3", "text3_" + recordCount); rec.setAttribute("text4", "text4_" + recordCount); rec.setAttribute("num1", "num1_" + recordCount); rec.setAttribute("num2", "num2_" + recordCount); rec.setAttribute("num3", "num3_" + recordCount); rec.setAttribute("num4", "num4_" + recordCount); records[i] = rec; recordCount++; } response.setData(records); processResponse (requestId, response); } protected void executeAdd(String requestId, DSRequest request, DSResponse response) {} protected void executeUpdate(String requestId, DSRequest request, DSResponse response) {} protected void executeRemove(String requestId, DSRequest request, DSResponse response) {} } private class FxTestTable extends ListGrid { private boolean useSuper = false; public FxTestTable() { setAutoFetchData(true); setShowRecordComponents(true); setShowRecordComponentsByCell(true); setShowAllRecords(true); setShowHeader(true); String[] colNames = new String[] {"id","text1","text2","text3","text4","num1","num2","num3","num4"}; ListGridField[] fields = new ListGridField[9]; for (int count = 0; count < 9; count++) { String colName = colNames[count]; String columnLabel = colNames[count]; ListGridField field = new ListGridField(colName, columnLabel); fields[count] = field; } setFields(fields); } protected Canvas createRecordComponent (ListGridRecord record, Integer colNumZeroIndexed) { if (useSuper) { return super.createRecordComponent (record, colNumZeroIndexed); } else { // Output simple widget so that we can compare rendering times with full cell renderer HLayout hl = new HLayout(); hl.setContents("" + cellRendererCount++); return hl; } } } }
Mode 1 - a call to super.createRecordComponent
Mode 2 - creating a very simple widget directly and returning it
When running the test class in both modes for different numbers of records i observed the following results:
(adjust numRecords int in TestDS.executeFetch to ammend the test data set size)
Al timings were made manually with a stop watch so not entirely accurate but you get the idea.
100 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.1 ,1.2, 1.2, 1.1, 1.0
Mode 2 (5 runs, time in seconds) = 5.1, 5.0, 5.1, 5.0, 5.0 (approx 5x slower)
200 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.3, 1.4, 1.3, 1.2, 1.3
Mode 2 (5 runs, time in seconds) = 13.0, 13.2, 13.0, 13.1, 13.2 (approx 10x slower)
500 records (9 columns)
Mode 1 (5 runs, time in seconds) = 1.9, 2.0, 2.0, 1.9, 2.0
Mode 2 (3 runs, time in mins:seconds) = 1:03, 1:04, 1:04 (approx 30x slower)
1000 records (9 columns)
Mode 1 (5 runs, time in seconds) = 3.0, 3.2, 3.1, 3.0, 3.1
Mode 2 (3 runs, time in mins:seconds) = 4:20, 4:28, 4:02 (approx 80x slower)
2500 records (9 columns)
Mode 1 (5 runs, time in seconds) = 6.8, 7.0, 6.9, 7.2, 7.1
Mode 2 = not tested
(but based on non linear mode 2 performance degrade from 100 through 200, 500 and 1000 records i estimate somewhere around 15 - 20 minutes)
So my questions are.....
Q. Why is returning even a simple widget so much more time consuming than a call to super.createRecordComponent?
Where is this extra time spent? Surely at some point super.createRecordComponent creates the default widget used for a ListGrid cell.
Q. Why does performance degrade non linearly, unlike that observed using mode 1?
ps i have tried upgrading to GWT 2.4 with SmartGWT 3.1p but my timings were almost identical in all data set sizes for mode 2.
Any light you can shed on this will be greatly appreciated. At the moment this is a show stopper for us and our new renderer.
Many thanks
manny31
Comment