#!/usr/bin/perl   

# example PerlDSM application; finds the number of primes from 2 to N

# note:  not intended to be efficient at all; just an example of how to
# use PerlDSM with array variables

use DSMClnt;

package main;

# shared variables:
$NextI;  # next value of $I to cross out multiples of
@Prime;  # $Prime[I] = 0 if I composite, else = 1

# global non-shared variables:
$NumNodes;  # total number of application nodes
$MyNode;  # number of this node
$SvrSkt;  # server socket ID for this node
$N;  # range of primes to be checked
$Lim;  # sqrt(N)
$IHaveChecked = 0;  # number of $I values this node has checked

# check in with server
($SvrSkt,$NumNodes,$MyNode) = DSMClnt::DSMCheckIn();
print "total of ", $NumNodes, " nodes, of which I am number ",$MyNode, "\n";

$N = $ARGV[2];
$Lim = int(sqrt($N));

# tie shared variables
tie $NextI,'DSMClnt',0,'$NextI',-1;
foreach $I (2..$N)  {
   tie $Prime[$I],'DSMClnt',1,'$Prime',$I;
}
tie $LOCK,'DSMClnt',0,'$LOCK',-1;
tie $BARR,'DSMClnt',0,'$BARR',-1;

# initialize Prime array; assume each $I prime until proven otherwise
if ($MyNode == 0)  {
   $NextI = 2;
   foreach $I (2..$N)  {
      $Prime[$I] = 1;
   }
}

# barrier (wait for node 0 to finish initialization)
$Dummy = $BARR;  # left-hand side irrelevant

while (1)  {
   # get next $I value, and atomically increment
   $Dummy = $LOCK;
   $I = $NextI++;
   $LOCK = 0;
   $IHaveChecked++;
   # don't cross out multiples of $I if $I > sqrt($N)
   last if ($I > $Lim);
   # don't cross out multiples of $I if $I known to be composite
   if ($Prime[$I] == 1) {
      # cross out all multiples of $I
      $UpperBd = int($N/$I);
      if ($UpperBd*$I < $N)  {
         $UpperBd++;
      }
      foreach $K (2..$UpperBd)  {
         $J = $K * $I;
         if ($J <= $N)  {
            $Prime[$J] = 0;
         }
      }
   }
}

# wait for everyone to finish, then write answer if I am node 0
$Dummy = $BARR;
print "I checked ", $IHaveChecked, " values of I\n";
if ($MyNode == 0)  {
   $Count = 0;
   foreach $I (2..$N)  {
      if ($Prime[$I] == 1)  {
         $Count++;
      }
   }
   print "number of primes = ", $Count, "\n";
}

$Dummy = $BARR;
DSMClnt::DSMExit();

