1 Reply Latest reply on Oct 26, 2010 4:22 AM by noxhoej

    Overhead in SeamELResolver

    noxhoej
      Hi

      I have been profiling my Seam application to find out where it is spending its time. This was done, using the YourKit profiler with CPU sampling (instead of tracing) to minimize the measurement overhead.

      As an example page I have been looking at a "create entity" page, which doesn't load any data from the database.
      On my PC, this page takes 588 ms to process. Of these 588 ms, a whopping 405 ms is used in com.sun.faces.el.FacesCompositeELResolver.getValue(ELContext, Object, Object) which is called 5,423 times.
      Almost all of this time (385 ms) is spent in org.jboss.seam.el.SeamELResolver.resolveBase(ELContext, Object) which will, if the key is not found in the rootNameSpace, cycle through all 18 imported Seam namespaces looking for the requested key. For each namespace, it will try to look up the namespace qualified key through org.jboss.seam.contexts.Contexts.lookupInStatefulContexts(String) (57,738 calls in total).
      According to YourKit, all 385 ms is spent trying to find the key in the ServerConversationContext, because ServerConversationContext.getIdStack() always requests the org.jboss.seam.core.Manager Component through Manager.instance() (to call getCurrentConversationIdStack() on it).
      org.jboss.seam.Component.getInstance(String, boolean, boolean, Object) has a check at the bottom (which should normally never fail - only in case of an erroneous hot-deploy) to see if the found component is of the right class. And all 385 ms is spent in java.lang.Class.isInstance(Object).

      It seems a pity to spend a good 65% of the total request time in a check that should "never" fail :-(
      On the other hand, if ServerConversationContext could cache (at least for the current request) either the idStack or even just the Manager instance, I wouldn't be seeing this overhead.

      I see that Michael Youngstrom has been looking into doing some caching in ServerConversationContext (https://jira.jboss.org/browse/JBSEAM-3655), but ran into some problems with it. But it looks like he was going to cache the actually found obejcts for EL variables, so I am not sure if thoose problems would also be applicable to caching the idStack or the Manager instance?


      On a side note: of the 4,435 keys passed to SeamELResolver.resolveBase(ELContext, Object), 1,300 are found in the rootNamespace, 2,887 are looked for in the imported Seam namespaces, but not found, and only 248 are found in an imported namespace. It looks like we are currently only using 5 of the Seam namespaces:
        org.jboss.seam.international.messages
        org.jboss.seam.core.locale
        org.jboss.seam.international.timeZone
        org.jboss.seam.framework.currentDate
        org.jboss.seam.security.identity

      Is it possible to somehow override (or unimport) most of the imports in Seams own components.xml, as it would of course also help, to have just 5 namespaces to search, instead of 18.


      Most of the time is wasted looking for the 2,887 keys that aren't there. Almost ALL of these keys, are either optional <ui:param> parameters to <ui:include>'d facelets or optional attributes to composition components. In the facelets, these parameters/attributes are accessed with EL (e.g. #{myoptional}, ${! empty myoptional}, #{myoptional == null ? 'default' : myoptional}, or some such) and if the parameter/attribute hasn't been given, EL will start to look for it "all over". Isn't there a way to narrow down the scope to just the parameters/attributes passed to this specific facelet, when you know that this is what you are looking for???

      Regards,
      Nicholas Oxhøj