6 Replies Latest reply on Mar 20, 2008 6:43 PM by mars1412

    newbie: h:selectOneMenu performance problem

    mars1412 Apprentice

      I am currently struggling with an issue, I don't understand.


      when I use a selectOneMenu in my page and use the value attribute, it seems like the testBean is created once for each element in the selectItems!
      I hope that I am doing something wrong and that this is not the expected behavior.
      I'll post my code and some comments.


      This is the code in my page


           <h:selectOneMenu value="#{testBean.selectedItem}">
               <f:selectItems value="#{testBean.items}"/>
           </h:selectOneMenu>




      my testbean is simple:


      @Name("testBean")
      @Scope(ScopeType.CONVERSATION)
      @Install(debug = true)
      public class TestBean implements Serializable {
      
           /** The Constant serialVersionUID. */
           private static final long serialVersionUID = 1L;
      
           private static final int NO_OF_SELECT_ITEMS = 200;
      
           @Logger
           Log log;
      
           Integer selectedItem = 7;
      
           public Integer getSelectedItem() {
                System.out.println("getSelectItem called");
                return selectedItem;
           }
      
           public void setSelectedItem(Integer selectedItem) {
                System.out.println("setSelectItem called");
                this.selectedItem = selectedItem;
           }
      
           public List<SelectItem> getItems() {
                System.out.println("get Items called");
                List<SelectItem> selectItems = new ArrayList<SelectItem>(NO_OF_SELECT_ITEMS);
                for (int i = 0; i < NO_OF_SELECT_ITEMS; i++) {
                     selectItems.add(new SelectItem(i, Integer.toString(i) + "xxxx"));
                }
                return selectItems;
           }
      }
      



      when I access the page, the output is like this:


      13:24:10,950 INFO  [DebugObserver] JSF phase: before RENDER_RESPONSE 6
      13:24:10,966 INFO  [STDOUT] get Items called
      13:24:10,966 INFO  [STDOUT] get Items called
      13:24:10,966 INFO  [STDOUT] getSelectItem called
      13:24:10,966 INFO  [STDOUT] getSelectItem called
                   +++++ 198 TIMES !!
      13:24:11,419 INFO  [DebugObserver] JSF phase: after  RENDER_RESPONSE 6




      • why is getSelectItem called 198 times in the render response phase?

      • well calling the simple getter is not the problem, the real problem is, that a testBean instance will be created for each of these calls: from the JBoss server.log, I can see, that between the before and after RENDER_RESPONSE phase, I find the following line for 200 times:



      2008-03-14 13:16:37,555 DEBUG [org.jboss.seam.contexts.Contexts] found in conversation context: testBean



      when I omitt the value attribute:


           <h:selectOneMenu>
               <f:selectItems value="#{testBean.items}"/>
           </h:selectOneMenu>



      I get this output.


      13:30:04,811 INFO  [DebugObserver] JSF phase: before RENDER_RESPONSE 6
      13:30:04,811 INFO  [STDOUT] get Items called
      13:30:04,811 INFO  [STDOUT] get Items called
      13:30:04,826 INFO  [DebugObserver] JSF phase: after  RENDER_RESPONSE 6



      even in this case I don't understand why getItems() is called twice ...

        • 1. Re: newbie: h:selectOneMenu performance problem
          Pete Muir Master

          Martin Trummer wrote on Mar 14, 2008 01:34 PM:


          I hope that I am doing something wrong and that this is not the expected behavior.


          Expected behaviour. See



          • well calling the simple getter is not the problem, the real problem is, that a testBean instance will be created for each of these calls: from the JBoss server.log, I can see, that between the before and after RENDER_RESPONSE phase, I find the following line for 200 times:



          2008-03-14 13:16:37,555 DEBUG [org.jboss.seam.contexts.Contexts] found in conversation context: testBean





          Incorrect analysis, nothing here indicates it is created, just looked up by Seam.

          • 2. Re: newbie: h:selectOneMenu performance problem
            mars1412 Apprentice


            Expected behaviour. See Why does JSF call my getter hundreds of times?

            thanks for the link, but preparing the list is not the problem here (Its only called twice).


            the problem is that


            #{testBean.selectedItem}



            is executed for each element in the list.


            In a real example, the getItems() function could use a list, that is initialized lazily. But what about the get/setSelectedItem()?


            This must be stored on my manager component, which usually extends EntityHome.


            And if the EntityHome instance is "created" for 200 times, it is a performance problem, because these components are usually use quite heavyweight.


            when I said "create" here and in my last post it is no correct. you are right - the component is just looked up and found in the conversation context, BUT:


            after looking up the component in the context it seems that ALL member variables are being set (once for every item in the select list) and after the call, they are set again:


            [org.jboss.seam.contexts.Contexts] found in conversation context: profileEditor
            ..
            Processing event:org.jboss.seam.preSetVariable.profileEditor.categoryIdSelection
            ..
            Processing event:org.jboss.seam.postSetVariable.profileEditor.categoryIdSelection
            ..
            



            So, how could I separate the get/setSelectedItem() functions from my EntityHome()?

            • 3. Re: newbie: h:selectOneMenu performance problem
              Pete Muir Master

              Martin Trummer wrote on Mar 14, 2008 03:37 PM:


              thanks for the link, but preparing the list is not the problem here (Its only called twice).

              the problem is that

              #{testBean.selectedItem}



              is executed for each element in the list.


              Sure, but the explanation is identical ;-)


              And if the EntityHome instance is "created" for 200 times, it is a performance problem, because these components are usually use quite heavyweight.

              when I said "create" here and in my last post it is no correct. you are right - the component is just looked up and found in the conversation context,


              You seem to have answered your own point here.


              BUT:

              after looking up the component in the context it seems that ALL member variables are being set (once for every item in the select list) and after the call, they are set again:

              [org.jboss.seam.contexts.Contexts] found in conversation context: profileEditor
              ..
              Processing event:org.jboss.seam.preSetVariable.profileEditor.categoryIdSelection
              ..
              Processing event:org.jboss.seam.postSetVariable.profileEditor.categoryIdSelection
              ..
              



              Yes. Again, expected behaviour. The overhead of this is low - have you done some profiling to see where your bottleneck is? Or are you guessing?



              So, how could I separate the get/setSelectedItem() functions from my EntityHome()?


              Put it in a POJO and outject the POJO.

              • 4. Re: newbie: h:selectOneMenu performance problem
                mars1412 Apprentice


                have you done some profiling to see where your bottleneck is? Or are you guessing?

                I was just guessing - but until now I got the TPTP profiler running (took me a while though)



                Again, expected behaviour

                Well, not for a newbie like me :)
                Not in my wildest nightmares, I would have expected, that the value expression is evaluated (at least) once for every element in the list.


                <h:selectOneMenu value="#{testBean.selectedItem}">



                Since this is a JSF issue, I won't bother anyone here with questions about this anylonger.
                I think I really need to get a better understanding of JSF in the first place.


                Anyway, here are my profiling results - with my interpretation..


                situation:


                I have a Seam POJO that extends EntityHome and manages a WebUser entity.
                The EntityHome class has a String property selectedTimeZone, which is bound to the value of the selectOneMenu component. Its getter will be invoked once for every item in the selct list.



                The overhead of this is low

                Profiling tells me that one call to getTimeZoneId() takes 0.0092 seconds. Which is quite low.
                BUT: this method is called for 552 times (once for each select item), so it takes about 5 seconds!


                so I created a separate POJO, as you suggested, and this really helps a lot (thanks).
                now getTimeZoneId() takes only 0.0016 seconds: about 1 second in total.


                this is much better (althugh I think that's still way too much for a simple select box)


                I only need to access the new lightweight separate POJO now (instead of the heavyweight EntityHome subclass) - that's why it's faster now.


                But what I don't really understand is this:


                as you have already said, JSF calls getTimeZoneId() once for every item - ok.


                When this happens, Seam will lookup the corresponding bean in the contexts.


                When it finds the bean, I guess (from the following log message), that every variable (inlcuding injections) of the bean is set again:


                Processing event:org.jboss.seam.preSetVariable.profileEditor.categoryIdSelection



                I don't understand this.


                Why do we need to set this again and again? And where do we get the values from?


                I thought these values are stored on the bean, and that the bean object itself is stored in the context: then you would only have to lookup the bean and that's it.


                I think this is a very basic point, that I didn't get: I hope someone can enlighten me

                • 5. Re: newbie: h:selectOneMenu performance problem
                  Pete Muir Master

                  Post some code and so we can see what is going on - I don't know which component that event relates to.

                  • 6. Re: newbie: h:selectOneMenu performance problem
                    mars1412 Apprentice

                    please forget my last question of the preSetVariable stuff.
                    it was another wrong analysis of mine, sorry.


                    BTW: the thread Seam Performance Problem..  is really good and helped me understand what's going on