"Is Affix faster than... everything else?"

Let's find out!

The Perl ecosystem offers several ways to call C code. How does Affix stack up?

We will benchmark four approaches:

  1. Inline::C

    Compiles C code into a custom XS module. This is historically the fastest way to call C from Perl, as it eliminates the "FFI" layer entirely, but it requires a C compiler at installation time (or runtime).

  2. FFI::Platypus

    The current dominant FFI module on CPAN. It uses libffi (a portable, general-purpose Foreign Function Interface library) to handle argument shuffling.

  3. Affix

    Our pride and joy. Wraps our custom JIT engine: infix.

The Recipe

We'll compile a shared library performing a simple integer addition, then bind it using all three libraries.

use v5.40;
use Benchmark qw[cmpthese];
use Affix     qw[:all];
use Affix::Build;
use FFI::Platypus 2.00;

# All tests run on the same C.
my $c_code;
BEGIN { $c_code = <<~'' }
    int add_ints(int a, int b) {
        return a + b;
    }


# Inline::C setup
use Inline C => Config => ( ccflags => '-O3' );
use Inline C => $c_code;

# We must compile the library for Affix and Platypus
my $c = Affix::Build->new( flags => { cflags => '-O3' } );
$c->add( \$c_code, lang => 'c' );
my $lib = $c->link;

# FFI::Platypus setup
my $ffi_plat = FFI::Platypus->new( api => 2 );
$ffi_plat->lib($lib);
$ffi_plat->attach( [ add_ints => 'add_platypus' ], [ 'int', 'int' ], 'int' );

# Affix setup
affix $lib, [ add_ints => 'add_affix' ], [ Int, Int ] => Int;

# The race
say 'Benchmarking for 5 seconds...';
my $x = 100;
my $y = 200;
cmpthese - 5, {
    Inline   => sub { add_ints( $x, $y ) },
    Platypus => sub { add_platypus( $x, $y ) },
    Affix    => sub { add_affix( $x, $y ) }
    }

The Results

On my system, I see results similar to this:

Benchmarking for 5 seconds...
               Rate Platypus   Inline    Affix
Platypus  5026460/s       --     -57%     -82%
Inline   11641793/s     132%       --     -58%
Affix    28016636/s     457%     141%       --

Analysis

Summary