Bug 296484 - [annotations] performance problem with @annotation(x) context extraction.
Summary: [annotations] performance problem with @annotation(x) context extraction.
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: Compiler (show other bugs)
Version: unspecified   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 1.6.7   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2009-11-30 10:34 EST by Simone Gianni CLA
Modified: 2009-12-01 15:33 EST (History)
1 user (show)

See Also:


Attachments
Sample project, provided by Oliver Hoff, demonstrating the performance problem (4.09 KB, application/octet-stream)
2009-11-30 10:36 EST, Simone Gianni CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Simone Gianni CLA 2009-11-30 10:34:01 EST
User-Agent:       Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.0.5) Gecko/2009010218 Gentoo Firefox/3.0.5
Build Identifier: 20090619-0625 AspectJ 1.6.6

Thanks to Oliver Hoff for reporting this.

When @annotation(x) is used to extract an annotation in a pointcut, AspectJ weaves the following code :

   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 uses getDeclaredMethod to find the current method. 

If however the @annotation(x) is not used, and the annotation is extracted inside the advice using 

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

this is 10 times faster than the code produced by AspectJ.

This makes using @annotation a performance problem, while it could probably be optimized in two ways :
- Use thisJoinPointStaticPart to make it a performance-equivalent
- Annotation could even be cached and reused, without calling getAnnotation every time, to make it even more efficient.


Reproducible: Always

Steps to Reproduce:
1. See attached sample project
2. Comment/uncomment the two advices in Intercept.aj
Comment 1 Simone Gianni CLA 2009-11-30 10:36:13 EST
Created attachment 153350 [details]
Sample project, provided by Oliver Hoff, demonstrating the performance problem
Comment 2 Andrew Clement CLA 2009-11-30 12:21:26 EST
Yes, when I looked at the generated code last night I came to the same conclusion as Simone.  This stuff hasn't been reviewed since first being added in 1.5.0.

Caching the annotation seems the best option for now.
Comment 3 Andrew Clement CLA 2009-11-30 12:39:49 EST
Just found this tag in the AspectJ source :D

// OPTIMIZE cache result of getDeclaredMethod and getAnnotation?
Comment 4 Simone Gianni CLA 2009-11-30 13:01:22 EST
:D
Comment 5 Andrew Clement CLA 2009-11-30 16:03:43 EST
Changes are in to cache, it is quicker, but it is not as quick as the syntax for binding the string directly (see bug 296501).

Numbers for 1,000,000 iterations:

Manually fetching annotation with getAnnotation(): 645ms
Binding annotation with @annotation(Marker): 445ms (was > 20seconds)
Binding annotation value with @annotation(Marker(message)): 3ms
Comment 6 Andrew Clement CLA 2009-12-01 15:33:45 EST
fixed