Perls of wisdom
9 November 2015
It has been a long summer and it is time again to create a little post for a recent encounter on our supercomputer.
Errors in Perl
Perl is a common language which is very common within the Genomic communnity. Recently we had an interesting Perl issue where a job would just run for its maximum time allowed on our system and seemingly be running (no error message, using 100% of CPU, strace showing no errors). It would seem this Perl job had a very strange problem.
When confronted with this problem there are a number of methods available.
- Print statements.
perl -d ...
- Enbugger module
In this case Print statements was all that was required but in more complicated scenarios some of the other options would beneficial.
Understanding Perl
The job would output a number of lines of text and then seem to stop outputting anything further. Due to where it stopped I took a guess that nearby the logic would have failure for some special cases.
In this case we had the following loop structure (not the exact code):
my @data = qw(1 2 3); my $i = 0; until (data[$i] == -1) { $i++; } print "INFO: -1 is found at $i\n";
This loop tried to find a value in an array. In this case it was badly structured since the expression was never matched (i.e. @array = qw(1 2 3)
). This led to the loop going over the bounds of the array and looping forever (or some random memory to hit the condition).
A quick addition of a check in the loop resulted in it catching the error.
my @data = qw(1 2 3); my $i = 0; until ($data[$i] == -1) { $i++; die "ERROR: index out of range." if $i > $#data; } print "INFO: -1 is found at $i\n";
Looping techniques
What are the best looping strategies? In this case you expect the condition to always match. In this case there were problems with the input data which meant the condition was never met (no input data validation which is another future post topic). I prefer to make sure I only loop over the array elements rather than expect a condition to be met. For example:
my @data = qw(1 2 3); my $index = -1; for my $i (1..$#data) { if ($data[$i] == -1) { $index = $i; last; } } die "ERROR: -1 not found." if $index < 0; print "INFO: -1 is found at $index\n";
Of course the example above is simplified where the condition might have been more complicated and involved multiple arrays of all the same size so generic Perl features such as converting to map, clever use of grep etc… would not have helped. I suspect there is many codes out there which were put together quickly to solve a certain problem with minimal testing and error checking, so always remember to put some of these aspects into your own code.