Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [aspectj-users] Performance facts and tips

Here are a few additional comments and additions. I appreciated Wes's description, though we do need good benchmarks.

1) We should be working with a broader group to establish an AOP performance benchmark, rather than just devising an AspectJ one. Of course, this means specifying a problem at a higher level (e.g., the AspectJ solution might use cflow or if and a dynamic AOP one would dynamically deploy an aspect). I suspect some subset of examples from recent books, articles, and papers would be suitable for creating a benchmark like this. Maybe a future article or book could start including performance comparisons...

2) Areas to improve performance of generated code, from inspection on projects I've been involved in. Granted, we did not benchmark the performance cost of these issues:
 a) Allow inter-type declaration of static members, which is most commonly desired for storing a static logger member per class. Today, the best implementation of this is to use a Map in the aspect (which is known to be less efficient).
 b) Defer instantiation of thisJoinPoint in advice where it may not be needed. A common use case of this is in methods that may be enabled or disabled at runtime (e.g., only calculate a value or log something when monitoring or debugging), to avoid the performance penalty of creating thisJoinPoint when the test is false.
 c) Optimize the bytecode generated for this, target and args for interfaces, e.g., this(Interface) && execution(* toString(..)) will add an instanceof test to every toString method compiled. What's odd is that the compiler does optimize for classes (i.e., it only generates test code in cases where the test might succeed).

I also think it would be helpful for the compiler to issue a warning when a programmer writes Derived.method, where Derived inherits method, but doesn't override it; as Jim notes this is a common source of problems.

Ron Bodkin
Chief Technology Officer
New Aspects of Security
m: (415) 509-2895

> ------------Original Message-------------
> From: Jim Hugunin <lists@xxxxxxxxxxx>
> To: aspectj-users@xxxxxxxxxxx
> Cc: "aspectj-dev@xxxxxxxxxxx" <aspectj-dev@xxxxxxxxxxx>
> Date: Mon, Aug-25-2003 9:35 AM
> Subject: Re: [aspectj-users] Performance facts and tips
> 
> Wes Isberg wrote:
> > Below are heuristics for avoiding unnecessary performance
> > overhead in programs using our implementation of AspectJ 1.1.
> 
> A list of performance facts and tips without real examples and 
> benchmarks to back it up can be a dangerous thing.  I find it hard to 
> comment on the details below with first seeing those examples and 
> benchmarks.  I hope that your solicitation for contributions along those 
> lines is sucessful.  Nevertheless, I do have a few specific comments:
> 
> <snip>
> >   o Prefer perthis or pertarget when only using per-instance
> >     state in one aspect with the one master pointcut
> 
> perthis and pertarget have the potential to cause major performance 
> problems if not used extremely carefully.  I would need to see some 
> compelling benchmark data before recommending these to someone for 
> performance reasons.
> 
> >   o Prefer percflow to mapping to Thread or using ThreadLocal
> 
> If you're concerned solely about performance, use ThreadLocal instead of 
> percflow.  percflow ultimately must use ThreadLocal (or a close 
> substitute that works in 1.1) in its implementation, so it is very 
> unlikely to perform better than using ThreadLocal directly.
> 
> I doubt that benchmarks will show much performance difference at all 
> between these approaches, and therefore the decision should be based not 
> on performance but on which will produce the most readable and 
> understandable code.  BTW - This is my suspicion about most performance 
> issues in the absence of benchmarks.
> 
>  >   o Prefer private inter-type declarations to mapping from targets
> 
> I agree with this advice completely, and I think it should probably be 
> worthy of its own message to users or FAQ entry.  The reason that I can 
> say this even without benchmarks is that I believe it will lead to 
> simpler and easier-to-read code that will benefit from static type 
> checking.  I'm also pretty confident that this will have noticable 
> performance benefits, but I wouldn't want to push those too hard without 
> benchmarks to back me up.
> 
> <snip>
> > There's one exception to prefering static forms.  Given Type,
> > a subclass of SuperType, and foo(), defined in SuperType:
> > 
> >  static form:  call(* Type.foo(..))
> >  dynamic form: target(Type) && call(* foo(..))
> 
> This is an important issue that I'm nervous to see showing up in a 
> message about performance tips.  I believe that all users should be 
> strongly encouraged to use the dynamic form here, i.e.:
> 
>    pointcut addToList(): target(ArrayList) && call(* add(*));
> 
> If this form isn't used, the behavior could be very surprising.  For 
> example:
> 
>    List l = new ArrayList();
>    l.add(item):
> 
> The call to add here will not be matched by the simple pointcut "call(* 
> ArrayList.add(*))" because at the call site, the static signature is 
> "List.add(*)".  This is a subtle issue that doesn't match most 
> programmers' model of how method dispatch works in an OO system and can 
> easily be confusing.  The ability to restrict the declaring type of a 
> method in a call-PCD is an advanced feature of AspectJ and it should 
> only be used in rare situations.  Here's one example:
> 
>    declare warning: call(* ArrayList.*(..)):
>      "Should be accessing through List interface";
> 
> There are some compiler limitations that can add further confusion:
> > Some older compilers incorrectly replaced the static reference
> > type of a method invocation with the type of the nearest
> > superclass implementation.  In that case, when weaving
> > binaries generated by older compilers, the method invocation
> > would not be matched by the first/static pointcut, but would
> > be matched by the second/dynamic one.  If it's what the
> > user intended, it could be changed to use the static form
> > 
> >     call(* SuperType.foo(..))
> 
> <dangerous-bend>  If you really know what you're doing, and you want to 
> use a declaring type in a call pcd you can include the root declaring 
> type of the method that you're interested in.  Unless you're doing 
> something special that cares about static signatures like the "declare 
> warning" shown above, then this root declaring type is the only one you 
> should ever use in a call PCD.
> 
> The root declaring type of a method is the upper-most class or interface 
>   in the hierarchy that implements the method.  So, in the example 
> above, you could write:
> 
>    pointcut addToList(): target(ArrayList) && call(* List.add(*));
> 
> This makes it explicit that you're interested in the add method declared 
> by the List interface when implemented by an ArrayList.  Because this 
> uses the top-most type that declares this method you can't run into the 
> kinds of weird static signature issues shown above.
> </dangerous-bend>
> 
> My two cents - Jim
> 
> 
> _______________________________________________
> aspectj-users mailing list
> aspectj-users@xxxxxxxxxxx
> http://dev.eclipse.org/mailman/listinfo/aspectj-users
> 


Back to the top