Perf4J and Object Creation/Destroy

Posted by & filed under , , , .

If at any point in your coding life you had to measure some component performance, chances are that you came across Perf4J at some point. To quote from their own website:

Perf4J is to System.currentTimeMillis() as log4j is to System.out.println()

There are of course other ways to measure timings of components execution, however, I found Perf4J to be rather neat as it plugs into Log4J, Apache Logging, JDK Logging and a whole bunch of others. It also has a bunch of tools you can use to analyze the output and generate some interesting stats analysis or even graphs. Basically, if you haven’t looked into it by now, do so! 😉

Anyways, apart from trying to promote this framework, there’s (at least) another point I’m trying to make, regarding usage: unfortunately, the standard example shown in Perf4J’s developer how-to is not ideal (booooo!). They basically suggest the following pattern to using this framework:

// Create the LoggingStopWatch to start timing. This constructor takes the tag
// name, which identifies the code block being timed. Note that usually you
// will want to instantiate one of the subclasses of LoggingStopWatch, such as
// a Log4JStopWatch or CommonsLogStopWatch depending on your preferred
// logging framework.
StopWatch stopWatch = new LoggingStopWatch("codeBlock1");
 
// Execute the code block - this is just a dummy call to pause execution for
// 0-1 second.
Thread.sleep((long)(Math.random() * 1000L));
 
// Stop the StopWatch and log it. LoggingStopWatches automatically log their
// timing statements when one of the stop() or lap() methods are called.
stopWatch.stop();

At first glance all is good — we create a stop watch which starts automatically and when we’re done processing we stop it. This will trigger a record to be written somewhere — be it console, or in a log file or the likes if you decide to use (as suggested) something like LoggingStopWatch, Log4JStopWatch etc. There is however, a subtle problem with this approach – and it’s not far from Schroedinger’s Cat problem: in order to measure the timing, we have to create an instance of StopWatch! This instance gets used, it produces the output (timing) and then it gets thrown in the deep hole of the garbage collection 🙁 Which means every time this method gets called, we increase the pressure on the GC! If this is a method that gets called thousands of times a second, you got a few thousands of instances of StopWatch waiting to be GC’d! And the next thing you know, your JVM freezes for a fraction of a second to recollect these, which in a high-throughput application is not acceptable, needless to point out!

You can of course start thinking of using a single instance of StopWatch (static final) — however, these instances are not thread safe for once, and secondly, how can you correlate a start() to a stop() when calls to each will come in random order due to the very nature of multi-threaded apps???

So in order to avoid that issue, you can use a mixed approach and throw in a ThreadLocal:

public class C {
 private static final ThreadLocal<StopWatch> WATCH = new ThreadLocal<StopWatch>() {
  @Override protected StopWatch initialValue() {
   return new Log4JStopWatch("abc");//let's assume we're going to use Log4J here
  }
 }
 
 //...
 
 void methodToMeasure() {
  WATCH.get().start();
  try {
 
   //...
 
  } finally {
   WATCH.get().stop()
  }
 }
}

Voila! Each thread now gets its own instance, so need to to worry about multi-threading inside the StopWatch and correlating each stop() correctly to a start() call. Also, no need to worry about object creation either — the number of StopWatch instances will be equals to the number of threads in your application using class C above — so even if you have 1,000 threads in your app, it’s better to have 1,000 instances of StopWatch rather than 1,000 instances of StopWatch created and destroyed every second!

Simple, right?

Leave a Reply

Your email address will not be published.