0 Replies Latest reply on May 5, 2009 12:22 PM by jaikiran pai

    Expensive calls to getDeclaredMethods while creating joinpoi

    jaikiran pai Master

      While working on performance improvement of EJB3 deployments (EJBTHREE-1800), i have been seeing that most of the time is spent in AOP (ex: finding annotations, creating interceptor chains etc...).

      The sample app that i am trying is 100 EJBs with 100 methods each. (The performance degrades drastically as the number of methods increases)

      One of the issues relates to the way a joinpoint for a method is created
      Here's the flow:

      - (AOP) Interceptor chain for EJB containers is created
      - While the chain is being created, the corresponding AspectFactory are created

      protected Object createBean(ClassLoader cl) throws Throwable
       {
       ClassLoader loader = cl;
       if (loader == null)
       loader = Configurator.getClassLoader(classLoader);
       BeanInfo info = null;
       if (bean != null)
       info = configurator.getBeanInfo(bean, loader, accessMode);
      
       Joinpoint joinpoint = configurator.getConstructorJoinPoint(info, constructor, null);
      
      ....//blah blah blah
      
       invokeLifecycle("create", create, info, loader, result);
       invokeLifecycle("start", start, info, loader, result);
      
       return result;
       }
      

      The invokeLifecycle tries to call the create() and start() methods if any:
      protected void invokeLifecycle(String methodName, LifecycleMetaData lifecycle, BeanInfo info, ClassLoader cl, Object target) throws Throwable
       {
       if (lifecycle == null || lifecycle.isIgnored() == false)
       {
       String method = methodName;
       if (lifecycle != null && lifecycle.getMethodName() != null)
       method = lifecycle.getMethodName();
       List<ParameterMetaData> parameters = null;
       if (lifecycle != null)
       parameters = lifecycle.getParameters();
       MethodJoinpoint joinpoint;
       try
       {
       joinpoint = configurator.getMethodJoinPoint(info, cl, method, parameters, false, true);
       }
      ...// blah blah
      

      The calls goes to AbstractKernelConfigurator.getMethodJoinPoint:
       public MethodJoinpoint getMethodJoinPoint(BeanInfo info, ClassLoader cl, String name, List<ParameterMetaData> parameters, boolean isStatic, boolean isPublic) throws Throwable
       {
       return Configurator.findMethod(info, cl, name, parameters, isStatic, isPublic);
       }
      

      The findMethod ultimately leads to this implementation in org.jboss.joinpoint.plugins.Config
      public static MethodInfo findMethodInfo(ClassInfo classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict) throws JoinpointException
       {
      
      ...// blah blah
      
       MethodInfo result = locateMethodInfo(current, name, paramTypes, isStatic, isPublic, strict);
       if (result != null)
       return result;
       current = current.getSuperclass();
       }
      


      The implementation for locateMethodInfo looks unnecessarily expensive:
      private static MethodInfo locateMethodInfo(ClassInfo classInfo, String name, String[] paramTypes, boolean isStatic, boolean isPublic, boolean strict)
       {
       MethodInfo[] methods = classInfo.getDeclaredMethods();
       if (methods != null)
       {
       for (int i = 0; i < methods.length; ++i)
       {
       if (name.equals(methods[ i].getName()) &&
       equals(paramTypes, methods[ i].getParameterTypes()) &&
       (strict == false || (methods[ i].isStatic() == isStatic && methods[ i].isPublic() == isPublic)))
       return methods[ i];
       }
       }
       return null;
       }
      

      This locateMethodInfo is passed with the method name and params, so any specific reason why it needs to get all the declared methods and then do a equals on them instead of using the other API on ClassInfo which accepts the method name and params:

      MethodInfo getDeclaredMethod(String name, TypeInfo[] parameters);


      The current implementation leads to a performance degradation when the number of methods increases (All this piece of code is trying to do is find a couple of methods named create() and start()).