Ejemplo de Uso: Cálculo de $ \pi $

El siguiente ejemplo calcula el número $ \pi $ en paralelo lanzando diversos procesos que realizan una suma parcial. El proceso padre recolecta los resultados tan pronto como terminan haciendo uso de IO::Select:

pp2@nereida:~/LGRID_Machine/examples$ cat -n gridpipes.pl
 1  #!/usr/bin/perl
 2  use warnings;
 3  use strict;
 4  use IO::Select;
 5  use GRID::Machine;
 6  use Time::HiRes qw(time gettimeofday tv_interval);
 7
 8  my @machine = qw{beowulf orion nereida};
 9  my $nummachines = @machine;
10  my %machine; # Hash of GRID::Machine objects
11  #my %debug = (beowulf => 12345, orion => 0, nereida => 0);
12  my %debug = (beowulf => 0, orion => 0, nereida => 0);
13
14  my $np = shift || $nummachines; # number of processes
15  my $lp = $np-1;
16
17  my $N = shift || 100;
18
19  my @pid;  # List of process pids
20  my @proc; # List of handles
21  my %id;   # Gives the ID for a given handle
22
23  my $cleanup = 0;
24
25  my $pi = 0;
26
27  my $readset = IO::Select->new();
28
29  my $i = 0;
30  for (@machine){
31    my $m = GRID::Machine->new(host => $_, debug => $debug{$_}, );
32
33      $m->copyandmake(
34        dir => 'pi',
35        makeargs => 'pi',
36        files => [ qw{pi.c Makefile} ],
37        #cleanfiles => 1,
38        #cleandirs => 1, # remove the whole directory at the end
39      )
40    unless -x 'pi/pi';
41
42    die "Can't execute 'pi'\n" unless $m->_x("pi")->result;
43
44    $machine{$_} = $m;
45    last unless $i++ < $np;
46  }
47
48  my $t0 = [gettimeofday];
49  for (0..$lp) {
50    my $hn = $machine[$_ % $nummachines];
51    my $m = $machine{$hn};
52    ($proc[$_], $pid[$_]) = $m->open("./pi $_ $N $np |");
53    $readset->add($proc[$_]);
54    my $address = 0+$proc[$_];
55    $id{$address} = $_;
56  }
57
58  my @ready;
59  my $count = 0;
60  do {
61    push @ready, $readset->can_read;
62    my $handle = shift @ready;
63
64    my $me = $id{0+$handle};
65
66    my ($partial);
67    my $numBytesRead = sysread($handle,  $partial, 1024);
68    chomp($partial);
69
70    $pi += $partial;
71    print "Process $me: machine = $machine[$me % $nummachines] partial = $partial pi = $pi\n";
72
73    $readset->remove($handle) if eof($handle);
74  } until (++$count == $np);
75
76  my $elapsed = tv_interval ($t0);
77  print "Pi = $pi. N = $N Time = $elapsed\n";

Sigue un ejemplo de ejecución:

 pp2@nereida:~/src/perl/Event/select$ time pi 0 100000000 1
 3.141593

 real    0m3.244s
 user    0m3.244s
 sys     0m0.000s

pp2@nereida:~/src/perl/Event/select$ sshseveralpipes4.pl 1 100000000
Process 0: machine = orion partial = 3.141593 pi = 3.141593
Pi = 3.141593. N = 100000000 Time = 3.46131
pp2@nereida:~/src/perl/Event/select$ sshseveralpipes4.pl 3 100000000
Process 2: machine = nereida partial = 1.047198 pi = 1.047198
Process 1: machine = beowulf partial = 1.047198 pi = 2.094396
Process 0: machine = orion partial = 1.047198 pi = 3.141594
Pi = 3.141594. N = 100000000 Time = 1.927591

Este es el fuente (en C) del programa pi.c:

pp2@nereida:~/src/perl/Event/select$ cat -n pi.c
 1  #include <stdio.h>
 2  #include <stdlib.h>
 3
 4  main(int argc, char **argv) {
 5    int id, N, np, i;
 6    double sum, left;
 7
 8    if (argc != 4) {
 9      printf("Uso:\n%s id N np\n",argv[0]);
10      exit(1);
11    }
12    id = atoi(argv[1]);
13    N = atoi(argv[2]);
14    np = atoi(argv[3]);
15    for(i=id, sum = 0; i<N; i+=np) {
16      double x = (i + 0.5)/N;
17      sum += 4 / (1 + x*x);
18    }
19    sum /= N;
20    printf("%lf\n", sum);
Estos son los contenidos del Makefile:
pp2@nereida:~/src/perl/Event/select$ cat -T Makefile
pi:
^Icc pi.c -o pi

Casiano Rodríguez León
2010-03-22