Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-dev] Performance Issues when exposing context from Annotations

Hi Oliver,
yes, you are writing to the right mailing list.

3 seconds against 49 is quite shocking, but I can confirm getting 4 seconds against 22 on my machine, which is wrong anyway. I'm using AspectJ 1.6.6, compile time weaving, inside Eclipse with AJDT.

I also tried rewriting your pointcuts a bit :

public pointcut loggedMethod() : execution(@Log * *(..));
public pointcut log(Log log): loggedMethod() && @annotation(log); public pointcut log2(): loggedMethod() && !cflowbelow(loggedMethod());

this makes log and log2 two completely different pointcut "hierarchies", making it easier to test them out one by one.

Also, cflowbelow(log(Log)) could cause a second context extraction (very useful for the wormhole pattern), that could make things go slower.

However, it did not change the results, still getting 3/4 seconds against 22/23.

I removed the cflowbelow part completely, just to test only the context extraction part :

   public pointcut loggedMethod() : execution(@Log * *(..));
   public pointcut log(Log log): loggedMethod() && @annotation(log);

Dynamic annotation :

       before(): loggedMethod() {
Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class); log.message();
       }
       after() returning: loggedMethod() {
Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class); log.message();
       }


Annotation as parameter :

       before(Log log): log(log) {
           log.message();
       }
       after(Log log) returning: log(log) {
           log.message();
       }

And yes, the first one takes 2/3 seconds, the second one 22/23 seconds.

Raising the number of cycles from 1 milion to 10 milion still results in 20 seconds agains 200 seconds, so a 1:10 ratio anyway.

I checked that both matched correctly, obtained the same number of calls to advice, checked that "log" was there and no other optimization was taking place (also sent to output log.message()).

Using javap on SampleProgram I can see that AspectJ weaves these isntructions :

  49:  ldc     #1; //class tests/SampleProgram
  51:  ldc     #92; //String calc
  53:  iconst_0
  54:  anewarray       #74; //class java/lang/Class
57: invokevirtual #78; //Method java/lang/Class.getDeclaredMethod:(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;
  60:  ldc     #71; //class tests/Log
62: invokevirtual #84; //Method java/lang/reflect/Method.getAnnotation:(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;
  65:  checkcast       #71; //class tests/Log
68: invokevirtual #91; //Method tests/Intercept.ajc$afterReturning$tests_Intercept$2$74fc38c9:(Ltests/Log;)V

Which, in plain java, are :

Log l = SampleProgram.class.getDeclaredMethod("calc").getAnnotation(Log.class);

If I change

Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class);
To

Log log = SampleProgram.class.getDeclaredMethod("calc").getAnnotation(Log.class);

I obtain 23/24 seconds also with dynamic annotation lookup.

So the problem is the suboptimal way used by AspectJ when weaving @annotation(log).

I raised the bug https://bugs.eclipse.org/bugs/show_bug.cgi?id=296484 , and given you credit for the discovery.

Simone

Oliver Hoff wrote:
Hello,

At first: If I am posting on the wrong list, I am sorry for that. I didnt got used to mailing lists so far. (yeah computer science young generation loves fancy Web2.0 communication tools)

I recently started to play around with AspectJ and tried an aspect based generic logging example, where "log context configuration" (when and what should be logged) is specified within annotations. While I had no problems to get the example running, I have done some performance testing. While its definitly possible that I have messed with some "opimization guideline", maybe you will find the following test case interesting.

Log Annotation:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
    String message() default "";
}

Test program:
public class SampleProgram {
    public static void main(String[] args) {
        System.out.println(System.getProperties());
        run();
    }
    @Log(message="Outer")
    public static void run() {
        for(int i = 0; i < 1000000; i++) calc();
} @Log(message="Inner")
    public static void calc() {
        for(int i = 0; i < 10; i++) Math.exp(i);
    }
}

Testaspect 1:
import org.aspectj.lang.reflect.MethodSignature;
public aspect Logging {
public pointcut log(): execution(* *(..)) && @annotation(Log); public pointcut log2(): log() && !cflowbelow(log());

    before(): log() {
Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class);
        log.message();
} before(): log2() { System.out.println("[" + System.currentTimeMillis() + "] [S " + thisJoinPointStaticPart.getSignature().getName() + "]"); } after() returning: log() { Log log = (Log) ((MethodSignature) thisJoinPointStaticPart.getSignature()).getMethod().getAnnotation(Log.class);
        log.message();
} after() returning: log2() { System.out.println("[" + System.currentTimeMillis() + "] [F " + thisJoinPointStaticPart.getSignature().getName() + "]");
    }
}

Testaspect 2:
public aspect Logging2 {
public pointcut log(Log log): execution(* *(..)) && @annotation(log); public pointcut log2(): log(Log) && !cflowbelow(log(Log));

    before(Log log): log(log) {
        log.message();
} before(): log2() { System.out.println("[" + System.currentTimeMillis() + "] [S " + thisJoinPointStaticPart.getSignature().getName() + "]"); } after(Log log) returning: log(log) {
        log.message();
} after() returning: log2() { System.out.println("[" + System.currentTimeMillis() + "] [F " + thisJoinPointStaticPart.getSignature().getName() + "]");
    }
}

Testcase 1 output: (3 seconds execution time) (JIT on)
{
java.runtime.name=Java(TM) SE Runtime Environment,
java.runtime.version=1.6.0_07-b06,
java.vm.version=10.0-b23,
java.vm.vendor=Sun Microsystems Inc.,
java.vm.name=Java HotSpot(TM) Client VM,
java.vm.specification.version=1.0,
java.class.version=50.0,
java.version=1.6.0_07,
java.specification.version=1.6,
sun.arch.data.model=32,
... and more ...
}
[1259542706359] [S run]
[1259542709390] [F run]

Testcase 2 output: (49 seconds execution time) (JIT on)
{ ... same as above ... }
[1259542981187] [S run]
[1259543029781] [F run]

Testcase without aspects: round about 2 seconds

As far as I have noticed the second example is the "right" way to access the information of an annotation, but it is more expensive than the first dynamic access.

I hope that helps somehow and again if this is wrong place or information provided is useless, I am sorry for wasting your time.

Mit freundlichen Grüßen (Sincerely)
Oliver Hoff
_______________________________________________
aspectj-dev mailing list
aspectj-dev@xxxxxxxxxxx
https://dev.eclipse.org/mailman/listinfo/aspectj-dev


--
Simone Gianni            CEO Semeru s.r.l.           Apache Committer
http://www.simonegianni.it/



Back to the top