gwtproject / gwt

GWT Open Source Project
http://www.gwtproject.org
1.52k stars 376 forks source link

Grid widget is very slow #573

Closed dankurka closed 9 years ago

dankurka commented 9 years ago

Originally reported on Google Code with ID 565

GWT Release: 1.3rc1

Detailed description:

When using a Grid of moderate size (say, 100x3 Widgets), it's rather slow -
even if the Widgets are very simple. It continues to slow down as the Grid
gets bigger.

Workaround if you have one:

Using Grid.setText() instead of Grid.setWidget solves the problem, but of
course prevents me from doing things like colour-coding rows for easy-reading.

It looks like FlexTable is also affected, though I've not personally
experienced this one.

Links to the relevant GWT Developer Forum posts:

There's a few discussions on this:

http://groups.google.com/group/Google-Web-Toolkit/browse_frm/thread/7e99851785841187/fa4c0cdc8c5b6a9c?lnk=gst&q=grid+slow&rnum=1#fa4c0cdc8c5b6a9c
http://groups.google.com/group/Google-Web-Toolkit/browse_frm/thread/ebc4bad957e2509b/fa1e4142bd7b6d4c?lnk=gst&q=grid+slow&rnum=2#fa1e4142bd7b6d4c
http://groups.google.com/group/Google-Web-Toolkit/browse_frm/thread/4e2b5db9528d4e29/d9c64fb16403d035?lnk=gst&q=grid+slow&rnum=3#d9c64fb16403d035
http://groups.google.com/group/Google-Web-Toolkit/browse_frm/thread/ac353bd3ea2aeb45/5f53feec7627c180?lnk=gst&q=grid+slow&rnum=4#5f53feec7627c180

Reported by dave.rodgman on 2007-01-03 14:26:36

dankurka commented 9 years ago
Even I faced this issue, when my application displays around 50-60 rows with 13-14 
column. Rendering and especially re-rendering of Grids during refresh takes lots of

time and suddenly CPU usage shoots up, sometimes with a warning on IE saying that 
Javascript is slowing down the browser.

Reported by rahulsinghal on 2007-01-03 19:36:53

dankurka commented 9 years ago

Reported by gwt.team.morrildl on 2007-01-10 16:12:23

dankurka commented 9 years ago
Could one of you post a test case? Using a simple grid of (100,3) with setWidget
gives me times of 300 milliseconds on both FF and IE, using (60,15) gives me times
of
800 milliseconds on both browsers, so I don't think I've captured your problem. 

Reported by gwt.team.ecc on 2007-01-11 12:37:20

dankurka commented 9 years ago
Attached file demonstrates the problem. Updating the table takes seconds!

Reported by mmaterzok on 2007-01-29 11:17:03


dankurka commented 9 years ago
Yes, Even I have faced this problem. I have a dynamic grid being created based on 
the data received. each cell in the grid contains a text box. 
the cell as well as rows have formatting done using the row formatter and cell 
formatter. 
To render the a grid of 25 rows x 18 columns. It takes 9 seconds. CPU is 100%. IE 
gives warnings.
If I comment the setWidget for the textbox (i.e. no textboxes in the cells) it takes

900msecs.

Reported by vivmenon on 2007-01-31 11:26:43

dankurka commented 9 years ago
Code sample: Note (CptCellText extends TextBox)

 public void prepareGrid()
      {
          Window.alert("prepare Grid"); 
          long time =System.currentTimeMillis();
          CellFormatter cellFormatter = this.getCellFormatter();
          List gridColumnObjs = grid.getGridRenderObj().getColumns();
          int rowCount =this.getRowCount();
          int colCount = this.getColumnCount();
          for(int row=0;row<rowCount;row++)
          {
           //   Window.alert("prepare Grid 1"+row);
              Image rowChkBoxOnLoad = new Image(IMAGES_CHECKBOXOFF);
               this.setWidget(row, 0, rowChkBoxOnLoad);  
               cellFormatter.setHeight(row,0,"25");
               cellFormatter.setWidth(row, 0, "26");
               cellFormatter.setStyleName(row, 0, GRID_DATACOLUMN_STYLE);
               cellFormatter.setHorizontalAlignment(row, 0, 
HasAlignment.ALIGN_CENTER);
               cellFormatter.setVerticalAlignment(row, 0, HasAlignment.ALIGN_MIDDLE);
              if (row%2 == 0)
              {
                  this.getRowFormatter().setStyleName(row, GRID_EVENROW_STYLE);
              }
              else 
              {
                  this.getRowFormatter().setStyleName(row, GRID_ODDROW_STYLE);
              }

              CptCellText cellTextField = null;
              for(int col = 1; col<colCount;col++)
              {
               //   Window.alert("In columns" +row+" "+col);
                  DColumn column = (DColumn)gridColumnObjs.get(col-1);
             //     cellFormatter.setHeight(row, col, "25");

                  String columnHref = column.getHref();
                  cellTextField = new CptCellText();
            //      Window.alert("Cceckin href");
                  if(columnHref != null && columnHref.trim().length() > 0)
                  {
                      cellTextField.addClickListener(this);                    
                  }
                  int columnWidth = column.getWidth() + 12; 
           //       Window.alert("1.6");

                  //cellFormatter.setWidth(row, col, Integer.toString(columnWidth));
               //   Window.alert("1.7");
                  cellFormatter.setStyleName(row, col, GRID_DATACOLUMN_STYLE);
              //    Window.alert("1.8");
                  int columnDataType = column.getDataType();
              //    Window.alert("1.9");
                  cellFormatter.setVerticalAlignment(row, col, 
HasAlignment.ALIGN_MIDDLE);     
             //     Window.alert("1.10");
                  if(columnDataType == 1)//----for String Data------Aligned LEFT
                  {                 
                 //     Window.alert("1.11");
                     // cellFormatter.setHorizontalAlignment(row, col, 
HasAlignment.ALIGN_LEFT);                       
                      cellTextField.setWidth(Integer.toString(columnWidth));
                      cellTextField.setTextAlignment(TextBoxBase.ALIGN_LEFT);
                      this.setWidget(row, col, cellTextField);
              //        Window.alert("1.12");            
                  }
                  else if(columnDataType == 2)//---for Numeric Data------ ALIGNED 
RIGHT
                  { 
             //         Window.alert("1.21");
                  //    cellFormatter.setHorizontalAlignment(row, col, 
HasAlignment.ALIGN_RIGHT);               
                      cellTextField.setWidth(Integer.toString(columnWidth));
                      cellTextField.setTextAlignment(TextBoxBase.ALIGN_RIGHT);
                     this.setWidget(row, col, cellTextField);
           //           Window.alert("1.22");
                  }
                  else if(columnDataType == 3)//---for DateTime Data aligned CENTER
                  {
               //       Window.alert("1.31");
                    //  cellFormatter.setHorizontalAlignment(row, col, 
HasAlignment.ALIGN_CENTER);                
                      cellTextField.setWidth(Integer.toString
(columnWidth));                   
                      cellTextField.setTextAlignment(TextBoxBase.ALIGN_CENTER);
                     this.setWidget(row, col, cellTextField);
            //          Window.alert("1.32");
                  }
                  else if(columnDataType == 4)//---for Image Data aligned CENTER
                  {
               //       Window.alert("1.41");
                      //Window.alert("Type = 4, Image and url = "+colData);
                      cellFormatter.setHorizontalAlignment(row, col, 
HasAlignment.ALIGN_CENTER);
                      Image img = new Image();
                      this.setWidget(row, col, img);
               //       Window.alert("1.42");
                  }
                  if (row%2 == 0)
                  {
                      cellTextField.setStyleName
("gridCellEven");                      
                  }
                  else 
                  {
                      cellTextField.setStyleName
("gridCellOdd");                      
                  }

               //   Window.alert("1. loop over");       

              }
          }
          Window.alert("Prepare grid over "+(System.currentTimeMillis()-time));

      }

Reported by vivmenon on 2007-01-31 11:35:52

dankurka commented 9 years ago

Reported by gwt.team.morrildl on 2007-02-12 20:51:40

dankurka commented 9 years ago
Will this bug get fixed. Is it possible to know when this will get fixed? Can I get

a patch?

Reported by vivmenon on 2007-02-21 05:40:03

dankurka commented 9 years ago
Could you post an example using GWT objects only? I can't seem to recreate this and
it looks like you are using a subclass of Grid.

Reported by spaceLenny on 2007-02-21 13:05:38

dankurka commented 9 years ago
its the Grid itself, the widget added to the Grid  CptCellText extends TextBox
DColumn column object basically holds the style, width and the datatype of data that

is addded to the cell. This is used for the sorting function
So what can be done is comment the DColumn calls, and change CptCellText to TextBox

Reported by vivmenon on 2007-02-21 13:37:19

dankurka commented 9 years ago
its the Grid itself, the widget added to the Grid  CptCellText extends TextBox
DColumn column object basically holds the style, width and the datatype of data that

is addded to the cell. This is used for the sorting function
So what can be done is comment the DColumn calls, and change CptCellText to TextBox

Reported by vivmenon on 2007-02-21 13:38:35

dankurka commented 9 years ago
If I comment out all of the DColumn calls, there isn't any code left. :)

But I ran the above example anyway and got Prepare Grid 160... with a 9x9 grid. 

the rendering was almost instantaneous.

Reported by spaceLenny on 2007-02-21 13:57:18

dankurka commented 9 years ago
Even at 150x9 the run time is about 2 seconds - inspecting each of the 1350 cells and
setting style of each row and column as well as creating and attaching 2 widgets.
Even on FF.

I think I may be missing a piece of the problem.

Reported by spaceLenny on 2007-02-21 14:20:36

dankurka commented 9 years ago
A 25 rows * 8 columns takes close to 8 secs. CPU goes up to 100%. I think what you 
can do is run a for loop which does a setWidget(i,j,TextBox) and sets the Cell 
formatting. I color code the rows and also add ClickListener for the cells on which

I want an action to be taken.
On checking the time, the maximum time is take for the setWidget call.

Another observation is it takes less than a second for 10 rows * 8 columns. However

when you render beyond 10 rows there is a visible time lag and CPU jumps up. it 
takes 3 secs for 15 rows, 7-8 secs for 25 rows. 

Reported by vivmenon on 2007-02-21 14:47:07

dankurka commented 9 years ago
Lenny. Also if possible send me your code. I can run it out here and see if there is

any issue with IE maybe.

Reported by vivmenon on 2007-02-21 14:55:31

dankurka commented 9 years ago
Above results were achieved with the following:

TestGrid test = new TestGrid(150,9);
RootPanel.get().add(test);
test.prepareGrid();

Note that the attached file has almost no code in it when DColumn is removed. Also
that the image is just set to "test" right now (can be set to anything).

Reported by spaceLenny on 2007-02-21 17:57:49


dankurka commented 9 years ago
Hey, you missed out one line of code which is causing the problem.
Do this in the for loop
TextBox cellTextField = new TextBox();
this.setWidget(row, col+1, cellTextField);

col+1 is used because the first column is a rowChkBox ie is a image based check box,

SO you start setting the Widgets in the subsequent columns. You might have to adjust

your loop accrodingly so that you dont get a Index out of bounds exception

Reported by vivmenon on 2007-02-22 05:43:33

dankurka commented 9 years ago
Prepare Grid: 2339

It calls setWidget around line 48.

It was in my original test case, I just lost it when i posted the previous source
file as I was cleaning out the commented code. 

Reported by spaceLenny on 2007-02-22 12:17:28


dankurka commented 9 years ago
I took your file added the setWidget code and then ran it. It tool 5-6 secs to 
render and CPU goes to 100%. 

Now if we add some styles and formatting and also add text to it. I am sure the time

will increase. 

Reported by vivmenon on 2007-02-22 12:40:51


dankurka commented 9 years ago
This is interesting. It seems like it has to do with IE specifically.

GWT: 2339
FF2(Mac): 2339
Safari: 1405

I'm not at my work PC, so I can't test this. I will try later today.

Have you tried it in FF on PC or Opera? 

Reported by spaceLenny on 2007-02-22 12:53:04

dankurka commented 9 years ago
Our application is built for IE. GWT 4-5 sec, IE 5 secs. 
In either case instead of a setWidget if you do a setText then its almost immediate.

But a setWidget takes time. In your case also it takes more than 2 secs.

Reported by vivmenon on 2007-02-22 13:01:27

dankurka commented 9 years ago
Ok, I think that the bulk of the time is being spent in the TextBox creation. 

Could you try the attached TestGrid and see if it has any notable change?

Reported by spaceLenny on 2007-02-22 15:34:55


dankurka commented 9 years ago
Any idea when this bug will get fixed? Or do we have to live with it forever?

Reported by vivmenon on 2007-09-12 13:49:55

dankurka commented 9 years ago
The problem is, unfortunately, a very difficult one, here are some of the planned 
mitigations
   a) Lazy hookup of events to make widget hookup faster.
   b) Introduction of incubator scrolling/paging table widget to reduce number of 
widgets in a specific table.
   c) (maybe) introduction of Flyweights as an alternative to full-weight widgets.

Reported by gwt.team.ecc on 2007-10-08 21:03:09

dankurka commented 9 years ago
Need to come back and revisit optimizations in light of advancements in other widgets
 in the incubator, etc.

Reported by bruce+personal@google.com on 2008-04-08 17:01:05

dankurka commented 9 years ago

Reported by sumitchandel+legacy@google.com on 2008-05-02 02:32:22

dankurka commented 9 years ago
The project I am working on has run into this issue.

If I understand the gwt code correctly HTMLTable the base class for grid is using the
various w3c dom methods to create and populate rows. As a proof of concept I created
a widget that removed all of the grid and htmltable's magic and just used  pure DOM.*
calls to create a table. Performed about the same as Grid which makes me wonder if
we
are running into the fact that the DOM manipulation methods are extremely slow in
IE6. Benchmarks can be found here: http://www.quirksmode.org/dom/innerhtml.html

I was able to come up with a very dirty work around that was able to create tables
at
blazingly fast speed. Create a string buffer. manually create the html for your
table/rows/columns. Then use DOM to create a DIV element set the div elements
innerHTML to your buffers toString(). Then again use the DOM to grab the element
object for your table from the DIV. You need to do this to get around a bug in IE6.
It doesnt like you to set the innerHTML of a <table>. Now spawn off a Grid object and
inject your created table element into it.

Yes its dirty. Yes its a hack. But with my proof of concept I was able to spawn a
table with 50,000 cells (1000x50) in a fraction of a second; something that is
unthinkable with the current grid implementation.

Reported by TrashHalo on 2008-05-23 02:32:59

dankurka commented 9 years ago
You are dead-on correct, this is exactly what we are doing with GridBulkRenderer in
the gwt-incubator project. This bug is not closed because the bulk renderer has not
yet made it into gwt trunk.

Reported by ecc%google.com@gtempaccount.com on 2008-05-23 13:33:53

dankurka commented 9 years ago
Hi,
My code has been debugging for... approx 2 hours now and the grid is still drawing
(118*24). That left me time to find this thread.

I confirm the problem really is on the setWidget() call.

Going down to debugging HTMLTable, I can confirm it takes a few seconds for each DOM
method call.
In particular, getRowCount() and cleanCell() were very slow while calling
getDOMRowCount() and getRawElement()

That makes my soft unusable when there are more than 20*20 approx. :-(
TrashHalo, could you provide us with a concrete example on how to do your workaround?

Thanks

Olivier

Reported by olivier.chirouze on 2008-08-22 09:17:07

dankurka commented 9 years ago
As the problem is the underlying speed of the table widget, the BulkRenderer classes
in gwt-incubator is the best solution to this problem. 

Reported by ecc%google.com@gtempaccount.com on 2008-10-02 13:39:57

dankurka commented 9 years ago
This is the same problem I have to with our application report UI. Unfortunately some
users run a report worth 50K rows against 200+ columns, and we need to display those
in the grid. I am contemplating on doing a direct swap of innerhtml() on grid... any
thoughts?

Reported by melvin.ramos on 2009-02-24 18:15:31

dankurka commented 9 years ago
Hello,

Is this issue fixed? If yes, from which version this fix is included?

I am using GWT 1.7.0 and IE6.

Problem:

When I am adding 1500 rows in a Grid, IE6 takes around 8 secs to complete.
code:--- gridObj.setWidget(row, 0, new Label("SomeText"));

Now, If I use some CSS styles for each rows and columns, then IE takes over 1 min to
render.

code:--
getRowFormatter().setStyleName(row, "oddRow");
getRowFormatter().setStyleName(row, "evenRow");
getCellFormatter().setStyleName(row, 0, "border");

Please let me know, if you have a solution/workaround to this issue.

Thanks,
Sabir

Reported by sabimd00 on 2010-07-06 09:55:14

dankurka commented 9 years ago
First: I am on GWT 2.0.4 and IE8/FF3.x

I am trying to display a table with 65x150 cells. The cells content is always 1-2 letters
(later on I'd like to swap the contents with a combobox - but that's not necessary
now). I ran into a similar issue - probably directly related to this one. Using setText
instead of setWidget didn't solve my problem.

I use a FlexTable and simply add those rows and columns. I use an asynchronious action
command and draw it in its execute() method. I assign a css-style using "addStyleName".
No event-handlers are assigned by me (no onClick etc.)

While in Firefox the table is only a bit laggy while it's not fully loaded, IE8 lags
even afterwards. When the table finishes loading its cells, it becomes VERY responsive
in Firefox, but it stays awfully laggy in IE8. The CPU load hits 50% when hovering
over a css-styled row. There are no such issues in Firefox.

However: it doesn't seem that IE8 is totally at fault. At least not because of the
table. I created a simple HTML with a <table>-element and 150 rows as well as 65 columns,
added some styles to it and IE8 displayed the table flawlessly and damn fast.

I am posting here, since I think it's related. Please move to a new topic if it's not.

Thank you for your help in advance :/.

Igor.

Reported by divStar on 2010-09-20 09:23:36

dankurka commented 9 years ago
In my app I noticed that IE8 is actually slower than Ie7. 

I certainly see a lot of lag when adding a mouse-over effect using addStylename.
When I change the background color directly from code the performance is much higher.

Reported by david.nouls on 2010-09-20 11:42:59

dankurka commented 9 years ago
I think it's better to apply CSS styles to those rows only once, and then just use CSS
:HOVER pseudo-class.

Reported by Rafoex on 2010-09-20 13:22:03

dankurka commented 9 years ago
In my app, the Grid is taking time to load next page (each page displaying 10rows *
15 columns). This problem persists only on IE browser; takes 3 secs to load next/previous
page and for other browsers (Firefox, Safari) it loads the page in a flash.

The Grid was working fine with GWT 1.7 until recently we migrated to GWT 2.3.
It contains only labels, checkbox/pushButton.
I even tried removing pushbutton from the Grid but its taking same amount if time.

Any idea why it is taking extra time to load on IE only.

Thanks,
Vivek

Reported by vaxy.dude on 2012-01-11 04:47:07

dankurka commented 9 years ago
This item was closed in Oct2008 so looks like there will be no fix for it. On the other
hand take a look at the CellTable widget which is built specifically for large data
sets.

Reported by vivmenon on 2012-01-11 07:03:33