sub reduce(&@) {
my $f = shift;
my $a = shift;
my $b;
our @args;
(local *_, local *args) = (sub { \@_ }->($a, $b), \@_);
no strict 'refs';
my $caller = caller();
local *{$caller."::a"} = \$a;
local *{$caller."::b"} = \$b;
$b = shift(@args), $a = &$f while @args;
return $a;
}
####
Rate ike1_p ike1_n ike2_p ike1_i ike2_i ike2_n
ike1_p 6.34/ms -- -2% -2% -4% -6% -7%
ike1_n 6.46/ms 2% -- -1% -3% -4% -5%
ike2_p 6.50/ms 3% 1% -- -2% -3% -4%
ike1_i 6.63/ms 5% 3% 2% -- -1% -2%
ike2_i 6.72/ms 6% 4% 3% 1% -- -1%
ike2_n 6.79/ms 7% 5% 4% 2% 1% --
(I)nline: reduce { $a * $b } 1..100;
(P)rototype: reduce \&prototyped, 1..100;
(N)o prototype: reduce \&unprototyped, 1..100;
####
ikegami1_i 1 ok
ikegami1_n 1 ok
ikegami1_p 1 ok
ikegami2_i 1 ok
ikegami2_n 1 ok
ikegami2_p 1 ok
ikegami1_i 6 ok
ikegami1_n 6 ok
ikegami1_p 6 ok
ikegami2_i 6 ok
ikegami2_n 6 ok
ikegami2_p 6 ok
----------------------------------------
Tiny (3 args)
Rate ikegami2_p ikegami2_n ikegami2_i ikegami1_i ikegami1_n ikegami1_p
ikegami2_p 67.8/s -- -0% -1% -38% -39% -56%
ikegami2_n 68.0/s 0% -- -1% -38% -39% -56%
ikegami2_i 68.6/s 1% 1% -- -38% -38% -56%
ikegami1_i 110/s 63% 62% 61% -- -1% -29%
ikegami1_n 111/s 64% 63% 61% 1% -- -29%
ikegami1_p 155/s 129% 128% 126% 41% 40% --
Multiply by 1000 to get real rate.
----------------------------------------
Short (6 args)
Rate ikegami2_p ikegami2_n ikegami2_i ikegami1_n ikegami1_i ikegami1_p
ikegami2_p 52.6/s -- -2% -3% -31% -32% -45%
ikegami2_n 53.7/s 2% -- -1% -30% -31% -43%
ikegami2_i 54.2/s 3% 1% -- -29% -30% -43%
ikegami1_n 76.4/s 45% 42% 41% -- -1% -20%
ikegami1_i 77.5/s 47% 44% 43% 1% -- -18%
ikegami1_p 95.0/s 80% 77% 75% 24% 23% --
Multiply by 1000 to get real rate.
----------------------------------------
Medium (20 args)
Rate ikegami2_p ikegami2_n ikegami2_i ikegami1_i ikegami1_n ikegami1_p
ikegami2_p 25.4/s -- -2% -4% -11% -12% -20%
ikegami2_n 26.0/s 2% -- -1% -9% -10% -18%
ikegami2_i 26.4/s 4% 2% -- -8% -9% -17%
ikegami1_i 28.6/s 13% 10% 8% -- -1% -10%
ikegami1_n 29.0/s 14% 11% 10% 1% -- -9%
ikegami1_p 31.8/s 25% 22% 21% 11% 10% --
Multiply by 1000 to get real rate.
----------------------------------------
Long (100 args)
Rate ikegami1_p ikegami1_n ikegami2_p ikegami1_i ikegami2_i ikegami2_n
ikegami1_p 6.34/s -- -2% -2% -4% -6% -7%
ikegami1_n 6.46/s 2% -- -1% -3% -4% -5%
ikegami2_p 6.50/s 3% 1% -- -2% -3% -4%
ikegami1_i 6.63/s 5% 3% 2% -- -1% -2%
ikegami2_i 6.72/s 6% 4% 3% 1% -- -1%
ikegami2_n 6.79/s 7% 5% 4% 2% 1% --
Multiply by 1000 to get real rate.
####
use strict;
use warnings;
use Benchmark qw( cmpthese );
my $OUTER = $ARGV[0] || -3;
my $INNER = $ARGV[1] || 1000;
$a=$b; # Avoid warning.
sub ikegami1(&@) {
my $f = shift;
my $a = shift;
if (prototype($f)||'' eq '$$') {
$a = $f->($a, shift) while @_;
} else {
my $b;
no strict 'refs';
my $caller = caller();
local *{$caller."::a"} = \$a;
local *{$caller."::b"} = \$b;
$b = shift, $a = $f->() while @_;
}
return $a;
}
sub ikegami2(&@) {
my $f = shift;
my $a = shift;
my $b;
our @args;
(local *_, local *args) = (sub { \@_ }->($a, $b), \@_);
no strict 'refs';
my $caller = caller();
local *{$caller."::a"} = \$a;
local *{$caller."::b"} = \$b;
$b = shift(@args), $a = &$f while @args;
return $a;
}
sub prototyped($$) { $_[0] * $_[1] }
sub unprototyped { $a * $b }
sub test {
my ($name, $code, $expect) = @_;
my $rv = eval($code);
my $ok = ($expect == $rv);
printf("%-10s %d %s\n", $name, $_, $ok?'ok':'XXX');
}
my %tests = map +(
"${_}_i" => "${_} { \$a * \$b } 1..\$_;", # inline
"${_}_p" => "${_} \\&prototyped, 1..\$_;", # proto
"${_}_n" => "${_} \\&unprototyped, 1..\$_;", # no proto
), qw(
ikegami1
ikegami2
);
for my $data (1, 6) {
my $expect = do { local $_ = $data; eval($tests{ikegami1_i}) };
for my $name (sort keys %tests) {
my $code = $tests{$name};
test($name, $code, $expect) for $data;
}
print("\n");
}
print("\n");
my %bench_code = map +( $_ => "use strict; use warnings; for (1..$INNER) { my \$rv = $tests{$_}; }" ), keys %tests;
for (
[ 'Tiny', 3, ],
[ 'Short', 6, ],
[ 'Medium', 20, ],
[ 'Long', 100, ],
) {
my ($name, $data) = @$_;
print("$name ($data args)\n\n");
cmpthese($OUTER, \%bench_code) for $data;
print("\n\n");
}
print("Multiply by $INNER to get real rate.\n");