Wednesday, 23 March 2011

Suprise when profiling Java/Groovy app with jprofiler

First, if you are a Java programmer you really need to get hold of http://www.ej-technologies.com/products/jprofiler/overview.html!

Long story short, I profiled a long running application thinking I knew exactly where the performance penalty was - it wasn't anywhere near there :) It was in the equals() method of a groovy class which was implemented as:

boolean equals(Object other) {

other instanceof ThisClass && other.hashCode().equals(other.hashCode())

}

hashCode:

int hashCode() {

this.name ? name.hashCode() : 0

}

(This class had a single property which was a String and set in the constructor so I could easily cache the hashCode) but flip me, who knew this would be a bottleneck accounting for 17% of the CPU time. OK, it was called over 3 million times, but still....

The solution? I don't know if it is the cost of groovy or what, but my first call is to cache the hashCode and reference that in the hashCode and equals method. Run the profiler and see if that helped. Second step will be to re-implement in Java and see if that helps....

Long story

There was a Java/Groovy based app which used Hibernate and SQL Server which I migrated to use MongoDB. The app had some non-trivial complex hierarchies which were a pain to store in a relational DB but trivial to store in a document DB. There was an obvious aggregate root for the data structure so the conversion was very straight forward.

The application was fantastically quick for loading a single document but the user's home page displays all their active documents, of which there might be hundreds. The SQL server application uses a denormalised summary table which condenses each document into a single row so that is lightening quick but the mongo app was really slow.

Given that hibernate has a first level cache *and* given that the documents have lots of references *and* given that MongoDB has no such first level cache you might follow my line of thinking that the performance cost was in Mongo loading each referenced object over and over again.

Like me, you would be wrong :)

Lesson of the day - use jprofiler - it just might surprise you!

No comments:

Post a Comment