Showing posts with label scripting. Show all posts
Showing posts with label scripting. Show all posts

Wednesday, 28 September 2011

And the Second Prize Goes To...

I've written here before about the virtues of Eclipse MAT for doing heap analysis but I recently encountered a situation in which I couldn't persuade it to give me the answers that I really needed.

I was analysing a set of heap dumps from an application and MAT's leak suspects report showed me that circa 300Mb of heap space was being retained by a single object. The object in question was a metadata manager, so it was well known that this object would retain a big chunk of heap space. This overhead was fixed size, and so not really of interest. The report categorised everything else in a single bucket as 'other', which wasn't much help.

I really needed to know about the most significant objects that were retaining space outside of the retained set of the metadata manager. While it's possible to explore around using MAT views like the histogram and come up with some answers, I didn't feel that this was a very methodical approach and it would be quite easy to miss something important.

I realised that the problem could be helped by applying a little simple set theory - what we are interested in is how a histogram or retained set looks after subtracting the retained set of the number one leak suspect. This is very simple to do, but very repetitive - an ideal job for a script, so that's what I wrote.

So at the bottom of the post is a perl script that will read two files saved as CSV from either the MAT histogram or retained set views and print the result of the subtraction in CSV format to its output. Some views don't automatically calculate the retained size, so you need to select the rows and ask MAT to do at least the minimal retained set calculation before saving the CSV. If you only speak Windows, then you can use the script by installing a suitable perl implementation - I usually use ActiveState's ActivePerl.

I managed to use this quite successfully. I started by subtracting the retained set of the metadata manager from the overall histogram. By continuing to subtract more 'suspects' from the result, I was able to identify the second, third and fourth placed consumers of heap space in my dump files, which I felt was going far enough.

Finally, the script... unfortunately Blogger doesn't seem to allow attachments.



# perl script to subtract one Java retained set from another.
# Retained sets or histograms can be saved in CSV format from Eclipse MAT
# The retained size is required, so ask MAT to calculate it if it is missing
#
# usage: perl subtract-retained.pl .csv .csv [.csv]...
#
# Andy Carlson
# http://threeturves.blogspot.com/
# September 2011
#
use strict;

my ($basefile) = shift;
my (%count,%shallow,%retained,%loaders);
my ($lineno) = 0;

# read the baseline histogram
open (HIN,$basefile) || die;
while () {
$lineno++;
next if ($lineno == 1);
next if (!$_);
my ($class,$count,$shallow,$retained) = split (/,/);

if (!$retained && ($retained ne '0')) {
warn "warning: no retained size for $class at $basefile line $lineno - skipping remainder of file";
last;
}

$loaders{$class}++;
$count{$class} += $count;
$shallow{$class} += $shallow;
$retained{$class} += $retained;
}
close HIN;

# now read one or more retained sets and subtract from the base histogram
while (1) {
my ($rsetfile) = shift;
last if (!$rsetfile);
open (HIN,$rsetfile) || die;
$lineno = 0;
while () {
$lineno++;
next if ($lineno == 1);
next if (!$_);
my ($class,$count,$shallow,$retained) = split (/,/);
if (!$retained && ($retained ne '0')) {
warn "warning: no retained size for $class at $rsetfile line $lineno - skipping remainder of file";
last;
}
$count{$class} -= $count;
$shallow{$class} -= $shallow;
$retained{$class} -= $retained;
}
close HIN;
}

# produce the output
print "class,objects,shallow heap,retained heap,loaders\n";
my ($class);
foreach $class (sort keys (%loaders)) {
print "$class,$count{$class},$shallow{$class},$retained{$class},$loaders{$class}\n";
}

Monday, 27 October 2008

Groovy for database business logic

My first impressions of Groovy as a way to solve my database-oriented business logic problem are very good.

I started out by re-implementing the stored procedure logic that I'd prototyped as a Groovy class. I got it working and passing the unit test in a couple of hours. My first implementation was fairly horrid, but over the next few hours I figured out some more of the Groovy idioms and removed some Java style code which made the whole thing more expressive and easier to follow.

One thing which took some figuring out was date handling and date arithmetic. I started out using the java Calendar class, which was somewhat verbose. I then found http://groovy.codehaus.org/JN0545-Dates which explained some useful stuff like the Groovy Duration classes. These made my code much more concise, although I'm not too comfortable about the fact that you can do 'duration + java date', but not the other way round. I can see exactly why it is so (because java.util.Date doesnt have a 'plus' method), but it's rather counter-intuitive.

While it was in the state of being a 'like for like' copy, I also took the opportunity to do a couple of comparisons:-
  • lines of code (including blanks and comments) - 66 for Groovy, 87 for the stored procedure - the savings were mainly down to the elimination of variable declarations at the start of the procedure and the much simpler looping syntax with Groovy.
  • performance - I was only able to test on my local Windows machine, which is not ideal, but with a sensible amount of data, the Groovy version was taking about 7% longer than the stored procedure version.

Since my code has an inner loop with a complex SQL insert/select statement in it, I thought it worth looking at what Groovy was doing with this. Using the (Eclipse) debugger, I found that it was creating a new PreparedStatement for each iteration of the loop, which I thought may be costing some performance. I tried expanding this operation out to explicitly create a PreparedStatement outside the loop and execute it inside the loop. The result was zero improvement in performance, but some pretty ugly code so I undid this change.

Overall, Groovy looks like it is meeting my requirements as a way to implement complex database business logic, so I'm now about to start on turning my prototype logic into something which can meet the rather more complex requirements of the real thing.

Sunday, 26 October 2008

Time to be more Groovy

Following a recommendation from a colleague, I've had good intentions to learn and use more Groovy for quite a while now, but somehow havent quite had a problem that really presents itself as the ideal starting point.

A few months back I took the initial plunge and used Groovy to do a real job. The job probably wasnt the best choice as a first Groovy project - it was basically pulling data from a multi-gigabyte binary file (actually WebLogic JMS storage files), but it needed to be done and I got the job done with Groovy. In the end I probably wished I hadn't done it this way because I couldn't then use the resulting script anywhere else without getting Groovy set up there first and the alternative was shifting the huge files to the machine where the script was working. I don't think I really learned much idiomatic Groovy either.

Today I have a new problem to solve - basically I have some complex pricing calculations to do based on data in a relational database. The calculations need to be done both in scheduled batch mode and 'on the fly' within a J2EE app for 'what-if' style illustrations. They also need to be very pluggable so that entirely different pricing structures can be supported.

Thinking about this problem, what I need is:-
  • Must be runnable from a J2EE app
  • Must have good DB integration
  • Must have automated unit tests
  • Must have concise, expressive logic and preferably polymorphism
  • Must be easy to debug

The initial prototype (with lots of simplifying assumptions) was done as a stored procedure with DBUnit test cases, which nicely meets the first three requirements, but runs out of steam on the third. I think that continuing with this approach is going to result in something pretty cumbersome as I gradually remove the simplifying assumptions.

Native Java didn't seem too attractive in terms of really tight DB integration - both JDBC and Hibernate fall a long way short of the simplicity with which SQL can be used in a stored procedure.

So I took another look at Groovy - it seems to fit the bill pretty well. I suspect that GSQL will be rather less cumbersome than either raw JDBC or Hibernate, although probably not quite as closely integrated as running SQL inside a stored proc. I was also worried (based on past experience of Jython and Javascript) about debugging, but it seems that this angle is also covered with both JSwat and Eclipse being supported. Hopefully it will also get me into more idiomatic Groovy in the process...

We shall see!