"In-flght" profiling with AOP
A while ago Frans Bourma wrote about a mind-opening experience which he experienced during a talk Dr. Kersten Krab Thourup gave on performance metrics. Kersten spoke about using AOP to instrument an application during development, and keeping the profiling capability in depolyed software to cater for profiling "in-flight" software.
Even if you jump through hoops to make your test enviroments behave like the production environment, you will experience performance challenges in production from time to another. Kersten had written an AOP-based framework to allow fine-grained performace metrics to be retrieved from a live production system at any time. As Frans points out, this is an excellent example of where AOP fits within an enterprise application. In the Java-space, AOP is a mature design concept and it has been used for performance profiling many times before. Ron Bodkin has written a great article on using the open-source monitoring framework Glassbox with AspectJ and Java Management Extensions (JMX).
Since I've experienced the same challenges, I decided to write my own little profiling framework using Aspect#. The framework is very simple compared with Ron's, but it serves its purpose.
Methods are adviced with perfomance instrumentation as an around advice. This advice tracks the total execution time for the target, the targets immediate callers and how many times the target has been invoked.
Below is a example of performance metrics extracted from Castle's TimeTracking demo. (Click on the image to enlarge)
The sample only shows a fraction of the metrics that was gathered during the session, but it should be sufficient to give you an idea of the kind of data that is collected and how it can be used. The pivot table shows an hierachical structure of the instrumented assembies, the instrumented types and most important the instrumented methods. Performance statistics are shown for every method. A list of callers of the instrumented method is shown below the method statistics.
There are some limitations to what methods can be advised by the framework. This is the reason why the report shown above is more coarse-grained than a similar report created with a conventional profiling tool would be. This is due to the limitations on how runtime AOP can be achieved in .NET. Aspect# is used in combination with the Castle Windsor / MicroKernel, but which types finally get advised depends on a number of factors. First, advised types should be resolved through the Windsor container as shown below.
IWindsorContainer container=new WindsorContainer(new XmlInterpreter());
MyComponent component=container[typeof(MyComponent)];
If you’re not using Castle for dependency injection you can also explicitly apply advice using the Aspect# aspect engine.
AppDomainConfigurationBuilder cfg = new AppDomainConfigurationBuilder();
AspectEngine engine = cfg.Build();
component=(MyComponent) engine.WrapClass(typeof(MyComponent));
It is preferable to use the container to instrument your types because this allows you to apply advice in a more transparent manner. Below is the configuration need to instrument the TimeTracking application.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
<section name="insight" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />
</configSections>
<insight>
<components>
<component id="sessionPersister" service="Insight.ISessionPersister, Insight" type="Insight.Persisters.XmlFilePersister, Insight">
<parameters>
<path>c:\Temp\</path>
</parameters>
</component>
</components>
</insight>
<castle>
<facilities>
<facility id="aspectsharp" type="Castle.Facilities.AspectSharp.AspectSharpFacility, Castle.Facilities.AspectSharp">
<![CDATA[
import Insight in Insight
interceptors [ "instrumentation" : InstrumentationInterceptor ]
aspect InstrumentationAspect for System.Object
pointcut method|property(*)
advice(InstrumentationInterceptor)
end
end
]]>
</facility>
</facilities>
<components>
<!--- Component definitions eluded for brevity -->
</components>
</castle>
</configuration>
The important part of the configuration file is the Aspect# facility declaration. Aspect# uses a Ruby-like language to configure aspects and apply pointcuts. In this example I’m using a catch-all strategy to instrument as many operations as possible. This is done by advising every type that inherits from System.Object and using a wildcard (*) to match any method or property. Please refer to the Aspect# documentation for more information on the aspect definition language.
Even when you use a catch-all strategy, not all types will receive advice. Aspect# uses Castle’s Dynamic Proxy to apply advice to types at runtime. This framework is capable of proxying both interfaces and concrete classes, and these have different behaviors. If you’ve defined a service that implements an interface in your container and you resolve this interface, the Aspect# facility will inject an interface proxy between the client and the service. Because an interface proxy is capable of intercepting calls to any method or property on the target, the target will be fully instrumented.
If you define a component as a concrete class, the methods which receive advice depends upon the design of the class. Because class-proxying leverages subclassing to proxy a type, only virtual members will be advised. If the target is a sealed class, no methods can be advised.
My current performance profiling framework is very simple compared to “real” profiling tools like JetBrains DotTrace. I’ve chosen to keep the framework simple for two reasons. I want to keep the amount of data collected to a minimum to avoid bloated session logs, and I wanted the framework to have minimal impact on the performance of the instrumented application. The code for the framework is available for download here.