xsigndll
xsigndll

Reputation: 553

Perl, Alias sub to variable

I'm currently doing micro-optimization of a perl program and like to optimize some getters.

I have a package with this getter-structure:

package Test;

our $ABC;

sub GetABC { $ABC } # exported sub...

Calling GetABC() creates a lot of sub-related overhead. Accessing the variable directly via $Test::ABC is insanely faster.

Is there a way to alias the getter to the variable to gain the same performanceboost as if I would call the variable directly? Inlining hint with "()" doesn seem to work...

Upvotes: 0

Views: 163

Answers (1)

amon
amon

Reputation: 57640

There is no way to turn a variable into an accessor sub, or to replace a sub with a variable access. You will have to live with the overhead.

Non-solutions:

  • Using a () prototype does not turn calls into your sub to constant accesses because that prototype merely makes a sub potentially eligible for inlining. Since the body of the sub is not itself constant, this sub cannot be a constant.

  • The overhead is per-call as perl has to do considerable bookkeeping for each call. Therefore, rewriting that accessor in XS won't help much.

  • Creating a constant won't help because the constant will be a copy, not an alias of your variable.

But looking at the constant.pm source code seems to open up an interesting solution. Note that this a hack, and may not work in all versions of Perl: When we assign a scalar ref to a symbol table entry directly where that entry does not yet contain a typeglob, then an inlineable sub springs into place:

package Foo;
use strict;
use warnings;
use feature 'say';

my $x = 7;
BEGIN { $Foo::{GetX} = \$x }  # don't try this at home
say GetX; #=> 7
$x = 3;
say GetX; #=> 3

This currently works on most of my installed perl versions (5.14, 5.22, 5.24, 5.26). However, my 5.22-multi and 5.26-multi die with “Modification of a read-only value attempted”. This is not a problem for the constant module since it makes the reference target readonly first and (more importantly) never modifies that variable.

So not only doesn't this work reliably, this will also completely mess up constant folding.


If the function call overhead is indeed unbearable (e.g. takes a double-digit percentage of your processing time), then doing the inlining yourself in the source code is going to be your best bet. Even if you have a lot of call locations, you can probably create a simple script that fixes the easy cases for you: select all files that import your module and only have a single package declaration. Within such files, replace calls to GetABC (with or without parens) to fully qualified variable accesses. Hopefully that token is not mentioned within any strings. Afterwards, you can manually inspect the few remaining occurrences of these calls.

Upvotes: 5

Related Questions