use strict; use warnings; use threads; use threads::shared; use MCE::Flow; my ($m, $n, $count_max) = (500, 500, 2000); my ($x_max, $x_min, $y_max, $y_min) = ( 1.25, -2.25, 1.75, -1.75 ); my $r = shared_clone []; my $g = shared_clone []; my $b = shared_clone []; for my $i ( 0 .. $m - 1 ) { $r->[$i] = shared_clone []; $g->[$i] = shared_clone []; $b->[$i] = shared_clone []; } #--------------------------------------------------------------------# # Perl version of Mandelbrot_OpenMP by John Burkardt. # http://people.sc.fsu.edu/~jburkardt/c_src/mandelbrot_openmp/ # mandelbrot_openmp.html # # Carry out the iteration for each pixel, determining count. sub mandelbrot { my ($m1, $m2) = @_; my ($x, $x1, $x2, $y, $y1, $y2); my ($c, %count, $i, $j, $k); for $i ( $m1 .. $m2 ) { for $j ( 0 .. $n - 1 ) { $x = ( ( $j - 1 ) * $x_max + ( $m - $j ) * $x_min ) / ( $m - 1 ); $y = ( ( $i - 1 ) * $y_max + ( $n - $i ) * $y_min ) / ( $n - 1 ); $count{$i}{$j} = 0; $x1 = $x; $y1 = $y; for $k ( 1 .. $count_max ) { $x2 = ( $x1 * $x1 ) - ( $y1 * $y1 ) + $x; $y2 = 2 * $x1 * $y1 + $y; if ( $x2 < -2.0 || 2.0 < $x2 || $y2 < -2.0 || 2.0 < $y2 ) { $count{$i}{$j} = $k; last; } $x1 = $x2; $y1 = $y2; } if ( ( $count{$i}{$j} % 2 ) == 1 ) { lock $r; # not necessary, but runs faster with locking $r->[$i][$j] = 255; $g->[$i][$j] = 255; $b->[$i][$j] = 255; } else { lock $r; # ditto $c = int( 255.0 * sqrt(sqrt(sqrt($count{$i}{$j} / $count_max))) ); $r->[$i][$j] = $g->[$i][$j] = 3 * $c / 5; $b->[$i][$j] = $c; } } } return; } #--------------------------------------------------------------------# # Return the smaller of two numbers. sub min { $_[0] < $_[1] ? $_[0] : $_[1]; } # Write image to an ASCII PPM file. sub write_to_ppm { my ($ofile) = @_; my ($FH, $i, $j, $jlo, $jhi); open $FH, '>', $ofile or die "cannot open file ($ofile): $!\n"; print $FH "P3\n"; print $FH "$n $m\n"; print $FH "255\n"; for ( $i = 0; $i < $m; $i++ ) { for ( $jlo = 0; $jlo < $n; $jlo += 4 ) { $jhi = min( $jlo + 4, $n ); for ( $j = $jlo; $j < $jhi; $j++ ) { printf $FH " %d %d %d", $r->[$i][$j], $g->[$i][$j], $b->[$i][$j] } print $FH "\n"; } } close $FH; } #--------------------------------------------------------------------# # The bounds_only option applies to sequence of numbers # which means to compute the begin and end boundaries only, # not the numbers in between. Thus, workers receive 2 # numbers in @{ $chunk_ref }. # Same as mce_flow_s { mce options }, sub { ... }, 0, $m - 1; MCE::Flow::run_seq( { chunk_size => 5, max_workers => 'auto', bounds_only => 1 }, sub { my ($mce, $chunk_ref, $chunk_id) = @_; mandelbrot( @{ $chunk_ref} ); }, 0, $m - 1 ); ## Write image to an ASCII PPM file. write_to_ppm('mandelbrot.ppm');