Esta integral puede aproximarse por la suma:
El siguiente programa C calcula una parte de la suma:
~/src/perl/grid-machine/examples$ 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("Usage:\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);
21 exit(0);
22 }
El siguiente ejemplo calcula el número
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:
~/src/perl/grid-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{europa};
9 #my @machine = qw{europa beowulf orion};
10 my @machine = qw{nereida europa};
11 #my @machine = qw{127.0.0.1 127.0.0.2 127.0.0.3 127.0.0.4};
12 #my @machine = qw{beo chum};
13 my $nummachines = @machine;
14 my %machine; # Hash of GRID::Machine objects
15 #my %debug = (beowulf => 12345, orion => 0, nereida => 0);
16 #my %debug = (europa => 12344, beowulf => 0, orion => 0, nereida => 0);
17 my %debug = (europa => 0, beowulf => 0, orion => 0, nereida => 0);
18
19 my $np = shift || $nummachines; # number of processes
20 my $lp = $np-1;
21
22 my $N = shift || 100;
23
24 my @pid; # List of process pids
25 my @proc; # List of handles
26 my %id; # Gives the ID for a given handle
27
28 my $cleanup = 0;
29
30 my $pi = 0;
31
32 my $readset = IO::Select->new();
33
34 my $i = 0;
35 for (@machine){
36 my $m = GRID::Machine->new(host => $_, debug => $debug{$_}, );
37
38 $m->copyandmake(
39 dir => 'pi',
40 makeargs => 'pi',
41 files => [ qw{pi.c Makefile} ],
42 cleanfiles => $cleanup,
43 cleandirs => $cleanup, # remove the whole directory at the end
44 keepdir => 1,
45 );
46
47 $m->chdir("pi/");
48
49 die "Can't execute 'pi'\n" unless $m->_x("pi")->result;
50
51 $machine{$_} = $m;
52 last unless ++$i < $np;
53 }
54
55 my $t0 = [gettimeofday];
56 for (0..$lp) {
57 my $hn = $machine[$_ % $nummachines];
58 my $m = $machine{$hn};
59 ($proc[$_], $pid[$_]) = $m->open("./pi $_ $N $np |");
60 $readset->add($proc[$_]);
61 my $address = 0+$proc[$_];
62 $id{$address} = $_;
63 }
64
65 my @ready;
66 my $count = 0;
67 do {
68 push @ready, $readset->can_read unless @ready;
69 my $handle = shift @ready;
70
71 my $me = $id{0+$handle};
72
73 my ($partial);
74 my $numBytesRead = sysread($handle, $partial, 1024);
75 chomp($partial);
76
77 $pi += $partial;
78 print "Process $me: machine = $machine[$me % $nummachines] partial = $partial pi = $pi\n";
79
80 $readset->remove($handle) if eof($handle);
81 } until (++$count == $np);
82
83 my $elapsed = tv_interval ($t0);
84 print "Pi = $pi. N = $N Time = $elapsed\n";
Siguen algunos ejemplos de ejecución que demuestran que la técnica acelera. Comparaciones con Globus demuestran que el rendimiento en este ejemplo es superior a Globus.
pp2@nereida:~/LGRID_Machine/examples$ time ssh beowulf 'pi/pi 0 1000000000 1' 3.141593 real 0m27.020s user 0m0.036s sys 0m0.008s casiano@beowulf:~$ time ssh orion 'pi/pi 0 1000000000 1' 3.141593 real 0m29.120s user 0m0.028s sys 0m0.003s pp2@nereida:~/LGRID_Machine/examples$ time ssh nereida 'pi/pi 0 1000000000 1' 3.141593 real 0m32.534s user 0m0.036s sys 0m0.008s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 1 1000000000 Process 0: machine = beowulf partial = 3.141593 pi = 3.141593 Pi = 3.141593. N = 1000000000 Time = 27.058693 real 0m28.917s user 0m0.584s sys 0m0.192s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 2 1000000000 Process 0: machine = beowulf partial = 1.570796 pi = 1.570796 Process 1: machine = orion partial = 1.570796 pi = 3.141592 Pi = 3.141592. N = 1000000000 Time = 15.094719 real 0m17.684s user 0m0.904s sys 0m0.260s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 3 1000000000 Process 0: machine = beowulf partial = 1.047198 pi = 1.047198 Process 1: machine = orion partial = 1.047198 pi = 2.094396 Process 2: machine = nereida partial = 1.047198 pi = 3.141594 Pi = 3.141594. N = 1000000000 Time = 10.971036 real 0m13.700s user 0m0.952s sys 0m0.240s # 2 veces nereida pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 2 1000000000 Process 0: machine = 127.0.0.1 partial = 1.570796 pi = 1.570796 Process 1: machine = 127.0.0.2 partial = 1.570796 pi = 3.141592 Pi = 3.141592. N = 1000000000 Time = 16.38121 real 0m17.849s user 0m0.504s sys 0m0.212s ****************************************** con -O 3 en gcc pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 4 1000000000 Process 3: machine = 127.0.0.4 partial = 0.785398 pi = 0.785398 Process 0: machine = 127.0.0.1 partial = 0.785398 pi = 1.570796 Process 1: machine = 127.0.0.2 partial = 0.785398 pi = 2.356194 Process 2: machine = 127.0.0.3 partial = 0.785398 pi = 3.141592 Pi = 3.141592. N = 1000000000 Time = 18.508143 real 0m21.299s user 0m0.840s sys 0m0.360s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 2 1000000000 Process 1: machine = 127.0.0.2 partial = 1.570796 pi = 1.570796 Process 0: machine = 127.0.0.1 partial = 1.570796 pi = 3.141592 Pi = 3.141592. N = 1000000000 Time = 16.552487 real 0m18.076s user 0m0.504s sys 0m0.188s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 3 1000000000 Process 1: machine = 127.0.0.2 partial = 1.047198 pi = 1.047198 Process 0: machine = 127.0.0.1 partial = 1.047198 pi = 2.094396 Process 2: machine = 127.0.0.3 partial = 1.047198 pi = 3.141594 Pi = 3.141594. N = 1000000000 Time = 17.372372 real 0m19.461s user 0m0.696s sys 0m0.240s pp2@nereida:~/LGRID_Machine/examples$ time gridpipes.pl 1 1000000000 Process 0: machine = 127.0.0.1 partial = 3.141593 pi = 3.141593 Pi = 3.141593. N = 1000000000 Time = 32.968117 real 0m33.858s user 0m0.336s sys 0m0.128s
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
