perl -e 'use Inline C=>q{void greet(){printf("Hello, world\n");}};greet'
####
use strict;
use warnings;
use autodie;
use v5.12;
use Benchmark qw/cmpthese/;
use Test::More tests => 3;
use Inline 'C';
use constant TOP => 150000;
use constant TIME => 5;
is(
scalar @{ basic_perl( 3571 ) },
500,
"The first 500 primes are found from 2 to 3571."
);
is_deeply(
external_cpp(),
basic_perl(),
"external_cpp() function gives same results as basic_perl()."
);
is_deeply(
inline_c(),
basic_perl(),
"inline_c() function gives same results as basic_perl()."
);
note "\nComparing basic_perl(), external_cpp(), and inline_c() for\n",
TIME, " seconds searching ",
TOP, " integers.\n\n";
cmpthese(
- TIME,
{
basic_perl => \&basic_perl,
external_cpp => \&external_cpp,
inline_c => \&inline_c,
},
);
note "\nI love it when a plan comes together.\n\n";
# The pure Perl version.
sub basic_perl {
my $top = $_[0] // TOP;
my @primes = ( 2 );
BASIC_OUTER: for( my $i = 3; $i <= $top; $i += 2 ) {
my $sqrt_i = sqrt( $i );
for( my $j = 3; $j <= $sqrt_i; $j += 2 ) {
next BASIC_OUTER unless $i % $j;
}
push @primes, $i;
}
return \@primes;
}
# A wrapper around the external executable compiled in C++.
sub external_cpp {
my $top = TOP;
open my $fh, '-|', "primes.exe $top";
chomp( my @primes = <$fh> );
close $fh;
return \@primes;
}
# To be consistent: a wrapper around the Inline C version.
sub inline_c{
my $top = TOP;
my @primes = inline_c_primes( $top );
return \@primes;
}
__END__
// Reference only (not used by Inline::C )
// The source code, "primes.cpp" for "primes.exe",
// used by external_cpp().
#include
#include
#include
#include
#include
using namespace std;
vector get_primes( int search_to );
void print( int value );
// The first 500 primes are found from 2 to 3571.
const int TOP = 3571;
// http://en.wikipedia.org/wiki/List_of_prime_numbers
int main( int argc, char *argv[] ) {
int search_to = ( argc > 1 ) ? atoi(argv[1]) : TOP;
vector primes = get_primes( search_to );
for_each( primes.begin(), primes.end(), print );
return 0;
}
vector get_primes( int search_to ) {
vector primes;
primes.push_back( 2 );
for( int i = 3; i <= search_to; i += 2 ) {
int sqrt_i = sqrt( i );
for( int j = 3; j <= sqrt_i; j += 2 ) {
if( i % j == 0 ) goto SKIP;
}
primes.push_back( i );
SKIP: {};
}
return primes;
}
void print ( int value ) {
cout << value << endl;
}
__C__
# Here is the C code that is compiled by Inline::C
#include "math.h"
void inline_c_primes( int search_to )
{
Inline_Stack_Vars;
Inline_Stack_Reset;
Inline_Stack_Push(sv_2mortal(newSViv(2)));
int i;
for( i = 3; i <= search_to; i+=2 ) {
int sqrt_i = sqrt( i );
int qualifies = 1;
int j;
for( j = 3; ( j <= sqrt_i ) && ( qualifies==1 ); j += 2 ) {
if( i % j == 0 ) {
qualifies = 0;
}
}
if( qualifies == 1 ) {
Inline_Stack_Push(sv_2mortal(newSViv(i)));
}
}
Inline_Stack_Done;
}
# Cross your fingers and hope for the best!
##
##
1..3
ok 1 - The first 500 primes are found from 2 to 3571.
ok 2 - external_cpp() function gives same results as basic_perl().
ok 3 - inline_c() function gives same results as basic_perl().
#
# Comparing basic_perl(), external_cpp(), and inline_c() for
# 5 seconds searching 150000 integers.
#
Rate basic_perl external_cpp inline_c
basic_perl 1.27/s -- -94% -98%
external_cpp 20.0/s 1467% -- -66%
inline_c 59.3/s 4555% 197% --
#
# I love it when a plan comes together.
#
##
##
1..3
ok 1 - The first 500 primes are found from 2 to 3571.
ok 2 - external_cpp() function gives same results as basic_perl().
ok 3 - inline_c() function gives same results as basic_perl().
#
# Comparing basic_perl(), external_cpp(), and inline_c() for
# 5 seconds searching 150000 integers.
#
Rate basic_perl external_cpp inline_c
basic_perl 2.37/s -- -91% -97%
external_cpp 25.3/s 969% -- -67%
inline_c 76.0/s 3106% 200% --
#
# I love it when a plan comes together.
#
##
##
use strict;
use warnings;
use autodie;
use v5.12;
use Benchmark qw/cmpthese/;
use Test::More tests => 4;
use Inline 'C' => 'DATA';
use constant TOP => 200000;
use constant TIME => 10;
note "Operating system: $^O, Perl version: $^V\n\n";
note "Constant TOP is ", TOP;
note "Constant TIME is ", TIME, "\n\n";
is( scalar @{ basic_perl( 3571 ) },
500,
"basic_perl(3571): The first 500 primes are found from 2 to 3571."
);
is_deeply(
external_cpp(TOP),
basic_perl(TOP),
"external_cpp(TOP): Same results as basic_perl(TOP)."
);
is_deeply(
inline_c_list(TOP),
basic_perl(TOP),
"inline_c_list(TOP): Same results as basic_perl(TOP)."
);
is_deeply(
inline_c_aref(TOP),
basic_perl(TOP),
"inline_c_aref(TOP): Same result as basic_perl(TOP)."
);
note "\nComparing basic_perl(), external_cpp(), inline_c_list(), inline_c_aref()\n",
"for ",
TIME, " seconds searching ",
TOP, " integers.\n\n";
cmpthese(
- TIME,
{
basic_perl => \&basic_perl,
external_cpp => \&external_cpp,
inline_c_list => \&inline_c_list,
inline_c_aref => \&inline_c_aref,
},
);
note "\nI love it when a plan comes together.\n\n";
# The pure Perl version.
sub basic_perl {
my $top = $_[0] // TOP;
my @primes = ( 2 );
BASIC_OUTER: for( my $i = 3; $i <= $top; $i += 2 ) {
my $sqrt_i = sqrt( $i );
for( my $j = 3; $j <= $sqrt_i ; $j += 2 ) {
next BASIC_OUTER unless $i % $j;
}
push @primes, $i;
}
return \@primes;
}
# A wrapper around the external executable compiled in C++.
sub external_cpp {
my $top = $_[0] // TOP;
open my $fh, '-|', "primes $top";
chomp( my @primes = <$fh> );
close $fh;
return \@primes;
}
# To be consistent: a wrapper around the Inline C version.
sub inline_c_list{
my $top = $_[0] // TOP;
my @primes = inline_c_list_primes( $top );
return \@primes;
}
sub inline_c_aref{
my $top = $_[0] // TOP;
return inline_c_aref_primes( $top );
}
__END__
// Reference only (not used by Inline::C )
// The source code, "primes.cpp" for "primes.exe",
// used by external_cpp().
#include
#include
#include
#include
#include
using namespace std;
vector get_primes( int search_to );
void print( int value );
// The first 500 primes are found from 2 to 3571.
const int TOP = 3571;
// http://en.wikipedia.org/wiki/List_of_prime_numbers
int main(int argc, char *argv[] ) {
int search_to = ( argc > 1 ) ? atoi(argv[1]) : TOP;
vector primes = get_primes( search_to );
for_each( primes.begin(), primes.end(), print );
return 0;
}
vector get_primes( int search_to ) {
vector primes;
primes.push_back(2);
for( int i = 3; i <= search_to; i += 2 ) {
int sqrt_i = sqrt( i );
for( int j = 3; j <= sqrt_i; j += 2 ) {
if( i % j == 0 ) goto SKIP;
}
primes.push_back(i);
SKIP: {};
}
return primes;
}
void print ( int value ) {
cout << value << endl;
}
__C__
#include "math.h"
void inline_c_list_primes( int search_to )
{
Inline_Stack_Vars;
Inline_Stack_Reset;
Inline_Stack_Push(sv_2mortal(newSViv(2)));
int i;
for( i = 3; i <= search_to; i+=2 ) {
int sqrt_i = sqrt( i );
int qualifies = 1;
int j;
for( j = 3; (j<=sqrt_i) && (qualifies==1); j += 2 ) {
if( i % j == 0 ) {
qualifies = 0;
}
}
if( qualifies == 1 ) {
Inline_Stack_Push(sv_2mortal(newSViv(i)));
}
}
Inline_Stack_Done;
}
AV * inline_c_aref_primes ( int search_to )
{
AV* av;
av = newAV();
av_push( av, newSViv( 2 ) );
int i;
for( i = 3; i <= search_to; i+=2 ) {
int sqrt_i = sqrt( i );
int qualifies = 1;
int j;
for( j = 3; (j<=sqrt_i) && (qualifies==1); j += 2 ) {
if( i % j == 0 ) {
qualifies = 0;
}
}
if( qualifies == 1 ) {
av_push( av, newSViv( i ) );
}
}
return sv_2mortal( av );
}
##
##
1..4
# Operating system: linux, Perl version: v5.14.2
#
# Constant TOP is 200000
# Constant TIME is 10
#
ok 1 - basic_perl(3571): The first 500 primes are found from 2 to 3571.
ok 2 - external_cpp(TOP): Same results as basic_perl(TOP).
ok 3 - inline_c_list(TOP): Same results as basic_perl(TOP).
ok 4 - inline_c_aref(TOP): Same result as basic_perl(TOP).
#
# Comparing basic_perl(), external_cpp(), inline_c_list(), inline_c_aref()
# for 10 seconds searching 200000 integers.
#
Rate basic_perl external_cpp inline_c_list inline_c_aref
basic_perl 1.64/s -- -91% -97% -97%
external_cpp 17.6/s 977% -- -67% -67%
inline_c_list 53.0/s 3138% 201% -- -2%
inline_c_aref 54.1/s 3202% 207% 2% --
#
# I love it when a plan comes together.
#