We need some applications. Don Leskiw has suggested a target-tracking application which combines data and task parallelism with opportunities for applet front ends. Other numerical applications of Java, suitable for parallelism, are needed.
As a trivial example of the use of our channels interface, I have ported one of the examples from the Cornell meta-computing seminar to Java. This outputs its results to files which can be viewed with xv. It should be given an applet interface. The source is included below.
--------------------------- Life.java ------------------------------
import java.io.* ;
public class Life {
static final int N = 64 ;
static final int NITER = 50 ;
static final String [] hosts = {"koum", "naos"} ;
static final int NNODES = hosts.length ;
public static void main(String args[]) {
try {
DataInputStream fromNode [] = new DataInputStream [NNODES] ;
// Create a ring of channels
Port R [] = new Port [NNODES] ;
Port S [] = new Port [NNODES] ;
for(int i = 0 ; i < NNODES ; i++) {
R [i] = new Port() ;
S [i] = new Port() ;
}
for(int i = 0 ; i < NNODES ; i++)
Port.channel(R [i], S [(i + 1) % NNODES]) ;
// Create the node processes.
for(int i = 0 ; i < NNODES ; i++) {
Port U = new Port() ;
Port V = new Port() ;
Port.channel(U, V) ;
RPC.spawn("LifeWorker", hosts [i], V) ;
// Send parameters to node
U.sendInt(N) ;
U.sendInt(NITER) ;
U.sendInt(NNODES) ;
U.sendInt(i) ;
U.sendChan(R [i]) ;
U.sendChan(S [i]) ;
fromNode [i] = new DataInputStream(new PortInputStream(U)) ;
}
/* Handle output. */
for(int iter = 0 ; iter <= NITER ; iter++) {
/* Copy current state of board from nodes to a `.pgm' file. */
String fname = "life" + iter / 10 + iter % 10 + ".pgm" ;
PrintStream out = new PrintStream(new FileOutputStream(fname)) ;
out.println("P2") ;
out.println("" + N + " " + N) ;
out.println("" + 1) ;
for(int node_id = 0 ; node_id < NNODES ; node_id++) {
DataInputStream in = fromNode [node_id] ;
int blockLen = in.readInt() ;
for(int i = 0 ; i < blockLen ; i++) {
out.print("" + in.readInt() + " ") ;
if(i % 20 == 19) out.println("") ;
}
}
}
}
catch(Exception e) {
;
}
}
}
------------------------ LifeWorker.java ----------------------------
import java.io.* ;
public class LifeWorker extends Child {
public static void main(String args[]) {
try {
Port R = new Port() ;
Port S = new Port() ;
// Get parameters from host
int N = initial.recvInt() ;
int NITER = initial.recvInt() ;
int NNODES = initial.recvInt() ;
int node_id = initial.recvInt() ;
initial.recvChan(R) ;
initial.recvChan(S) ;
// Create port streams
DataOutputStream toHost =
new DataOutputStream(new PortOutputStream(initial)) ;
DataOutputStream toNodePrev =
new DataOutputStream(new PortOutputStream(R)) ;
DataInputStream fromNodePrev =
new DataInputStream(new PortInputStream(R)) ;
DataOutputStream toNodeNext =
new DataOutputStream(new PortOutputStream(S)) ;
DataInputStream fromNodeNext =
new DataInputStream(new PortInputStream(S)) ;
// Define block
int blockSizeMax = (N + NNODES - 1) / NNODES ;
int blockBase = blockSizeMax * node_id ;
int blockSize ;
if(blockBase + blockSizeMax > N)
blockSize = N - blockBase ;
else
blockSize = blockSizeMax ;
// `block' has `blockSize + 2' columns. This allows for ghost cells.
int block [] [] = new int [blockSize + 2] [N] ;
for(int i = 0 ; i < blockSize ; i++) {
int ib = i + 1 ;
for(int y = 0 ; y < N ; y++) {
int x = blockBase + i ;
if(x == N / 2 || y == N / 2)
block [ib] [y] = 1 ;
else
block [ib] [y] = 0 ;
}
}
// Dump initial state of board to host
toHost.writeInt(blockSize * N) ;
for(int i = 0 ; i < blockSize ; i++) {
int ib = i + 1 ;
for(int y = 0 ; y < N ; y++)
toHost.writeInt(block [ib] [y]) ;
}
toHost.flush() ;
// Main update loop.
int neighbours [] [] = new int [blockSize] [N] ;
for(int iter = 0 ; iter < NITER ; iter++) {
// Shift this block's upper edge into next neighbour's lower ghost edge
for(int y = 0 ; y < N ; y++)
toNodeNext.writeInt(block [blockSize] [y]) ;
toNodeNext.flush() ;
for(int y = 0 ; y < N ; y++)
block [0] [y] = fromNodePrev.readInt() ;
// Shift this block's lower edge into prev neighbour's upper ghost edge
for(int y = 0 ; y < N ; y++)
toNodePrev.writeInt(block [1] [y]) ;
toNodePrev.flush() ;
for(int y = 0 ; y < N ; y++)
block [blockSize + 1] [y] = fromNodeNext.readInt() ;
/* Calculate a block of neighbour sums. */
for(int i = 0 ; i < blockSize ; i++) {
int ib = i + 1 ;
for(int y = 0 ; y < N ; y++) {
int y_n = (y - 1 + N) % N ;
int y_p = (y + 1) % N ;
neighbours [i] [y] =
block [ib - 1] [y_n] + block [ib - 1] [y] + block [ib - 1] [y_p] +
block [ib] [y_n] + block [ib] [y_p] +
block [ib + 1] [y_n] + block [ib + 1] [y] + block [ib + 1] [y_p] ;
}
}
/* Update block of board values. */
for(int i = 0 ; i < blockSize ; i++) {
int ib = i + 1 ;
for(int y = 0 ; y < N ; y++) {
int neighbour = neighbours [i] [y] ;
if(neighbour < 2 || neighbour > 3)
block [ib] [y] = 0 ;
if(neighbour == 3)
block [ib] [y] = 1 ;
}
}
/* Dump current state of board to host */
toHost.writeInt(blockSize * N) ;
for(int i = 0 ; i < blockSize ; i++) {
int ib = i + 1 ;
for(int y = 0 ; y < N ; y++)
toHost.writeInt(block [ib] [y]) ;
}
toHost.flush() ;
}
}
catch(Exception e) {
;
}
}
}