The need for performance metrics and comparison
Since we released AW 1.0, and more generally for every release of any AOP / interceptor framework (AspectJ, JBoss AOP, Spring AOP, cglib etc), a question is always raised: "what is the performance cost of such an approach ?", "how much do I loose per method invocation when an advice / interceptor is applied ?".
This is indeed an issue that needs to be carefully addressed, and that in fact has affected the design of every mature enough framework.
We are probably all scared by the cost of the java.lang.reflect despite its relative power, and usually, even before starting to evaluate semantics robustness and ease of use in general - we start doing some hello world bench.
We have started AWbench for that purpose. Offering a single place to measure the relative performance of AOP / interceptor framework, and even measure it by your own.
More than providing performance comparison, AWbench is a good place to figure out the semantics differences and ease of use of each framework. A simple "line of count" metrics could be provided as well (source + external file like xml + Ant glue).
Current results
AWBench (ns/invocation) |
aspectwerkz |
aspectwerkz_1_0 |
aspectj |
jboss |
spring |
dynaop |
cglib |
ext:aopalliance |
ext:spring |
ext:aspectj |
|---|---|---|---|---|---|---|---|---|---|---|
before |
10 |
480 |
10 |
135 |
526 |
320 |
70 |
NA |
40 |
10 |
before, static info access |
30 |
490 |
25 |
130 |
515 |
305 |
NA |
NA |
35 |
NA |
before, rtti info access |
45 |
511 |
50 |
140 |
521 |
305 |
NA |
NA |
35 |
NA |
after returning |
15 |
NA |
10 |
NA |
NA |
320 |
80 |
NA |
40 |
15 |
after throwing |
3414 |
5378 |
2999 |
4902 |
NA |
6789 |
8061 |
NA |
NA |
3475 |
before + after |
20 |
480 |
20 |
160 |
520 |
315 |
70 |
NA |
35 |
20 |
before, args() primitives |
10 |
556 |
10 |
195 |
601 |
370 |
140 |
NA |
205 |
NA |
before, args() objects |
10 |
545 |
10 |
185 |
NA |
345 |
105 |
NA |
NA |
NA |
before, args() target() |
10 |
591 |
10 |
220 |
NA |
2513 |
140 |
NA |
NA |
NA |
around, static info access |
60 |
475 |
10 |
130 |
465 |
315 |
75 |
65 |
60 |
90 |
around, rtti info access |
70 |
506 |
50 |
140 |
486 |
310 |
NA |
NA |
70 |
NA |
around x 2, args() target() |
75 |
490 |
25 |
130 |
671 |
4581 |
NA |
75 |
75 |
NA |
AWBench (relative %) |
aspectwerkz |
aspectwerkz_1_0 |
aspectj |
jboss |
spring |
dynaop |
cglib |
ext:aopalliance |
ext:spring |
ext:aspectj |
|---|---|---|---|---|---|---|---|---|---|---|
before |
100 |
4800 |
100 |
1350 |
5260 |
3200 |
700 |
NA |
400 |
100 |
before, static info access |
100 |
1633 |
83 |
433 |
1716 |
1016 |
NA |
NA |
116 |
NA |
before, rtti info access |
100 |
1135 |
111 |
311 |
1157 |
677 |
NA |
NA |
77 |
NA |
after returning |
100 |
NA |
66 |
NA |
NA |
2133 |
533 |
NA |
266 |
100 |
after throwing |
100 |
157 |
87 |
143 |
NA |
198 |
236 |
NA |
NA |
101 |
before + after |
100 |
2400 |
100 |
800 |
2600 |
1575 |
350 |
NA |
175 |
100 |
before, args() primitives |
100 |
5560 |
100 |
1950 |
6010 |
3700 |
1400 |
NA |
2050 |
NA |
before, args() objects |
100 |
5450 |
100 |
1850 |
NA |
3450 |
1050 |
NA |
NA |
NA |
before, args() target() |
100 |
5910 |
100 |
2200 |
NA |
25130 |
1400 |
NA |
NA |
NA |
around, static info access |
100 |
791 |
16 |
216 |
775 |
525 |
125 |
108 |
100 |
150 |
around, rtti info access |
100 |
722 |
71 |
200 |
694 |
442 |
NA |
NA |
100 |
NA |
around x 2, args() target() |
100 |
653 |
33 |
173 |
894 |
6108 |
NA |
100 |
100 |
NA |
Introducing AWbench
Summary
AWbench is a micro benchmark suite, which aims at staying simple. The test application is very simple, and AWbench is mainly the glue around the test application that applies one or more very simple advice / interceptor of the framework of your choice.
AWbench comes with an Ant script that allows you to run it on you own box, and provide some improvement if you know some for a particular framework.
What is the scope for the benchmark?
So far, AWbench includes method execution pointcuts, since call side pointcuts are not supported by proxy based framework (Spring AOP, Cglib, dynAOP etc).
The awbench.method.Execution class is the test application, and contains one method per construct to bench. An important fact is that bytecode based AOP may provide much better performance for before advice and after advice, as well as much better performance when it comes to accessing contextual information.
Indeed, proxy based frameworks are very likely to use reflection to give the user access to intercepted method parameters at runtime from within an advice, while bytecode based AOP may use more advanced constructs to provide access at the speed of a statically compiled access.
The current scope is thus:
For method execution pointcut
Construct |
Contextual information access |
Notes |
|---|---|---|
|
|
|
before advice |
none |
|
before advice |
static information (method signature etc) |
|
before advice |
contextual information accessed reflectively |
Likely to use of casting and unboxing of primitives |
before advice |
contextual information accessed with explicit framework capabilities |
Only supported by AspectJ and AspectWerkz 2.x |
|
|
|
after advice |
none |
|
after returning advice |
return value |
|
after throwing advice |
exception instance |
|
|
|
|
before + after advice |
none |
|
|
|
|
around advice |
optimized |
AspectJ and AspetWerkz 2.x provides specific optimizations (thisJoinPointStaticPart vs thisJoinPoint) |
around advice |
non optimizezd |
|
|
|
|
2 around advice |
contextual information |
|
By accessing contextual information we means:
- accessing a method parameter using its real type (i.e. boxing and unboxing might be needed)
- accessing a the advised instance using its real type (i.e. casting might be needed)
A pseudo code block is thus likely to be:
Which AOP and Proxy frameworks are benched?
The following are included in AWbench:
Bytecode based frameworks
Framework |
URL |
|---|---|
AspectWerkz 1.0 |
http://aspectwerkz.codehaus.org |
AspectWerkz 2.x |
http://aspectwerkz.codehaus.org |
AspectJ (1.2) |
http://eclipse.org/aspectj/ |
JBoss AOP (1.0) |
http://www.jboss.org/developers/projects/jboss/aop |
Proxy based frameworks
Framework |
URL |
|---|---|
Spring AOP (1.1.1) |
http://www.springframework.org/ |
cglib proxy (2.0.2) |
http://cglib.sourceforge.net/ |
dynaop (1.0 beta) |
https://dynaop.dev.java.net/ |
Moreover, AWbench includes AspectWerkz extensible AOP container that allow to run any Aspect / Interceptor framework within the AspectWerkz 2.x runtime:
AspectWerkz extensible AOP container running |
Notes |
|---|---|
AspectJ |
|
AOP Alliance |
http://aopalliance.sourceforge.net/ |
Spring AOP |
|
AWbench is extensible. Refer to Contributing to add a framework.
