4 Replies Latest reply on May 25, 2009 9:09 AM by kukeltje.ronald.jbpm.org

    Large Table Performance 2 (Ignore other post)

    gzoller.greg.zoller.aviall.com

      Hello,


      (Sorry for the dupe post--struggled w/forum editor!)


      I am trying to performance-tune a large table. For the purposes of my tuning I created a labs page that populates 1000 rows of trivially simple canned data (no db involved, etc.). It's as basic as I could get. I'll show my code then my performance numbers. I also attempted to follow the tuning guidelines in this article


      Java:


      @Name("orderMgr")
      @Scope(ScopeType.SESSION)
      public class OrderMgr {
       @Out (required=false) private Order order;
       private int count = 1000;
       public OrderMgr() {this.order = new Order(count);}
       public int getCount() {return count;}
       public Order getOrder() {return this.order;}
      }
      



      HTML:


      <rich:dataTable id="table"
           immediate="true"
           cellpadding="0" cellspacing="0" 
           border="0" var="item" value="#{sessionContext.get('order').lines}">
           <rich:column>
                <f:facet name="header">Num</f:facet>
                <h:graphicImage id="lineInvalid" value="/img/invalid.gif"/>
                <h:outputText id="lineNum" value="#{item.number}" />
           </rich:column>
           <!-- other columns here -->
      </rich:dataTable>
      



      Ok, so in FF3 this took about 10.5s to render once primed.  For a comparison I saved the exact same rendered page and loaded it into a browser statically, and this took about 2.5s to render.


      8s is quite a performance tax for something not really doing any logic.  If I understand the article correctly, using an outjected object should avoid the Seam interceptor penalty (or most of it).


      Actually that was really strange.  I read a lot of posts talking about the cost of Seam interceptors.  Turns out I didn't see much of a difference, and I tried @BypassInterceptors on the class, @Out for order, and normal Seam (non-outjected) access for order.  No significant performance difference.  The sample here even shows I told EL what context to look in for the object...any performance gains were insignificant. Any ideas there?


      I'm kinda bummed because my problem seemed so similar to the article using nearly identical technology and the author got huge performance gains and my YSlow needle didn't budge.


      I'd love to hear from anyone who's made headway with this kind of problem.


      Thanks!
      Greg

        • 1. Re: Large Table Performance 2 (Ignore other post)
          dan.j.allen

          I can tell you one thing for sure. If it takes 10 seconds to render a 1000-line table, you still haven't solved your performance problem yet.


          As for the tips in the article, there are a couple of things to remember:



          1. The performance gain for disabling interceptor or circumventing interceptors primarily dealt with conversation-scoped components in Seam 2.0.

          2. In Seam 2.1, the ManagedIdentityInterceptor is disabled by default and therefore you don't have to worry about it.

          3. The ManagedEntityInterceptor only affected conversation-scoped components anyway. To see it degrade performance, the component must have been holding a reference to a large number of managed entities.

          4. I suggest using outjection just so that you are sure that your page is not doing any logic but only rendering prepared data

          5. To see interceptors affect performance, you have to be calling them 1,000 - 10,000 times per page. That is typically used by using the rendered attribute inside of a table column



          If you get the table to render in a reasonable amount of time, then the remainder of the performance gains are really achieved using Ajax.


          My advice to you is to drop some timers around your UI and try to figure out where things are stalling out.

          • 2. Re: Large Table Performance 2 (Ignore other post)
            gzoller.greg.zoller.aviall.com

            Dan,


            Thanks for the response!  This clarifies a lot, especially why my avoidance of interceptors (in this example) didn't yield any performance goodness.


            I've attempted to add timers to see what's going on, specifically a PhaseListener.  Here's the output from that:


            21:10:47,605 INFO  [STDOUT] Phase Id: RESTORE_VIEW 1 View Id:/performance/tables.xhtml Duration:0ms
            21:10:48,953 INFO  [STDOUT] Phase Id: RENDER_RESPONSE 6 View Id:/performance/tables.xhtml Duration:1332ms



            Hmm...nothing helpful here?


            Now it's down to process-of-elimination.  I replaced all my EL w/hard-wired values and got a total page-render time of 2.8s.  Then I went back and tracked render numbers for each field added, noting the deltas:


            (Times shown are the cumulative render-times as each field is added back into the table in-order.)


             1.97s   img/int
             2.62    date (unformatted)
             2.76s   string 
            10.02s   block of 3 h:selectBooleanCheckbox w/labels
            10.27s   int
            10.59s   int
            11.23s   formatted double
            



            Woof!  I think I found my trouble spot:  Something about those check boxes are slow!  Getting rid of them my page time was only 3.7s.  Woohoo!  For 1000 rows I'm happy with that.


            Here's the column code for the check boxes:



            <rich:column>
                 <f:facet name="header">Flags</f:facet>
                 <h:outputLabel for='a' value="A"/>
                 <h:selectBooleanCheckbox id="a" value="#{item.a}">
                      <a4j:support event="onchange" ajaxSingle="true"/>
                 </h:selectBooleanCheckbox>
                 <h:outputLabel for='b' value="B"/>
                 <h:selectBooleanCheckbox id="b" value="#{item.b}">
                      <a4j:support event="onchange" ajaxSingle="true"/>
                 </h:selectBooleanCheckbox>
                 <h:outputLabel for='c' value="C"/>
                 <h:selectBooleanCheckbox id="c" value="#{item.c}">
                      <a4j:support event="onchange" ajaxSingle="true"/>
                 </h:selectBooleanCheckbox>
            </rich:column>



            I did more trials and learned that the a4j:support tags eat about 1s, most likely because of the huge amount of JavaScript Richfaces generates per-widget for this tag.  It's something, but it doesn't explain where the rest of the 7s went.  Until I learn more--no check boxes in my tables!  (and they seemed so harmless...)


            Greg

            • 3. Re: Large Table Performance 2 (Ignore other post)
              dan.j.allen

              Actually, now that you mention it, that makes sense. In the article I talk about how I only put the rows in edit mode when you are editing a row. That helped tremendously...and I was thinking it just had to do with avoiding the evaluation of the rendered attribute. But now that I look at the implementation for the HtmlBasicInputRenderer, the base class for all input renderers, I see that it does a ridiculous amount of work trying to find a converter. So likely that is the source of the penalty you are seeing for using the checkboxes.

              • 4. Re: Large Table Performance 2 (Ignore other post)
                kukeltje.ronald.jbpm.org

                Compliments for finding this. Now I know I have to change my table to have an edit mode for sure like Dan mentions in his reply.