Note, I tried testing this before in this question which may look similar, however those results were flawed and a result of constant folding, which I subsequently disabled. and republished in this question.
Given these two evals (comment one on execution) which only change &Module::FOO()
and &FOO()
.
# Symbols imported, and used locally.
eval qq[
package Foo$num;
Module->import();
my \$result = &Module::FOO() * &Module::FOO();
] or die $@;
# Symbols imported, not used locally referencing parent symbol.
eval qq[
package Foo$num;
Module->import();
my \$result = &FOO() * &FOO();
] or die $@;
why would the top block take up substantially less space? The script and output are reproduced below,
package Module {
use v5.30;
use warnings;
use constant FOO => 42;
use Exporter 'import';
our @EXPORT = ('FOO');
}
package main {
use v5.30;
use autodie;
use warnings;
$|=1;
say "Our PID is $$";
for my $num ( 0..1e5 ) {
eval qq[
package Foo$num;
Module->import();
my \$result = &Module::FOO() * &Module::FOO();
] or die $@;
eval qq[
package Foo$num;
Module->import();
my \$result = &FOO() * &FOO();
] or die $@;
}
say "DONE";
_debug();
}
sub _debug {
open my $fh, "<", "/proc/$$/status";
while ( <$fh> ) {
next unless /Rss/;
print;
}
}
RssAnon: 101856 kB
RssFile: 5228 kB
RssShmem: 0 kB
RssAnon: 151528 kB
RssFile: 5224 kB
RssShmem: 0 kB
It was requested by aquanight
on irc.freenode.net/#perl
to try this experiment with constant
directly, here is the code I used,
eval qq[
package Foo$num;
use constant FOO => 42;
my \$result = &FOO() * &FOO();
] or die $@;
eval qq[
package Foo$num;
use constant FOO => 42;
my \$result = &Foo${num}::FOO() * &Foo${num}::FOO();
] or die $@;
With this both examples performed as such, to be clear, it was actually worse to use the variant with constant directly and to access the constants with package qualification, then it was to create another package which has the constants to and package-qualify to that package.
Our PID is 204846
RssAnon: 143560 kB
RssFile: 5196 kB
RssShmem: 0 kB
It seems that you can get very close if you export the entire symbol rather than one slot in the glob,
our @EXPORT = ('*FOO');
Re-running the same tests, wou will find that both are very similar
RssAnon: 93900 kB
RssFile: 5228 kB
RssShmem: 0 kB
In fact, this is much closer to the theoretical maximum, which cuts out the call to import
entirely,
eval qq[
package Foo$num;
my \$result = &Module::FOO() * &Module::FOO();
] or die $@;
Which produces,
RssAnon: 74528 kB
RssFile: 5160 kB
RssShmem: 0 kB
However if we examine this nugget of glory, as suggested by aquanight
,
our sub FOO; # top of file
Module->import();
package Bar;
print FOO(); # works
print Bar::FOO(); # does not work
The symbol FOO
is made available to package Bar
without bloating the Bar
package. When this method is applied to the above benchmark, it looks like,
eval qq[
our sub FOO ();
Module->import();
package Foo$num;
my \$result = FOO() * FOO();
] or die $@;
And produces these results,
RssAnon: 75112 kB
RssFile: 5284 kB
RssShmem: 0 kB
constant.pm
,This can be further implemented as,
eval qq[
our sub FOO ();
use constant FOO => 42;
package Foo$num;
my \$result = FOO() * FOO();
];
Which will produce these results,
RssAnon: 75076 kB
RssFile: 5180 kB
RssShmem: 0 kB