10 Replies Latest reply on Jul 10, 2008 4:48 AM by Ales Justin

    JBMDR-1; LRU cache impl

    Ales Justin Master

      I started hacking on JBMDR-1:
      - http://jira.jboss.com/jira/browse/JBMDR-1

      In order not to re-invent the wheel, is there some LRU cache impl present 'near' by?

      OK, I know JBossCache has LRU eviction policy, but this would mean dragging whole JBC into bootstrap.

      What about this idea:
      - for the bootstrap phase we have some simple (lru) cache
      - once jbc is present, we switch to jbc's lru

        • 2. Re: JBMDR-1; LRU cache impl
          Ales Justin Master

          Eh, I could type LRU in IDE to get that. :-)
          Thanks.

          But I see it uses plain HashMap to hold entries ...

          From past week :-)

          "adrian@jboss.org" wrote:

          > 1) I don't think we care about if two threads override each others info

          That's not the issue.

          A HashMap can break completely if two threads are updating
          the underlying data structures at the same time.

          This can then cause all sorts of weird behaviour,
          e.g. infinite loops when the broken linked list
          contains links that link to themselves


          I'll make it optional - fixing it in the commons-core.
          Till then synchronizing on access.

          • 3. Re: JBMDR-1; LRU cache impl
            Ales Justin Master

            How to introduce this into MC Kernel?
            The only place where we create (Abstract)MetaDataContext is in BasicKernelMetaDataRepository.
            So having a single entry point is good.
            But the problem is that this BasicKernelMetaDataRepository is instantiated from class name, leaving us with little configuration space.
            e.g. if I wanted to be more flexible on LRU min/max

            • 4. Re: JBMDR-1; LRU cache impl
              Adrian Brock Master

               

              "alesj" wrote:
              How to introduce this into MC Kernel?
              The only place where we create (Abstract)MetaDataContext is in BasicKernelMetaDataRepository.
              So having a single entry point is good.
              But the problem is that this BasicKernelMetaDataRepository is instantiated from class name, leaving us with little configuration space.
              e.g. if I wanted to be more flexible on LRU min/max


              You don't. The cached metadata context is there for people that want
              to programmatically construct the contexts and load from something that is slow
              e.g. If I want to add to the JVM context a metdata loader that loads metadata from a database
              (or do the same thing to more specific contexts inside a deployer)

              Nobody is using the cached version at the moment which was why this issue
              was never very important. ;-)

              • 5. Re: JBMDR-1; LRU cache impl
                Ales Justin Master

                OK, I've prepared the BasicKernelMetaDataRepository to be overridable with caching impl (CachingBasicKernelMetaDataRepository).
                Leaving it up to the user to introduce his real impl/config.

                Should we introduce something ourselves for AS5?

                • 6. Re: JBMDR-1; LRU cache impl
                  Adrian Brock Master

                   

                  "alesj" wrote:
                  Should we introduce something ourselves for AS5?


                  Why? There's little point caching the Memory or the AnnotatedElement loaders
                  which is all we use currently. It'd just be wasted cpu and memory. :-)

                  • 7. Re: JBMDR-1; LRU cache impl
                    Ales Justin Master

                    Just hoping this doesn't turn into YAGNI. :-)

                    • 8. Re: JBMDR-1; LRU cache impl
                      Ales Justin Master

                       

                      "adrian@jboss.org" wrote:

                      Why? There's little point caching the Memory or the AnnotatedElement loaders
                      which is all we use currently. It'd just be wasted cpu and memory. :-)

                      Marko did some investigation, due to the latest AS5 performance complaints on the jboss-dev ml.
                      Due to his results - AbstractMetaDataContext::getComponentMetaDataRetrieval is the biggest hotspot -, I've decided to add caching impls that are part of MDR already, and will work in bootstrap as well.

                      Marko's results on artificial app (100 EJBs, 100 @Local, 100 jsp):
                      21%
                       org.jboss.metadata.plugins.context.AbstractMetaDataContext.getComponentMetaDataRetrieval(Signature) (The method calls itself recursively)
                       org.jboss.metadata.spi.retrieval.MetaDataRetrievalToMetaDataBridge.getComponentMetaData(Signature)
                       org.jboss.aop.Advisor.hasJoinPointAnnotation(Class, Signature, String)
                       org.jboss.aop.Advisor.hasAnnotation(long, Method, String, Class)
                       org.jboss.aop.Advisor.hasAnnotation(Method, String)
                       org.jboss.aop.pointcut.MethodMatcher.classMatchesAll(ClassExpression)
                      
                       org.jboss.aop.pointcut.MethodMatcher.matchesIdentifier(ASTMethod)
                       org.jboss.aop.pointcut.MethodMatcher.matches(ASTMethod)
                      
                      16%
                       java.lang.reflect.Method.toString()
                       org.jboss.aop.metadata.MethodMetaData.getMethodMetaData(Method)
                       org.jboss.aop.metadata.MethodMetaData.hasTag(Method, String)
                       org.jboss.aop.pointcut.MethodMatcher.classMatchesAll(ClassExpression)
                       org.jboss.aop.pointcut.MethodMatcher.visit(ASTAll, Object)
                       org.jboss.aop.pointcut.ast.ASTAll.jjtAccept(PointcutExpressionParserVisitor, Object)
                       org.jboss.aop.pointcut.MethodMatcher.matchesIdentifier(ASTMethod)
                       org.jboss.aop.pointcut.MethodMatcher.matches(ASTMethod)
                       org.jboss.aop.pointcut.MethodMatcher.visit(ASTMethod, Object)
                      
                      10%
                       java.util.regex.Pattern$CharProperty.match(Matcher, int, CharSequence)
                       java.util.regex.Pattern$Curly.match0(Matcher, int, int, CharSequence)
                       java.util.regex.Pattern$Curly.match(Matcher, int, CharSequence)
                       java.util.regex.Matcher.match(int, int)
                       java.util.regex.Matcher.matches()
                       org.jboss.aop.pointcut.ast.ClassExpression.matches(String)
                       org.jboss.aop.pointcut.Util.matchesClassExpr(ClassExpression, Class, Advisor)
                       org.jboss.aop.pointcut.MethodMatcher.matchesClass(ASTMethod)
                       org.jboss.aop.pointcut.FieldMatcher.visit(ASTField, Object)
                      
                      9%
                       java.lang.Class.getMethod0(String, Class[])
                       java.lang.Class.getMethod(String, Class[])
                       org.jboss.metadata.plugins.loader.reflection.AnnotatedElementMetaDataLoader.getComponentMetaDataRetrieval(Signature)
                       org.jboss.metadata.plugins.context.AbstractMetaDataContext.getComponentMetaDataRetrieval(Signature)
                       org.jboss.metadata.spi.retrieval.MetaDataRetrievalToMetaDataBridge.getComponentMetaData(Signature)
                       org.jboss.aop.Advisor.hasJoinPointAnnotation(Class, Signature, String)
                       org.jboss.aop.Advisor.hasAnnotation(long, Method, String, Class)
                       org.jboss.aop.Advisor.hasAnnotation(Method, String)
                       org.jboss.aop.pointcut.MethodMatcher.classMatchesAll(ClassExpression)
                       org.jboss.aop.pointcut.MethodMatcher.matchesIdentifier(ASTMethod)
                      
                      8%
                       org.jboss.aop.pointcut.MatcherStrategy.subtypeOf(Class, ClassExpression, Advisor) (The method calls itself recursively)
                       org.jboss.aop.pointcut.Util.subtypeOf(Class, ClassExpression, Advisor)
                       org.jboss.aop.pointcut.Util.matchesClassExpr(ClassExpression, Class, Advisor)
                       org.jboss.aop.pointcut.MethodMatcher.matchesClass(ASTMethod)
                       org.jboss.aop.pointcut.MethodMatcher.matches(ASTMethod)
                       org.jboss.aop.pointcut.MethodMatcher.visit(ASTMethod, Object)
                       org.jboss.aop.pointcut.ast.ASTMethod.jjtAccept(PointcutExpressionParserVisitor, Object)
                       org.jboss.aop.pointcut.ExecutionMethodMatcher.visit(ASTExecution, Object)
                       org.jboss.aop.pointcut.ast.ASTExecution.jjtAccept(PointcutExpressionParserVisitor, Object)
                       org.jboss.aop.pointcut.MatcherHelper.visit(ASTStart, Object)
                       org.jboss.aop.pointcut.MatcherHelper.matches()
                       org.jboss.aop.pointcut.PointcutExpression.matchesExecution(Advisor, Method)


                      • 9. Re: JBMDR-1; LRU cache impl
                        Adrian Brock Master

                         

                        Marko did some investigation, due to the latest AS5 performance complaints on the jboss-dev ml.
                        Due to his results - AbstractMetaDataContext::getComponentMetaDataRetrieval is the biggest hotspot -, I've decided to add caching impls that are part of MDR already, and will work in bootstrap as well.

                        Marko's results on artificial app (100 EJBs, 100 @Local, 100 jsp):
                        21%
                         org.jboss.metadata.plugins.context.AbstractMetaDataContext.getComponentMetaDataRetrieval(Signature) (The method calls itself recursively)
                         org.jboss.metadata.spi.retrieval.MetaDataRetrievalToMetaDataBridge.getComponentMetaData(Signature)
                         org.jboss.aop.Advisor.hasJoinPointAnnotation(Class, Signature, String)
                         org.jboss.aop.Advisor.hasAnnotation(long, Method, String, Class)
                         org.jboss.aop.Advisor.hasAnnotation(Method, String)
                         org.jboss.aop.pointcut.MethodMatcher.classMatchesAll(ClassExpression)
                        
                         org.jboss.aop.pointcut.MethodMatcher.matchesIdentifier(ASTMethod)
                         org.jboss.aop.pointcut.MethodMatcher.matches(ASTMethod)
                        



                        What makes you think caching will improve this, I think you'll find it makes it worse

                        * It would only improve things if the same classes (and hence the same methods)
                        are getting reused a lot (not a common case)
                        * It would add extra work to the other cases

                        But as with all performance issues, the key thing is to measure it and analyze it.

                        The real first step (rather than blindly introducing caching) is to look for
                        at getComponentMetaData(Retrieval) and MethodMatcher to understand
                        why it is a hotspot (probably lots of calls to MethodMatcher?) and then
                        try to understand how it can be optimized (which means digging into the methods
                        to determine where it is spending the time).


                        • 10. Re: JBMDR-1; LRU cache impl
                          Ales Justin Master

                           

                          "adrian@jboss.org" wrote:

                          What makes you think caching will improve this, I think you'll find it makes it worse

                          You are right. :-)
                          I tried this on AS5_trunk, and like you said, it even got a bit slower.

                          But it still doesn't hurt to have this impl present. ;-)
                          Someone might actually have a real use-case for it, hitting a lot of the same data. Hence using that out-of-the-box.
                          Or even our new mdr-cache project. :-)