Skip to main content

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

Wes,

Just a quick not from an implementer.  We have found that with the 1.0
version does add overhead albeit it minimal (5 to 10 ms if I remember
correctly).  We arrived at this number by running our application with
approximately 500 concurrent users running for 5 hours in our performance
testing lab during off hours.

What we did was replace duplicate lines (think Template Pattern) in our data
access layer with one consistent aspect via the execution point cut.  The
major thing that the before and after advice perform is start/stop a timer.
My guess is that the overhead we experience (again minor in nature and not
enough to stop production of this aspect) is mostly likely related to us
needing to utilizing "thisJoinPointStaticPart".  The reason we utilize this
is that our timing mechanism needs the class name
[jp.getSignature().getDeclaringType().toString()] and signature
[jp.getSignature().getName()].  This is necessary to properly identify the
current timing operation because we they are happening simultaneously.

So my question back is this the type of information you are looking for?

Thanks,

Ron DiFrango


-----Original Message-----
From: Wes Isberg [mailto:wes@xxxxxxxxxxxxxx] 
Sent: Friday, August 22, 2003 8:53 PM
To: aspectj-users@xxxxxxxxxxx
Cc: aspectj-dev@xxxxxxxxxxx
Subject: [aspectj-dev] Performance facts and tips


Below are heuristics for avoiding unnecessary performance overhead in
programs using our implementation of AspectJ 1.1.

- Are they right?

- Is anyone interested in writing better examples?
   Or in writing code to quantify the effects?

- Are there other heuristics?

Results from this discussion will go at least into the FAQ,
and perhaps into the programming guide or fixes for 1.1.X/1.2.

I also want to know what the standards are for a good AspectJ program so
that we can ask whether there are cases where the performance of a good
AspectJ program built with our implementation is not on par with an
equivalent solution written by hand in Java or implemented with an
alternative AOP framework. Any experience reports on that point are also
welcome!

Thanks -
Wes

-------- Heuristics
As with any performance heuristic, use these only if profiling shows you
have a problem and only if they don't change the semantics of your program
in bad ways.

---- writing pointcuts

o Prefer static to dynamic pointcuts

The dynamic pointcut designators are if(), this(), target(), args(), cflow()
and cflowbelow().

The compiler/weaver can resolve static pointcuts, so there is no cost at
runtime to determine whether advice should run. The static pointcuts do mean
something different, so they should only be used when they're correct.

Examples:
   - within(..) v. this(..)
   - withincode(..) v. cflow(..)
   ...


o Restrict the scope of dynamic pointcuts with static pointcuts

You can limit the cost of determining whether advice should run by
restricting the points at which the dynamic test is run.

Examples:
   - call(void run()) && target(Foo)
   - within(com.company.app..*) && printingCalls()


o Restrict wildcarded pointcuts

Some wildcarded pointcut match a great many join points,
e.g., "call(* *(..))".  Used alone, this is rarely what's intended.


o Change the code to be more susceptible to pointcuts

Sometimes it's possible and easier to refactor the target code to write a
better pointcut; this can avoid dynamic tests.


---- writing advice

o Prefer thisJoinPointStaticPart (or neither) to thisJoinPoint

Using thisJoinPoint involves some runtime reflection.


o Prefer binding variables with target(), args() or this()
   to using thisJoinPoint.getArgs()

For the same reason as above...


o Prefer after returning to after

"after" advice is more costly than "after returning";
in most cases, users actually intend "after returning".


o Avoid {re}calculating things where possible

This is straight Java, but can have a lot of impact in advice that runs
frequently.

Examples:
   - deferring String concatenation until use
   - using lazy construction
   - caching results...


---- writing inter-type declarations

o Avoiding maps

Maps can be used to associate state with a particular instance or thread.
AspectJ provides inter-type member declarations and "per" aspects that can
do (and optimize) the same associations, avoiding the hashing or the
downcasts in your code.

   o Prefer perthis or pertarget when only using per-instance
     state in one aspect with the one master pointcut

   o Prefer private inter-type declarations to mapping from targets

   o Prefer percflow to mapping to Thread or using ThreadLocal

---- writing aspects

o Prefer default (issingleton) aspects, other things being equal


---- comment

Most of these heuristics are not worth saying without
more compelling examples.

I'm actually not sure that maps are always worse, but I've
seen bad code that uses maps when the AspectJ form was faster and clearer.
It may have just been unnecessary complexity.

The advice heuristics reduce the runtime work done by preferring cheaper
alternatives; they're mostly straight Java.

The pointcut heuristics should reduce runtime costs
(and make compiles faster) by more strictly specifying the
join point shadows specified (or not) by the static pointcut designators.
The dynamic pointcut designators are if(), this(), target(), args(), cflow()
and cflowbelow().

However, the dynamic checks should be efficient:

- this(), target() and args() are implemented by 'instanceof'
   checks, which have been optimized in most modern VM's

- cflow() and cflowbelow() are comparable to using ThreadLocal's

- if() is arbitrarily expensive, depending on the code invoked.

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(..))

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(..))


_______________________________________________
aspectj-dev mailing list
aspectj-dev@xxxxxxxxxxx http://dev.eclipse.org/mailman/listinfo/aspectj-dev
 
**************************************************************************
The information transmitted herewith is sensitive information intended only
for use by the individual or entity to which it is addressed. If the reader
of this message is not the intended recipient, you are hereby notified that
any review, retransmission, dissemination, distribution, copying or other
use of, or taking of any action in reliance upon this information is
strictly prohibited. If you have received this communication in error,
please contact the sender and delete the material from your computer.


Back to the top