Limbic~Region has asked for the wisdom of the Perl Monks concerning the following question:
I just wrote a rapid prototype of an application that really should have been written in C/C++ or at the very least - many things in XS instead of pure perl. While I am happy with the prototype and can use it effectively as an off-line analysis tool, I would like to see if there are any low effort changes that I can make to give it a significant speed improvement. Yes, I have profiled. Yes, I know that traditional answers such as using 'a better algorithm', 'caching' or 'a faster language'. I have already optimized the things I can at the level of effort I am willing to invest.
In other words, this post is about using source filters (possibly Filter::Simple::Compile) to inline subs and not the traditional performance tuning dogma.
Inlining subs is not easy as they can have multiple exit points, call other subs, etc. I am not trying to make every sub inlininable. Here is outline of what I am currently thinking.
Subs to be inlined will need to meet the following regex
In other words, the inline keyword is at the beginning of the line and the end of the sub is a close curly brace at the beginning of the line.m|^inline sub (\w+)(.*?^})|sm inline sub example { my ($num, $den) = @_; if (! $den) { return; } return $num / $den; }
Unintended behavior will result if you do the following:
It is because it ultimately gets translated to something like:my $date = calc_date(); inline sub calc_date { my $date = strftime('%Y-%m-%d', localtime); return $date; }
my $date; SOMEUNIQUELABEL: { my $date = strftime('%Y-%m-%d', localtime); $date = $date; last SOMEUNIQUELABEL; }
Supported flavors:
Parens are required even with no arguments. There can only be trailing white space after the semicolon (not even comments). The right hand side can only be a single sub invocation and not multiple values. No postfix conditionals are supported. It should be possible to turn a postfix conditional into block form but for now that is a level of complexity not supported (KISS). The calling line is replaced with an empty line if the invoking line has no my'd variables. If there are my'd variables, the = is replaced with a ;void_sub($foo, $bar); my @result = list_context_sub($foo, $bar); $val = scalar_context_sub($foo, $bar);
my ($foo, $bar) = blah($asdf); # becomes my ($foo, $bar);
The subroutine will become a naked block with a label.
my $blah = foo(1, 2); sub foo { my ($var1, $var2) = @_; return $var1 + $var2; } # becomes my $blah; SOMEUNIQUELABEL: { my ($var1, $var2) = @_; return $var1 + $var2; }
Supported flavors
@_ is replaces with the calling arguments from the invocation linevoid - no reference to @_ explicitly or implicitly my ($var1, $var2) = @_; # consumed all at once, no more references to +@_ explicitly or implicitly
my $blah = foo(1, 2); sub foo { my ($var1, $var2) = @_; return $var1 + $var2; } # becomes my $blah; SOMEUNIQUELABEL: { my ($var1, $var2) = (1, 2); return $var1 + $var2; }
Supported flavors
No implicit return is supported (last evaluated statement). No postfix conditionals are supported. It should be possible to turn a postfix conditional into block form but for now that is a level of complexity not supported (KISS). The return line gets replaced with the applicable assignment and last. The only special exception is if you have an empty return, the assignment gets replaced with undef;return; # void return $foo; # single item return ($blah, $asdf); # multiple items
my $blah = foo(1, 2); sub foo { my ($var1, $var2) = @_; if ($var2 == 0) { return; } return $var1 + $var2; } # becomes my $blah; SOMEUNIQUELABEL: { my ($var1, $var2) = (1, 2); if ($var2 == 0) { $blah = undef; last SOMEUNIQUELABEL; } $blah = $var1 + $var2; last SOMEUNIQUELABEL; }
I considered a do block as well but that would require the subs to all be written in the form where the return value was implicit (last evaluated expression). Any thoughts? Any gotchas or drawbacks I am not seeing? I know that the introduction of the new scope doesn't come for free either. This seems like a change I could implement quickly and Benchmark.
Update: As I implement this, I am adding additional constraints using <ins>comment</ins> tags.
Cheers - L~R
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: Inline Subs Revisited
by BrowserUk (Patriarch) on Apr 28, 2010 at 15:54 UTC | |
|
Re: Inline Subs Revisited
by Limbic~Region (Chancellor) on Apr 29, 2010 at 02:56 UTC | |
by BrowserUk (Patriarch) on Apr 29, 2010 at 14:39 UTC |