Adding a new example of jacobi2d with one data element per chare, and a liveViz
authorIsaac Dooley <idooley2@illinois.edu>
Wed, 11 Apr 2007 21:36:15 +0000 (21:36 +0000)
committerIsaac Dooley <idooley2@illinois.edu>
Wed, 11 Apr 2007 21:36:15 +0000 (21:36 +0000)
output. This is intended to be a course example from which the students will
write a game of life. There will be sharks eating fish and fish spawning at each
array element.

examples/charm++/jacobi2d-iter/Makefile [new file with mode: 0644]
examples/charm++/jacobi2d-iter/README [new file with mode: 0644]
examples/charm++/jacobi2d-iter/jacobi2d.C [new file with mode: 0644]
examples/charm++/jacobi2d-iter/jacobi2d.ci [new file with mode: 0644]
examples/charm++/jacobi2d-iter/runserver.sh [new file with mode: 0755]

diff --git a/examples/charm++/jacobi2d-iter/Makefile b/examples/charm++/jacobi2d-iter/Makefile
new file mode 100644 (file)
index 0000000..4c12794
--- /dev/null
@@ -0,0 +1,23 @@
+CHARMC=../../../bin/charmc -module liveViz $(OPTS)
+
+OBJS = jacobi2d.o
+
+all: jacobi2d
+
+jacobi2d: $(OBJS)
+       $(CHARMC) -language charm++ -o jacobi2d $(OBJS)
+
+jacobi2d.decl.h: jacobi2d.ci
+       $(CHARMC)  jacobi2d.ci
+
+clean:
+       rm -f *.decl.h *.def.h conv-host *.o jacobi2d charmrun
+
+jacobi2d.o: jacobi2d.C jacobi2d.decl.h
+       $(CHARMC) -c jacobi2d.C
+
+test: all
+       ./charmrun jacobi2d +p4 10
+
+bgtest: all
+       ./charmrun jacobi2d +p4 10 +x2 +y2 +z2
diff --git a/examples/charm++/jacobi2d-iter/README b/examples/charm++/jacobi2d-iter/README
new file mode 100644 (file)
index 0000000..827c791
--- /dev/null
@@ -0,0 +1,30 @@
+Jacobi iteration with a 2D Array.
+
+This code uses a 2-D blocked decomposition of a 2-d array with more
+than one element per chare. The code runs for a specified number of
+iterations, using a reduction to start each successive iteration.
+
+A 5-point stencil pattern is used to update the value for each data
+element. For example, the new value for element X is the current
+value of X plus the current values of its left, right, top, and
+bottom neighbors.
+
+     T
+   L X R
+     B
+
+X'  = (X + L + R + T + B) / 5.0
+
+
+To run the program with liveviz, run the parallel job as shown in
+runserver.sh, or just do a "./runserver.sh"
+
+While the program is running, connect a visualization client to that
+server. To do this you can run "charm/java/bin/liveViz localhost 1234"
+Note that port 1234 is the port specified in runserver.sh. You should
+at this point see a small window appear, with a black background, and
+a 64x64 pixel blue rectangle in the upper left corner. The parallel
+server job should also print out a series of lines whenever each worker
+is requested to provide a portion of the frame. Resizing the client
+window will cause the image to be requested again, but with a different
+size.
diff --git a/examples/charm++/jacobi2d-iter/jacobi2d.C b/examples/charm++/jacobi2d-iter/jacobi2d.C
new file mode 100644 (file)
index 0000000..6f030e0
--- /dev/null
@@ -0,0 +1,175 @@
+#include "liveViz.h"
+#include "jacobi2d.decl.h"
+
+// See README for documentation
+
+/*readonly*/ CProxy_Main mainProxy;
+
+/*readonly*/ int num_rows;
+/*readonly*/ int num_cols;
+
+CkArrayID a;
+
+#define total_iterations 128
+
+class Main : public CBase_Main
+{
+public:
+    int recieve_count;
+    CProxy_Jacobi array;
+    int num_chares;
+    int iterations;
+
+    Main(CkArgMsg* m) {
+        // set iteration counter to zero
+        iterations=0;
+
+        // store the main proxy
+        mainProxy = thisProxy;
+
+        // specify the number of worker chares in each dimension
+        num_rows = num_cols = 64;
+
+        // print info
+        CkPrintf("Running Jacobi on %d processors with (%d,%d) elements\n",
+            CkNumPes(), num_rows, num_cols);
+
+        // Create new array of worker chares
+        array = CProxy_Jacobi::ckNew(num_rows, num_cols);
+
+        // save the total number of worker chares we have in this simulation
+        num_chares = num_rows*num_cols;
+
+        // setup liveviz
+        CkCallback c(CkIndex_Jacobi::requestNextFrame(0),array);
+        liveVizConfig cfg(liveVizConfig::pix_color,false);
+        liveVizInit(cfg,a,c);
+
+        //Start the computation
+        recieve_count = 0;
+        array.begin_iteration();
+    }
+
+    // Each worker reports back to here when it completes an iteration
+    void report(int row, int col, float value) {
+        recieve_count++;
+        if (num_chares == recieve_count) {
+            if (iterations == total_iterations) {
+                CkPrintf("Completed %d iterations\n", iterations);
+                CkExit();
+            } else {
+                CkPrintf("starting new iteration.\n");
+                recieve_count=0;
+                iterations++;
+                // Call begin_iteration on all worker chares in array
+                array.begin_iteration();
+            }
+        }
+    }
+};
+
+class Jacobi: public CBase_Jacobi {
+public:
+    double temperature;
+
+    double update;
+    int messages_due;
+
+    // Constructor, initialize values
+    Jacobi() {
+       temperature = 1.0;
+    }
+
+    // a necessary function which we ignore now
+    // if we were to use load balancing and migration
+    // this function might become useful
+    Jacobi(CkMigrateMessage* m) {}
+
+
+    // Perform one iteration of work
+    // The first step is to send the local state to the neighbors
+    void begin_iteration(void) {
+        messages_due = 4;
+        update = 0.0;
+
+        // Nodes on an edge shouldn't send messages to non-existant chares.
+        if (thisIndex.x == 0)
+            messages_due--;
+        else
+            thisProxy(thisIndex.x-1, thisIndex.y).recieve_neighbor(thisIndex.x, thisIndex.y, temperature);
+
+
+        if (thisIndex.x == num_rows-1)
+            messages_due--;
+        else
+            thisProxy(thisIndex.x+1, thisIndex.y).recieve_neighbor(thisIndex.x, thisIndex.y, temperature);
+
+
+        if (thisIndex.y == 0)
+            messages_due--;
+        else
+            thisProxy(thisIndex.x, thisIndex.y-1).recieve_neighbor(thisIndex.x, thisIndex.y, temperature);
+
+
+        if (thisIndex.y == num_cols-1)
+            messages_due--;
+        else
+            thisProxy(thisIndex.x, thisIndex.y+1).recieve_neighbor(thisIndex.x, thisIndex.y, temperature);
+
+
+        check_done_iteration();
+    }
+
+    void recieve_neighbor(int neighbor_x, int neighbor_y, float t) {
+        // we have just received a message from worker neighbor_x,neighbor_y with
+        // a its current temperature. This worker's index is thisIndex.x, thisIndex.y
+        update += t;
+        messages_due--;
+        check_done_iteration();
+    }
+
+
+    // check to see if we have received all neighbor values yet
+    void check_done_iteration() {
+        if (messages_due == 0) {
+            temperature = (update+temperature) / 5.0;
+            mainProxy.report(thisIndex.x, thisIndex.y, 1.0);
+        }
+    }
+
+
+    // provide my portion of the image to the graphical liveViz client
+    // Currently we just provide some pretty color depending upon the thread id
+    // In a real program we would provide a colored rectangle or pixel that
+    // depends upon the local thread data.
+    void requestNextFrame(liveVizRequestMsg *m){
+        int wdes = m->req.wid;
+        int hdes = m->req.ht;
+
+        CkPrintf("%d,%d requestNextFrame() with desired size %dx%d\n", thisIndex.x, thisIndex.y, wdes, hdes);
+
+        // I will just deposit a single colored pixel to liveviz
+        // Normally you would deposit some rectangular region
+
+        // where to deposit
+        int sx=thisIndex.x;
+        int sy=thisIndex.y;
+        int w=1,h=1; // Size of my rectangular part of the image
+
+        // set the output pixel values for my rectangle
+        // Each component is a char which can have 256 possible values.
+        unsigned char *intensity= new unsigned char[3*w*h];
+        intensity[0] = (4*(256+thisIndex.x-thisIndex.y)) % 256; // RED component
+        intensity[1] = (4*(thisIndex.x+thisIndex.y)) % 256; // BLUE component
+        intensity[2] = (4*thisIndex.y) % 256; // GREEN component
+
+        liveVizDeposit(m, sx,sy, w,h, intensity, this);
+        delete[] intensity;
+
+    }
+
+
+
+};
+
+#include "jacobi2d.def.h"
diff --git a/examples/charm++/jacobi2d-iter/jacobi2d.ci b/examples/charm++/jacobi2d-iter/jacobi2d.ci
new file mode 100644 (file)
index 0000000..033b6f1
--- /dev/null
@@ -0,0 +1,20 @@
+mainmodule jacobi2d {
+  readonly CProxy_Main mainProxy;
+  readonly int num_rows;
+  readonly int num_cols;
+
+  mainchare Main {
+    entry Main(CkArgMsg *m);
+    entry void report(int, int, float);
+  };
+
+  array [2D] Jacobi {
+    // Normal Charm++ entry methods
+    entry Jacobi(void);
+    entry void begin_iteration(void);
+    entry void recieve_neighbor(int,int,float);
+
+    // A method for requesting data to be displayed graphically to the user
+    entry void requestNextFrame(liveVizRequestMsg *m);
+  };
+};
diff --git a/examples/charm++/jacobi2d-iter/runserver.sh b/examples/charm++/jacobi2d-iter/runserver.sh
new file mode 100755 (executable)
index 0000000..b07dc8c
--- /dev/null
@@ -0,0 +1,5 @@
+#!/bin/sh
+echo "Starting up server:"
+./charmrun +p4 ./jacobi2d ++server ++server-port 1234
+echo "Server Exited"
+