Have you ever thought about performance tuning a Perl Application ? Read-on to get a starting !
Identifying Performance Issues
The first task at hand in improving the performance of an application is to determine what parts of the application are not performing as well as they should. You need to find things that are actually slow. It’s no good wasting your effort on things that are already fast.
In this case I used two techniques to identify potential performance problems, code review and profiling.
A performance code review is the process of reading through the code looking for suspicious operations. The advantage of code review is the reviewer can observe the flow of data through the application. Understanding the flow of data through the application helps identify any control loops that can be eliminated
Application profiling is the process of monitoring the execution of an application to determine where the most time is spent and how frequently operations are performed. In this case, I used a Perl package called Benchmark::Timer. This package provides functions that I use to mark the beginning and end of interesting sections of code. Each of these marked sections of code are identified by a label. When the program is run and a marked section is entered, the time taken within that marked section is recorded.
Below is an example of using Benchmark
$time0 = Benchmark->new;
# your perl code here
$time1 = Benchmark->new;
$diffrence = timediff($time1, $time0);
print “the code took:”,timestr($difference);
Below is some methods for refactoring perl code.
If you work with large arrays or hashes and use them as arguments to functions, use a reference instead of the variable directly. By using a reference, you tell the function to point to the information. Without a reference, you copy the entire array or hash onto the function call stack, and then copy it again in the function. this will increase the performance by avoiding copying the entire contents of the data array in to the function References also save memory and simplify your programming.
Using short circuit logic
Please see sample code below. Using many if statements can be incredibly time consuming.
If ($x > 0)
$value = $x;
elsif ($y > 0)
$value = $ y;
$value = $default;
Aside from the waste of space in terms of sheer content, there are a couple of problems with this structure. From a programming perspective, it has the issue that it never checks if any of the variables have a valid value, a fact that would be highlighted if warnings were switched on. Second, it has to check each option until it gets to the one it wants, which is wasteful, as comparison operations (particularly on strings) are time consuming. Both problems can be solved by using short circuit logic.
If you use the logical || operator, Perl will use the first true value it comes across, in order, from left to right. The moment it finds a valid value, it doesn’t bother processing any of the other values. In addition, because Perl is looking for a true value, it also ignores undefined values without complaining about them. So we can rewrite the above into a single line:
$value = $x || $y || $default;
If $x is a true value, Perl doesn’t even look at the other variables. If $x is false, then Perl checks the value of $y and so on until it gets to the last value, which is always used, whether it’s true or not.
If you are using static strings in your application, remember to use single quotes rather than doubles. Double quotes force Perl to look for a potential interpolation of information, which adds to the overhead of printing out the string:
print ‘A string’,’another string’,”\n”;
I’ve also used commas to separate arguments rather than using a period to concatenate the string first. This simplifies the process;print simply sends each argument to the output file. Concatenation would concatenate the string and print it as one argument.
Concatenating a string
my $str = ‘haihelloworld’;
my $concat = ‘ ‘;
foreach my $c (1..10000)
$concat .= $str;
my $str = ‘haihelloworld’;
foreach my $c (1..10000)
push @concat, $str;
my $concat = join( ‘ ‘, @concat);
Running Example2 requires more time than running Example 1. Both generate a string, so what’s taking up the time? Conventional wisdom (including that of the Perl team) would say that concatenating a string is a time-expensive process, because we have to extend the memory allocation for the variable and then copy the string and its addition into the new variable. Conversely, adding a string to an array should be relatively easy. We also have the added problem of duplicating the string concatenation using join(), which adds an extra second.
If you’re writing modules use the AutoSplit and AutoLoader modules to make perl only load the parts of your
module that are actually being used by a particular script. You get two gains – you don’t waste CPU at start up
loading the parts of your module that aren’t used, and you don’t waste the RAM holding the the structures that
perl generates when it has compiled code. So your modules load more quickly, and use less RAM.
It’s easy to use by just changing your modules from the format shown in Example 3 to that shown in Example 4,
and then making sure to use AutoSplit to create the loading functions you need. Note that you don’t need to
use Exporter any more; AutoLoader handles the loading of individual functions automatically without you have to
explicitly list them
@EXPORT = qw/MsSub/;
#function code here
use AutoLoader ‘AUTOLOAD’;
# function code here