Update: Corrected a couple 1 off errors.

Update: Compute upper half only. Makes a copy afterwards, flips vertically, and copies into bottom half. There is a one time delay from Inline::C compiling the C code. Remember to run again.

Update: Draw lines when possible.

Update: Reduced IPC.

Finally, providing a demonstration combining MCE::Flow + GD + Inline::C.

use strict; use warnings; use MCE::Flow Sereal => 1; use MCE::Queue Fast => 1; use GD; # based on original code at http://www.alfrog.com/mandel.html # karlgoethebier: initial code refactor, thanks perlmonks # marioroy: parallelization via MCE::Flow (2 user tasks) + Inline::C # process upper half only (reduces work for writer by 50%) # draw lines when possible (reduces work for writer by 56x) # reduced # of times to enqueue/dequeue to lower IPC # also see tips by BrowserUk at: # http://www.perlmonks.org/?node_id=1128885 use Inline 'C' => Config => CCFLAGSEX => '-O2'; use Inline 'C' => <<'END_C'; int width, height, iterations, middle; void c_init( int _width, int _height, int _iterations ) { width = _width; height = _height; iterations = _iterations; middle = _height / 2; } AV * c_mandel( int x1, int x2 ) { AV *ret = newAV(); SV *line_size; double re_c, im_c, re_z, im_z, temp; int x, y, color, last_color; for (x = x1; x <= x2; x++) { for (y = 0; y <= middle; y++) { re_c = (double) ( x - 3 * width / 4 ) / ( width / 3 ); im_c = (double) ( y - height / 2 ) / ( width / 3 ); re_z = im_z = (double) 0.0; color = 0; while ( 1 ) { temp = (double) re_z; re_z = (double) re_z * re_z - im_z * im_z + re_c; im_z = (double) 2 * temp * im_z + im_c; ++color; if ( re_z * re_z + im_z * im_z > 4.0 ) break; if ( color == iterations ) { color = 0; break; } } if ( y && color == last_color ) { // increment line size, writer draws a line when > 0 line_size = *av_fetch( ret, -1, TRUE ); sv_setiv( line_size, SvIV( line_size ) + 1 ); } else { av_push( ret, newSViv( x ) ); av_push( ret, newSViv( y ) ); av_push( ret, newSViv( color ) ); av_push( ret, newSViv( 0 ) ); last_color = color; } } } return sv_2mortal( ret ); } END_C # fasten your seat belt, enjoy the ride :) my $width = 1280 * 1; my $height = 1024 * 1; my $iterations = 20; my $Q = MCE::Queue->new(); my $num_mandels = 3; my $num_writers = 1; # must be 1 # init C and MCE c_init( $width, $height, $iterations ); MCE::Flow::init { bounds_only => 1, chunk_size => 16, max_workers => [ $num_mandels, $num_writers ], task_name => [ 'tsk_mandel', 'tsk_writer' ], user_begin => sub { my ( $mce, $task_id, $task_name ) = @_; $mce->{ret} = [] if $task_name eq 'tsk_mandel'; }, user_end => sub { my ( $mce, $task_id, $task_name ) = @_; if ( $task_name eq 'tsk_mandel' ) { $Q->enqueue( MCE->freeze( $mce->{ret} ) ) if @{ $mce->{ret} } +; $Q->enqueue( undef ); } } }; # compute mandelbrot (user tasks; sequence begin, end ) MCE::Flow::run_seq( \&mandel, \&writer, 0, $width - 1 ); MCE::Flow::finish; # for MCE providers sub mandel { my ( $mce, $chunk_ref, $chunk_id ) = @_; push @{ $mce->{ret} }, @{ c_mandel( @{ $chunk_ref } ) }; if ( @{ $mce->{ret} } > 12000 ) { $Q->enqueue( MCE->freeze( $mce->{ret} ) ); $mce->{ret} = []; } } # for MCE consumer sub writer { my ( $mce ) = @_; # init image and color palette my $image = new GD::Image( $width, $height ); my @palette = $image->colorAllocate( 0, 0, 0 ); # black for ( 1 .. $iterations ) { my ( $r, $g, $b ) = map { int rand 255 } 1 .. 3; push @palette, $image->colorAllocate( $r, $g, $b ); } # process draw requests while (1) { my $ret = $Q->dequeue; if (!defined $ret) { last unless --$num_mandels; next; } my $data = MCE->thaw( $ret ); my $size = @{ $data }; for ( my $i = 0; $i < $size; $i += 4 ) { if ( $data->[$i+3] ) { # draw line if line_size > 0 $image->line( $data->[$i], # x1 $data->[$i+1], # y1 $data->[$i], # x2 $data->[$i+1] + $data->[$i+3], # y2 $palette[ $data->[$i+2] ] # color ); } else { # otherwise, set pixel $image->setPixel( $data->[$i], # x $data->[$i+1], # y $palette[ $data->[$i+2] ] # color ); } } } # copy upper half, flip vertically, then copy into bottom half my $middle = int( $height / 2 ); my $temp = new GD::Image( $width, $middle ); $temp->copy( $image, 0, 0, 0, 0, $width, $middle ); $temp->flipVertical(); $image->copy( $temp, 0, $middle + 1, 0, 0, $width, $middle ); # save image open my $fh, '>mandelbrot.png' || return 1; binmode $fh; print $fh $image->png; close $fh; }

In reply to Re^3: Refactoring: Better Variable Names For Better Understanding? [SOLVED] by marioroy
in thread Refactoring: Better Variable Names For Better Understanding? [SOLVED] by karlgoethebier

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.