$ time perl mandelbrot1.pl 16000 > m1.pbm
real 8m38.383s ( Perl code by Mykola Zubach, threads only )
$ time perl mandelbrot2.pl 16000 > m2.pbm
real 3m52.245s ( MCE supporting threads and processes )
$ time perl mandelbrot3.pl 16000 > m3.pbm
real 1.974s ( MCE + Inline::C, mind boggling )
####
# http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=mandelbrot
# based on Perl code contributed by Mykola Zubach
# parallelization via MCE by Mario Roy
use strict;
use warnings;
use MCE::Flow;
use constant MAXITER => 50;
use constant LIMIT => 4.0;
use constant XMIN => -1.5;
use constant YMIN => -1.0;
use constant WHITE => "\000";
use constant BLACK => "\001";
my ( $w, $h, $m, $invN );
sub draw_line {
my ( $mce, $y, $chunk_id ) = @_;
my ( $Cr, $Zr, $Zi, $Tr, $Ti );
my $Ci = $y * $invN + YMIN;
my $line;
LOOP: for my $x (0 .. $w - 1) {
$Cr = $x * $invN + XMIN;
$Zr = $Zi = $Tr = $Ti = 0.0;
for (1 .. MAXITER) {
$Zi = $Zi * 2 * $Zr + $Ci;
$Zr = $Tr - $Ti + $Cr;
$Ti = $Zi * $Zi;
$Tr = $Zr * $Zr;
if ($Tr + $Ti > LIMIT) {
$line .= WHITE;
next LOOP;
}
}
$line .= BLACK;
}
MCE->gather( $chunk_id, pack('B*', $line) );
}
## MAIN()
$w = $h = shift || 200;
$m = int( $h / 2 );
$invN = 2 / $w;
# Compute upper-half only, gather lines
my %picture = mce_flow_s { chunk_size => 1 }, \&draw_line, 0, $m;
# Output PBM image header
# Output upper half
# Remove first and last lines
# Output bottom half in reverse
binmode STDOUT;
print "P4\n$w $h\n";
print @picture{ sort { $a <=> $b } keys %picture };
delete @picture{ 1, $m + 1 };
print @picture{ sort { $b <=> $a } keys %picture };
##
##
# http://benchmarksgame.alioth.debian.org/u64q/performance.php?test=mandelbrot
# based on Perl code contributed by Mykola Zubach
# parallelization via MCE + Inline::C by Mario Roy
use strict;
use warnings;
use MCE::Flow;
use Inline 'C' => Config => CCFLAGSEX => '-O2';
use Inline 'C' => <<'END_C';
#define MAXITER 50
#define LIMIT 4.0
#define XMIN -1.5
#define YMIN -1.0
#define WHITE "\000"
#define BLACK "\001"
int width; double invN;
void c_init( int _width, double _invN )
{
width = _width;
invN = _invN;
}
SV* c_draw_line( int y )
{
SV *line = newSVpvn( "", 0 );
double Ci, Cr, Zr, Zi, Tr, Ti;
int x, j;
Ci = (double) y * invN + YMIN;
x = -1;
LOOP: do {
if ( ++x >= width ) break;
Cr = (double) x * invN + XMIN;
Zr = Zi = Tr = Ti = 0.0;
for (j = 1; j <= MAXITER; j++) {
Zi = Zi * 2.0 * Zr + Ci;
Zr = Tr - Ti + Cr;
Ti = Zi * Zi;
Tr = Zr * Zr;
if (Tr + Ti > LIMIT) {
sv_catpvn( line, WHITE, 1 );
goto LOOP;
}
}
sv_catpvn( line, BLACK, 1 );
} while ( 1 );
return sv_2mortal( line );
}
END_C
my ( $w, $h, $m, $invN );
sub draw_line {
my ( $mce, $y, $chunk_id ) = @_;
my $line = c_draw_line( $y );
MCE->gather( $chunk_id, pack('B*', $line) );
}
## MAIN()
$w = $h = shift || 200;
$m = int( $h / 2 );
$invN = 2 / $w;
# Init C
c_init( $w, $invN );
# Compute upper-half only, gather lines
my %picture = mce_flow_s { chunk_size => 1 }, \&draw_line, 0, $m;
# Output PBM image header
# Output upper half
# Remove first and last lines
# Output bottom half in reverse
binmode STDOUT;
print "P4\n$w $h\n";
print @picture{ sort { $a <=> $b } keys %picture };
delete @picture{ 1, $m + 1 };
print @picture{ sort { $b <=> $a } keys %picture };