Update a test to terminate politely

Update a test to terminate politely

This test was calling exit on Locale 0 to cause all processes to shut down
once "termination" was detected. Instead, pass a token to each process
telling it to finish.

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@15136 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

config param debug: bool = false;

//
// Simple, stand-alone implementation of EWD840:
// Derivation of a termination detection algorithm for distributed computations
// "Compiler" transformed user code starts at "use Time;". The transformations
// the compiler would apply are:
//   1. Call setupTerminationDetection() at the beginning of execution
//   2. Insert a call to incEndCount before every begin statement
//   3. Insert a call to decEndCount at the end of every begin statement
//   4. Insert a call to turnBlack before every on statement
//   5. Add a "single" variable to wait upon at the end of main
//

enum TerminationColor {black, white};
enum WakeupType {beginFinish, tokenPass, die};

class MyEndCount {
  var count: sync int;
  var localColor: sync TerminationColor;
  var token: sync TerminationColor;
}

class WakeupSyncVarHack {
  var wakeup: sync WakeupType;
}

pragma "private" var wakeup: WakeupSyncVarHack;
pragma "private" var endCount: MyEndCount;

def setupTerminationDetection() {
  for loc in Locales do on loc {
    endCount = new MyEndCount();
    wakeup = new WakeupSyncVarHack();
    if here.id == 0 {
      endCount.count = 1;
      endCount.localColor = TerminationColor.white;
      endCount.token = TerminationColor.white;
    } else {
      endCount.count = 0;
      endCount.localColor = TerminationColor.white;
    }
    begin tokenWaiter();
  }
}

def passToken(wakeupType) {
  var next = if here.id == 0 then numLocales-1 else here.id-1;
  var token = endCount.token;
  if endCount.localColor == TerminationColor.black then
    token = TerminationColor.black;
  if debug then
    writeln(here, ": Passing ", token, " token");
  on Locales(next) {
    endCount.token = token;
    if wakeupType != WakeupType.die then
      wakeup.wakeup = WakeupType.tokenPass;
    else
      wakeup.wakeup = WakeupType.die;
  }
  endCount.localColor = TerminationColor.white;
}

var finishedProg: single bool;

def tokenWaiter() {
  var wakeupType = wakeup.wakeup;
  while wakeupType != WakeupType.die {
    var nextWakeupType = wakeupType;
    if endCount.token.isFull {
      if endCount.count.readFF() == 0 {
        if here.id == 0 {
          if wakeupType == WakeupType.beginFinish {
            endCount.localColor.writeXF(TerminationColor.white);
            endCount.token.writeXF(TerminationColor.white);
          } else if wakeupType == WakeupType.tokenPass {
            if endCount.token == TerminationColor.white {
              finishedProg = true;
              nextWakeupType = WakeupType.die;
              endCount.localColor.writeXF(TerminationColor.white);
              endCount.token.writeXF(TerminationColor.white);
            } else {
              endCount.localColor.writeXF(TerminationColor.white);
              endCount.token.writeXF(TerminationColor.white);
            }
          }
        }
        passToken(nextWakeupType);
      }
    }
    wakeupType = wakeup.wakeup;
  }
  if here.id != 0 then
    passToken(WakeupType.die);
}

def decEndCount {
  endCount.count -= 1;
  if debug then
    writeln(here, ": decEndCount: It is now: ", endCount.count.readFF());
  if endCount.count.readFF() == 0 then
    wakeup.wakeup = WakeupType.beginFinish;
}

def incEndCount {
  endCount.count += 1;
  if debug then
    writeln(here, ": incEndCount: It is now: ", endCount.count.readFF());
}

def turnBlack {
  if debug then
    writeln(here, ": turning black");
  endCount.localColor.writeXF(TerminationColor.black);
}

var a: sync int = 0;

use Time;

def foo() {
  sleep(5);
  turnBlack;
  on Locales(0) {
    incEndCount;
    begin {
      sleep(3);
      a += 1;
      decEndCount;
    }
  }
  sleep(4);
  a += 1;
}

//
// A possible main program after compiler transformations for termination
// detection.
//
def main {
  setupTerminationDetection();
  incEndCount;
  begin {
    turnBlack;
    on Locales(1) {
      sleep(3);
      a += 1;
    }
    decEndCount;
  }
  incEndCount;
  begin {
    sleep(4);
    a += 1;
    decEndCount;
  }
  incEndCount;
  begin {
    turnBlack;
    on Locales(1) {
      incEndCount;
      begin {
        foo();
        a += 1;
        decEndCount;
      }
    }
    decEndCount;
  }

  decEndCount;
  finishedProg;
  write("program finished ");
  var aa = a;
  if aa == 5 then
    writeln("successfully");
  else
    writeln("unsuccessfully: a is ", aa);
}

config param debug: bool = false;

//
// Simple, stand-alone implementation of EWD840:
// Derivation of a termination detection algorithm for distributed computations
// "Compiler" transformed user code starts at "use Time;". The transformations
// the compiler would apply are:
//   1. Call setupTerminationDetection() at the beginning of execution
//   2. Insert a call to incEndCount before every begin statement
//   3. Insert a call to decEndCount at the end of every begin statement
//   4. Insert a call to turnBlack before every on statement
//   5. Add a "single" variable to wait upon at the end of main
//

enum TerminationColor {black, white};
enum WakeupType {beginFinish, tokenPass, die};

class MyEndCount {
  var count: sync int;
  var localColor: sync TerminationColor;
  var token: sync TerminationColor;
}

class WakeupSyncVarHack {
  var wakeup: sync WakeupType;
}

pragma "private" var wakeup: WakeupSyncVarHack;
pragma "private" var endCount: MyEndCount;

def setupTerminationDetection() {
  for loc in Locales do on loc do {
    endCount = new MyEndCount();
    wakeup = new WakeupSyncVarHack();
    if here.id == 0 {
      endCount.count = 1;
      endCount.localColor = TerminationColor.white;
      endCount.token = TerminationColor.white;
    } else {
      endCount.count = 0;
      endCount.localColor = TerminationColor.white;
    }
    begin tokenWaiter();
  }
}

def passToken() {
  var next = if here.id == 0 then numLocales-1 else here.id-1;
  var token = endCount.token;
  if endCount.localColor == TerminationColor.black then
    token = TerminationColor.black;
  if debug then
    writeln(here, ": Passing ", token, " token");
  on Locales(next) {
    endCount.token = token;
    wakeup.wakeup = WakeupType.tokenPass;
  }
  endCount.localColor = TerminationColor.white;
}

var finishedProg: single bool;

def tokenWaiter() {
  var wakeupType = wakeup.wakeup;
  while wakeupType != WakeupType.die {
    if endCount.token.isFull {
      if endCount.count.readFF() == 0 {
        if here.id == 0 {
          if wakeupType == WakeupType.beginFinish {
            endCount.localColor.writeXF(TerminationColor.white);
            endCount.token.writeXF(TerminationColor.white);
          } else if wakeupType == WakeupType.tokenPass {
            if endCount.token == TerminationColor.white {
              finishedProg = true;
            } else {
              endCount.localColor.writeXF(TerminationColor.white);
              endCount.token.writeXF(TerminationColor.white);
            }
          }
        }
        passToken();
      }
    }
    wakeupType = wakeup.wakeup;
  }
}

def decEndCount {
  endCount.count -= 1;
  if debug then
    writeln(here, ": decEndCount: It is now: ", endCount.count.readFF());
  if endCount.count.readFF() == 0 then
    wakeup.wakeup = WakeupType.beginFinish;
}

def incEndCount {
  endCount.count += 1;
  if debug then
    writeln(here, ": incEndCount: It is now: ", endCount.count.readFF());
}

def turnBlack {
  if debug then
    writeln(here, ": turning black");
  endCount.localColor.writeXF(TerminationColor.black);
}

var a: sync int = 0;

use Time;

def foo() {
  sleep(5);
  turnBlack;
  on Locales(0) {
    incEndCount;
    begin {
      sleep(3);
      a += 1;
      decEndCount;
    }
  }
  sleep(4);
  a += 1;
}

//
// A possible main program after compiler transformations for termination
// detection.
//
def main {
  setupTerminationDetection();
  incEndCount;
  begin {
    turnBlack;
    on Locales(1) {
      sleep(3);
      a += 1;
    }
    decEndCount;
  }
  incEndCount;
  begin {
    sleep(4);
    a += 1;
    decEndCount;
  }
  incEndCount;
  begin {
    turnBlack;
    on Locales(1) {
      incEndCount;
      begin {
        foo();
        a += 1;
        decEndCount;
      }
    }
    decEndCount;
  }

  decEndCount;
  finishedProg;
  write("program finished ");
  var aa = a;
  if aa == 5 then
    writeln("successfully");
  else
    writeln("unsuccessfully: a is ", aa);
  exit(if aa == 5 then 0 else 1);
}


Added a few comments in jacobi example.

Added a few comments in jacobi example.

git-svn-id: 88467cb1fb04b8a755be7e1ee1026be4190196ef@8811 3a8e244f-b0f2-452b-bcba-4c88e055c3ca

// Configuration variables for program:
config var n = 5,                       // size of nxn grid
           epsilon = 0.00001,           // convergence tolerance
           verbose = false;             // printing control

def main() {
  const ProblemSpace = [1..n, 1..n],    // domain for interior grid points
        BigDomain = [0..n+1, 0..n+1];   // larger domain including boundary points

  var A, Temp: [BigDomain] real = 0.0;  // A contains approximate solution
                                        // Temp is work array used in Jacobi iteration
  A[n+1, 1..n] = 1.0;

  if (verbose) {
    writeln("Initial configuration:");
    writeln(A, "\n");
  }

  var iteration = 0,                    // iteration counter
      delta: real;                      // measure of convergence at each iteration

  do {
    // compute next approximation using Jacobi method and store in Temp
    forall (i,j) in ProblemSpace do
      Temp(i,j) = (A(i-1,j) + A(i+1,j) + A(i,j-1) + A(i,j+1)) / 4.0;

    // compute difference between next and current approximations
    delta = max reduce abs(Temp[ProblemSpace] - A[ProblemSpace]);

    // update A with next approximation
    A[ProblemSpace] = Temp[ProblemSpace];

    // advance iteration counter
    iteration += 1;

    if (verbose) {
      writeln("iteration: ", iteration);
      writeln(A);
      writeln("delta: ", delta, "\n");
    }
  } while (delta > epsilon);

  writeln("Jacobi computation complete.");
  writeln("Delta is ", delta, " (< epsilon = ", epsilon, ")");
  writeln("# of iterations: ", iteration);
}

config var n = 5,
           epsilon = 0.00001,
           verbose = false;

def main() {
  const ProblemSpace = [1..n, 1..n],
        BigDomain = [0..n+1, 0..n+1];

  var A, Temp: [BigDomain] real = 0.0;

  A[n+1, 1..n] = 1.0;

  if (verbose) {
    writeln("Initial configuration:");
    writeln(A, "\n");
  }

  var iteration = 0,
      delta: real;

  do {
    forall (i,j) in ProblemSpace do
      Temp(i,j) = (A(i-1,j) + A(i+1,j) + A(i,j-1) + A(i,j+1)) / 4.0;

    delta = max reduce abs(Temp[ProblemSpace] - A[ProblemSpace]);
    A[ProblemSpace] = Temp[ProblemSpace];

    iteration += 1;

    if (verbose) {
      writeln("iteration: ", iteration);
      writeln(A);
      writeln("delta: ", delta, "\n");
    }
  } while (delta > epsilon);

  writeln("Jacobi computation complete.");
  writeln("Delta is ", delta, " (< epsilon = ", epsilon, ")");
  writeln("# of iterations: ", iteration);
}