Choosing the Right Design Pattern for a StopWatch Class

design-patternsrefactoring

I have to measure execution time for a blocks of code. I had implemented simple StopWatch class like http://www.goldb.org/stopwatchjava.html. If I will invoke methods of StopWatch class directly between business logic then my source code became unreadable and unclean.

What design pattern can be useful in my situation to keep code readable and clean?

Best Answer

If you're measuring methods then this is a classic example of cross-cutting concerns that AOP is designed to solve.

My Java is weak, but something like this in C# using PostSharp would work...

Create a ProfileAttribute class that does the profiling and logs it to some log file/database/whatever

public sealed class ProfileAttribute : Attribute
{
    private StopWatch stopWatch;

    public override OnEntry(MethodExecutionArgs args)
    {
        this.stopWatch = new StopWatch();
        this.stopWatch.Start();
    }

    public override OnExit(MethodExecutionArgs args)
    {
        this.stopWatch.Stop();
        /* 
        log(string.Format("[{0}]{1}.{2} took {3}ms", 
            DateTime.Now, 
            args.ClassName, // may not be actual member name, I forget
            args.MethodName, // may not be actual member name, I forget
            stopWatch.Elapsed.TotalMilliseconds));
        */
    }
}

Then, you can attribute any method that you want to profile (without having to clutter up the code too much) just by applying the attribute like so:

[Profile]
public void WatchedMethod()
{
    /* Code */
}

Afterwards, you can check your log(s) and should see something like:

[Jan 1, 2012 00:00:01]MyClass.WatchedMethod took 1.001ms

[Jan 1, 2012 00:00:02]MyClass.WatchedMethod took 1.000ms

[Jan 1, 2012 00:00:03]MyClass.WatchedMethod took 1.002ms

edits

At which point... it makes sense to write a small utility that can pull the data from logs, filter it, and present it in such a way that is usable to you (average the running times, show outlier times, etc.)

Also note that using certain AOP frameworks (maybe AspectJ... not sure) you can also decide what build(s) certain aspects can be built into... ie. you can weave this profile attribute into the debug build, but not weave it into the release build.

Note about runtime performance:

If your weaver is a compile-time weaver, it will inject the aspect's code into your code during the build. Using PostSharp with the example given, the resulting code will be:

private StopWatch stopWatch;

public void WatchedMethod()
{
    this.stopWatch = new StopWatch();
    this.stopWatch.Start();

    /* Code */

    this.stopWatch.Stop();
    /* 
    log(string.Format("[{0}]{1}.{2} took {3}ms", 
        DateTime.Now, 
        args.ClassName, // may not be actual member name, I forget
        args.MethodName, // may not be actual member name, I forget
        stopWatch.Elapsed.TotalMilliseconds));
    */
}
Related Topic