"Is Affix faster than pure Perl?"
This is the most important question. Migrating code to C requires an investment of time (and maybe the development of a new skillset) so the payoff must be worth it.
The simple answer is usually, "Yes, but..."
You must understand that there is a fixed cost to crossing the boundary between Perl and C (marshalling arguments, setting up the stack, the JIT trampoline, etc.). If your C function does very little (like adding two integers), the overhead might outweigh the speed gain. However, if your C function does heavy lifting (matrix math, cryptography, parsing), the gain is massive.
Let's benchmark a naive Fibonacci calculation in Perl versus C to see exactly how much faster native code can be.
The Recipe
use v5.40;
use Affix qw[:all];
use Affix::Build;
use Benchmark qw[cmpthese];
$|++;
# 1. Compiled C Implementation
# We use -O3 to ensure the C compiler optimizes the recursion as much as possible
my $c = Affix::Build->new( flags => { cflags => '-O3' } );
$c->add( \<<~'', lang => 'c' );
int fib_c(int n) {
if (n < 2) return n;
return fib_c(n-1) + fib_c(n-2);
}
affix $c->link, 'fib_c', [Int] => Int;
# 2. Perl Implementation
sub fib_p($n) {
return $n if $n < 2;
return fib_p( $n - 1 ) + fib_p( $n - 2 );
}
# 3. Benchmark
say 'Small N (High overhead impact)';
cmpthese(
-5,
{ Perl => sub { fib_p(10) },
Affix => sub { fib_c(10) }
}
);
say 'Large N (Raw compute dominance)';
cmpthese(
-5,
{ Perl => sub { fib_p(30) },
Affix => sub { fib_c(30) }
}
);
These are the results from my machine:
Small N (High overhead impact)
Rate Perl Affix
Perl 47892/s -- -100%
Affix 10607023/s 22048% --
Large N (Raw compute dominance)
Rate Perl Affix
Perl 3.16/s -- -100%
Affix 959/s 30258% --
How It Works
-
1. The Boundary Cost
In the "Small N" test, Affix leans on C to overcome the overhead of marshalling data back and forth. Even with the FFI 'tax,' the compiled C code processes the recursion so efficiently that it still runs 200x faster than the Perl subroutine.
-
2. The Compute Gain
In the "Large N" test, the difference widens. The C code runs entirely in native machine code for millions of recursive iterations before crossing back to Perl. As you can see, this results in the C version being over 300x faster than pure Perl.
Kitchen Reminders
-
Batching
If you have a C function that sets a single pixel, calling it 2 million times from Perl will be slow. Instead, expose a C function that takes an
Array[Pixel]and updates the whole image in one call. We'll get to even more advanced features like SIMD in later chapters.