Added bluegene emulator sources and test programs.
authorMilind Bhandarkar <milind@cs.uiuc.edu>
Fri, 15 Dec 2000 17:30:56 +0000 (17:30 +0000)
committerMilind Bhandarkar <milind@cs.uiuc.edu>
Fri, 15 Dec 2000 17:30:56 +0000 (17:30 +0000)
Added "bluegene" as a language known to charmc.
Makefile now has a target called bluegene.
Added preliminary bluegene documentation.
(copied from Arun's webpage.)

doc/Makefile
doc/bigsim/Makefile [new file with mode: 0644]
doc/bigsim/manual.tex [new file with mode: 0644]
src/langs/bluegene/BlueGene.C [new file with mode: 0644]
src/langs/bluegene/BlueGene.ci [new file with mode: 0644]
src/langs/bluegene/BlueGene.h [new file with mode: 0644]
src/scripts/Makefile
src/scripts/charmc

index 693a16ab162c969305a7ac90cec3ea80e0af7ddd..88a3e06f6ae17b856a75b50f0547bd48495eb34b 100644 (file)
@@ -14,6 +14,7 @@ ps:
        ( cd f90charm; $(LNCMD); make ps )
        ( cd fem; $(LNCMD); make ps )
        ( cd ampi; $(LNCMD); make ps )
+       ( cd bluegene; $(LNCMD); make ps )
 
 pdf:
        if [ ! -d $(IDIR)/pdf ] ; then mkdir $(IDIR)/pdf ; fi
@@ -26,6 +27,7 @@ pdf:
        ( cd f90charm; $(LNCMD); make pdf )
        ( cd fem; $(LNCMD); make pdf )
        ( cd ampi; $(LNCMD); make pdf )
+       ( cd bluegene; $(LNCMD); make pdf )
 
 html:
        if [ ! -d $(IDIR)/html ] ; then mkdir $(IDIR)/html ; fi
@@ -38,6 +40,7 @@ html:
        ( cd f90charm; $(LNCMD); make html )
        ( cd fem; $(LNCMD); make html )
        ( cd ampi; $(LNCMD); make html )
+       ( cd bluegene; $(LNCMD); make html )
 
 clean:
        ( cd install; $(RMCMD); make clean )
@@ -49,3 +52,4 @@ clean:
        ( cd f90charm; $(RMCMD); make clean )
        ( cd fem; $(RMCMD); make clean )
        ( cd ampi; $(RMCMD); make clean )
+       ( cd bluegene; $(RMCMD); make clean )
diff --git a/doc/bigsim/Makefile b/doc/bigsim/Makefile
new file mode 100644 (file)
index 0000000..1e6e1b7
--- /dev/null
@@ -0,0 +1,36 @@
+PSDIR=../../../doc/ps
+PDFDIR=../../../doc/pdf
+HDIR=../../../doc/html
+
+all: ps pdf html
+
+ps:
+       make clean
+       touch index.tex
+       latex manual.tex
+       latex manual.tex
+       if [ -f manual.idx ] ; then makeindex -o index.tex manual.idx ; fi
+       latex manual.tex
+       dvips -o manual.ps manual.dvi
+       /bin/cp manual.ps $(PSDIR)/bluegene.ps
+
+html:
+       make clean
+       touch index.tex
+       latex manual.tex
+       latex2html -local_icons manual.tex
+       /bin/rm -rf $(HDIR)/bluegene
+       /bin/cp -R manual $(HDIR)/bluegene
+
+pdf:
+       make clean
+       touch index.tex
+       pdflatex manual.tex
+       if [ -f manual.idx ] ; then makeindex -o index.tex manual.idx ; fi
+       pdflatex manual.tex
+       /bin/cp manual.pdf $(PDFDIR)/bluegene.pdf
+
+clean:
+       /bin/rm -f *.ps *.pdf *.ilg *.aux *.log *.dvi *.idx *.toc 
+       /bin/rm -f index.tex *.blg *.bbl
+       /bin/rm -rf manual
diff --git a/doc/bigsim/manual.tex b/doc/bigsim/manual.tex
new file mode 100644 (file)
index 0000000..7726067
--- /dev/null
@@ -0,0 +1,542 @@
+\documentclass[10pt]{article}
+\usepackage{pplmanual}
+\input{../pplmanual}
+
+\title{Bluegene Emulator}
+\version{0.01}
+\credits{BlueGene Emulator was developed by Arun Singla, Neelam Saboo
+and Joshua Unger under the guidance of Prof. L. V. Kale.}
+
+\begin{document}
+\maketitle
+
+\section{Introduction}
+
+Blue Gene is a proposed one million processor machine from IBM.
+
+The Blue Gene emulator environment is designed with the following
+objectives:
+
+\begin{enumerate}
+\item To support a realistic Blue Gene API on existing parallel machines
+
+\item To obtain first-order performance estimates of algorithms
+
+\item To facilitate implementations of alternate programming models for
+      Blue Gene
+\end{enumerate}
+
+The ``Blue Gene'' machine supported by the emulator consists of
+three-dimensional grid of 1-chip nodes.  The user may specify the size
+of the machine along each dimension (e.g. 34x34x36).  The chip supports
+$k$ threads (e.g. 200), each with its own integer unit.  The proximity of
+the integer unit with individual memory modules within a chip is not
+currently modeled.
+
+The API supported by the emulator can be broken down into several
+components:
+
+\begin{enumerate}
+\item Low-level API for chip-to-chip communication
+\item Mid-level API that supports local micro-tasking with a chip level
+scheduler with features such as: read-only variables, reductions, broadcasts,
+distributed tables, get/put operations
+\item Migratable objects with automatic load balancing support
+\end{enumerate}
+
+Of these, the first two have been implemented.  The simple time stamping
+algorithm, without error correction, has been implemented.  More
+sophisticated timing algorithms, specifically aimed at error correction,
+and more sophisticated features (2, 3, and others), as well as libraries
+of commonly needed parallel operations are part of the proposed work for
+future.
+
+The following sections define the appropriate parts of the API, with
+example programs and instructions for executing them.
+
+\section{Blue Gene Programming Environment}
+
+The basic philosophy of the Blue Gene Emulator is to hide intricate details
+of Blue Gene machine from
+application developer.Thus, the application developer needs to provide
+intialization details and handler
+functions only and gets the result as though running on a real machine.
+Communication, Thread creation,
+Time Stamping, etc are done by the emulator.
+
+\subsection{Blue Gene API: Level 0}
+
+\function{void putMessage(PacketMsg *)}
+\desc{
+        chip-to-chip communication function, invoked by Blue Gene
+        environment when a node calls sendPacket
+        to put the message in the inBuffer of target node.
+}
+
+\function{boolean checkReady()}
+\desc{
+        invoked by communication thread to see if there is any unattended
+        message in inBuffer.
+}
+
+\function{PacketMsg *getMessage()}
+\desc{
+        invoked by communication thread to retrieve the unattended message
+        in inBuffer.
+}
+
+\subsection{Initialization API: Level 1a}
+
+Execution starts at BgInit(Main *), where Blue Gene machine parameters are
+initialized.
+
+\function{void CreateBlueGene(CreateBgNodeMsg *msg)}
+\desc{
+Specifies the machines configuration in CreateBgNodeMsg.
+}
+
+Data required for initialization of Node is specified in a system
+defined type CreateBgNodeMsg.
+
+\begin{alltt}
+        class CreateBgNodeMsg
+        \{
+                public:
+                  int numCTh ;
+                  int numWTh ;
+                  int numBgX ;
+                  int numBgY ;
+                  int numBgZ ;
+        \} ;
+\end{alltt}
+
+\function{int  getNumArgs()}
+\desc{
+Return the number of command line arguments
+}
+
+\function{const char** getArgs()}
+\desc{
+Return command line arguments
+}
+
+\function{typedef void (*BgHandler)(void*)}
+\desc{
+This is type defined in BlueGene.h. It represents a handler function
+that returns nothing and takes a (void *)
+}
+
+The Runtime system calls BgNodeInit(BgNode *) for each node, where
+application handlers are registered and
+computation is triggered by creating a task at required nodes. The Node
+Variables are encapsulated in a struct
+definition and a pointer to this (node private variable) is returned.
+
+\function{void  registerHandler(int handlerID, BgHandler h)}
+\desc{
+Register a Handler with each node
+}
+
+\function{void addMessage(PacketMsg *msgPtr, int handlerID, int threadCategory)}
+\desc{
+Create a micro-task, specifiy the handler function to be
+used for this message i.e. handlerID, and
+specify the thread category:
+\begin{description}
+\item[1:] a small piece of work that can be done by
+communication thread itself, so NO scheduling overhead.
+\item[0:] a large piece of work, so communication thread
+schedules it for a worker thread
+\end{description}
+}
+
+InterNode communication messages are to be inherited from PacketMsg
+
+\begin{alltt}
+        class PacketMsg
+        \{
+            public:
+                  int srcX ;
+                  int srcY ;
+                  int srcZ ;
+                  int destX ;
+                  int destY ;
+                  int destZ ;
+                  int numBytes ;
+                  double sendTime ;
+                  double recvTime ;
+        \} ;
+\end{alltt}
+
+After completion of execution, Blue Gene environment invokes a user defined
+function BgFinish().
+
+\subsection{Handler Function API: Level 1a}
+
+\function{void sendPacket(int x, int y, int z, PacketMsg *msgPtr, int handlerID, int threadCategory)}
+\desc{
+Sends a PacketMsg pointer to Node[x,y,z] and also specifies the
+handler function to be used for this message ie. handlerID,
+specify the thread category:
+\begin{description}
+\item[1:] a small piece of work that can be done by
+communication thread itself, so NO scheduling overhead.
+\item[0:] a large piece of work, so communication thread
+schedules it for a worker thread
+\end{description}
+}
+
+\function{void getXYZ(int& x, int& y, int& z)}
+\desc{
+Gets which Blue Gene node do the invoking thread belongs to
+}
+
+\function{double getTime()}
+\desc{
+Returns current time of thread in microseconds (execution time since
+the application started)
+}
+
+
+\section{Writing a Blue Gene Application}
+
+\subsection{Application Skeleton}
+
+\begin{alltt}
+Handler declarations
+Application specific messages, inherited from PacketMsg
+Struct definitions encapsulating Node (specific) variables
+
+void  BgInit(Main *)  function
+  Make a Blue Gene node creation message, CreateBgNodeMsg
+  Initialize number of Communication Threads and 
+    number of Worker Threads per node
+  Initialize number of Blue Gene nodes in X, Y, and Z dimension.
+  Initialize the emulator by calling CreateBlueGene(CreateBgNodeMsg)
+
+void *BgNodeInit(BgNode *) function
+  Register handlers, registerHandler(handlerID, handler)
+  Send initialization message packets to node, 
+    addMessage(messagePointer, handlerID)
+  Declare Node Variables (struct) and return a pointer to it.
+
+void  BgFinish()  function
+  detects Quiescence
+
+Handler Function 1, void handlerName(ThreadInfo *info)
+Hanlder Function 2, void handlerName(ThreadInfo *info)
+..
+Handler Function N, void handlerName(ThreadInfo *info)
+
+\end{alltt}
+
+\subsection{Sample Application 1}
+
+\begin{alltt}
+/* Application: 
+ *   Each node starting at [0,0,0] sends a packet to next node in
+ *   the ring order.
+ *   After node [0,0,0] gets message from last node
+ *   in the ring, the application ends.
+ */
+
+#include "BlueGene.h"
+#define  computeID 1
+
+extern "C" void compute(ThreadInfo *) ;
+
+class MyMsg : public PacketMsg
+\{
+public:
+  int dummy ;
+\} ;
+
+
+void BgInit(Main *main)
+\{
+  int num_comm = 1, num_work = 2;       // default number of communication
+                                        // and worker threads per node
+  int num_args = main->getNumArgs();
+  if (num_args < 4) \{ 
+    // Abort application: insufficient number of arguments
+    CkAbort("Usage: ring <x> <y> <z> [<numCommTh> <numWorkTh>]\n"); 
+  \}
+
+  if (num_args > 5) \{ num_work = atoi(main->getArgs()[5]); \}
+  if (num_args > 4) \{ num_comm = atoi(main->getArgs()[4]); \}
+
+  CreateBgNodeMsg *bgNodeMsg = new CreateBgNodeMsg;
+  bgNodeMsg->numBgX = atoi(main->getArgs()[1]);
+  bgNodeMsg->numBgY = atoi(main->getArgs()[2]);
+  bgNodeMsg->numBgZ = atoi(main->getArgs()[3]);
+  bgNodeMsg->numCTh = num_comm;
+  bgNodeMsg->numWTh = num_work;
+
+  main->CreateBlueGene(bgNodeMsg);
+  return;
+\}
+
+void* BgNodeInit(BgNode *bgNode)
+\{
+  bgNode->registerHandler(computeID, compute) ;
+
+  // trigger computation at Node[0,0,0]
+  if(bgNode->thisIndex.x==0 && bgNode->thisIndex.y==0 && bgNode->thisIndex.z==0)
+  \{
+   MyMsg *msg = new MyMsg ;
+   msg->dummy = 0 ;
+   bgNode->addMessage(msg, computeID, 0) ;
+  \}
+  return NULL;    // No node variables for this example
+\}
+
+void BgFinish() \{\}
+
+void compute(ThreadInfo *info)
+\{
+  int i, j, k ;
+  int ni, nj, nk ;
+
+  info->bgNode->getXYZ(i,j,k) ;
+
+  if(i==info->bgNode->numBgX-1 && j==info->bgNode->numBgY-1 && 
+     k==info->bgNode->numBgZ-1)
+  \{
+           ckout << "Exiting" << endl ;
+           info->bgNode->finish() ;
+           return ;
+  \}
+
+  nk = k + 1 ;
+  nj = j ;
+  ni = i ;
+  if( nk==info->bgNode->numBgZ )
+  \{
+          nk = 0 ;
+         nj = j+1 ;
+         if ( nj==info->bgNode->numBgY )
+         \{
+                nj = 0 ;
+                ni = i+1 ;
+                if ( ni==info->bgNode->numBgX ) \{
+                    ni = 0 ;
+                \}
+         \}
+  \}
+  MyMsg *msg = new MyMsg ;
+  msg->dummy = i+j+k ;
+  info->bgNode->sendPacket(ni, nj, nk, msg, computeID, 0) ;
+\}
+
+
+\subsection{Sample Application 2}
+
+/* Application: 
+ *   Find the maximum element.
+ *   Each node computes maximum of it's elements and
+ *   the max values it received from other nodes
+ *   and sends the result to next node in the reduction sequence.
+ * Reduction Sequence: Reduce max data to X-Y Plane
+ *   Reduce max data to Y Axis
+ *   Reduce max data to origin.
+ */
+
+#include "BlueGene.h"
+
+#define A_SIZE 4
+
+#define reduceID                    1
+#define computeMaxID        2
+#define contributeID             3
+
+//handler declarations
+void reduce(ThreadInfo *) ;
+void computeMax(ThreadInfo *) ;
+void contribute(ThreadInfo *) ;
+
+//Application specifice messages inherited from PacketMsg
+class contributeMsg: public PacketMsg
+\{
+public:
+  int max ;
+\} ;
+
+class computeMaxMsg: public PacketMsg
+\{\} ;
+
+class reduceMsg: public PacketMsg
+\{\} ;
+
+//Node variables encapsulated in a struct definition
+typedef struct userDataStruct
+\{
+  int data[A_SIZE] ;
+  int count ;
+\} userData ;
+
+void BgInit(Main *main)
+\{
+  int num_comm = 1, num_work = 2;       // default number of communication
+and worker threads
+  int num_args = main->getNumArgs();
+  if (num_args < 4) \{ 
+    CkAbort("Usage: maxReduceNV <x> <y> <z> [<numCommTh> <numWorkTh>]\n"); 
+  \}
+  if (num_args > 5) \{ num_work = atoi(main->getArgs()[5]); \}
+  if (num_args > 4) \{ num_comm = atoi(main->getArgs()[4]); \}
+
+  CreateBgNodeMsg *bgNodeMsg = new CreateBgNodeMsg;
+  bgNodeMsg->numBgX = atoi(main->getArgs()[1]);
+  bgNodeMsg->numBgY = atoi(main->getArgs()[2]);
+  bgNodeMsg->numBgZ = atoi(main->getArgs()[3]);
+  bgNodeMsg->numCTh = num_comm;
+  bgNodeMsg->numWTh = num_work;
+
+  main->CreateBlueGene(bgNodeMsg);
+  return;
+\}
+
+void* BgNodeInit(BgNode *bgNode)
+\{
+  //register handlers
+  bgNode->registerHandler(reduceID, reduce) ;
+  bgNode->registerHandler(computeMaxID, computeMax) ;
+  bgNode->registerHandler(contributeID, contribute) ;
+
+  //triger computer at each node
+  computeMaxMsg *msg = new computeMaxMsg;
+  bgNode->addMessage(msg, computeMaxID, 0);
+
+  //declare node variable and return a pointer
+  userData *ud = new userData ;
+  ud->count = 0 ;
+  for(int i=0; i<A_SIZE; i++)
+   ud->data[i] = 0 ;
+
+  return (void*)ud ;
+\}
+
+void BgFinish()
+\{\}
+
+void computeMax(ThreadInfo *info)
+\{
+  int A[A_SIZE][A_SIZE];
+  int i, j;
+  int max = 0;
+
+  int x,y,z;
+  info->bgNode->getXYZ(x,y,z);
+
+  // Initialize data in each node
+  for (i=0;i<A_SIZE;i++)
+    for (j=0;j<A_SIZE;j++)
+      A[i][j] = info->bgNode->numBgX * info->bgNode->numBgY * 
+                info->bgNode->numBgZ - x*y*z - i*j ;
+
+  // Find Max
+  for (i=0;i<A_SIZE;i++)
+    for (j=0;j<A_SIZE;j++)
+      if (max < A[i][j])
+      \{
+             max = A[i][j];
+      \}
+
+  // contribute the results for reduction
+  contributeMsg *msg = new contributeMsg;
+  msg->max = max;
+  info->bgNode->addMessage(msg,contributeID,1);
+
+  ckout << "computeMax in " << x << ", " << y << ", " << z << endl;
+  ckout << "contributed max value " << max << endl;
+\}
+
+void contribute(ThreadInfo *info)
+\{
+  int x,y,z;
+  info->bgNode->getXYZ(x,y,z);
+
+  // Accessing node variables : get number of data values received at this node
+  int count = ((userData*)(info->bgNode->nvData))->count++ ;
+  // Store new contribution to node variables
+  ((userData*)(info->bgNode->nvData))->data[count++] =
+((contributeMsg*)(info->msg))->max ;
+
+ // Compute the required Count of data values at each node to start reduction 
+ // at that node, depends on reduction sequence
+  int reqCount ;
+
+  if(z==info->bgNode->numBgZ-1)
+  \{
+         reqCount = 1 ;
+  \}
+  else if(z>0 || (z==0 && x==info->bgNode->numBgX-1))
+  \{
+         reqCount = 2 ;
+  \}
+  else if(x>0 || (x==0 && y==info->bgNode->numBgY-1))
+  \{
+         reqCount = 3 ;
+  \}
+  else
+         reqCount = 4 ;
+
+  if(count==reqCount)     //if data for reduction is ready
+  \{
+       reduceMsg *msg = new reduceMsg ;
+       info->bgNode->addMessage(msg, reduceID, 0) ;
+       ckout << "contribute in Node " << x << ", " << y << ", " << z << endl;
+       ckout << "Values collected " << count << ", calling reduction " << endl;
+       return ;
+  \}
+
+  ckout << "contribute in Node " << x << ", " << y << ", " << z << endl ;
+  ckout << "Values collected " << count << ", reqCount " << reqCount << endl;
+\}
+
+void reduce(ThreadInfo *info)
+\{
+  int x,y,z;
+  info->bgNode->getXYZ(x,y,z);
+  ckout << "reduce in " << x << ", " << y << ", " << z << endl;
+
+  //do reduction
+  int max = 0 ;
+  int count = ((userData*)(info->bgNode->nvData))->count ;
+  for(int i=0; i<count; i++)
+  \{
+           if(max<((userData*)(info->bgNode->nvData))->data[i])
+           max = ((userData*)(info->bgNode->nvData))->data[i] ;
+  \}
+
+  if(x==0 && y==0 && z==0)
+  \{
+         ckout << "Exiting: max value is " << max << endl ;
+         info->bgNode->finish() ;
+         return ;
+  \}
+
+  //send max to destination, depends on reduction sequence
+  if(z>0)
+   z-- ;
+  else if(x>0)
+   x-- ;
+  else
+   y-- ;
+
+  contributeMsg *msg = new contributeMsg;
+  msg->max = max;
+  info->bgNode->sendPacket(x,y,z,msg,contributeID,1);
+
+  ckout << "sending max value " << max << " to " << x << ", " << y << ", " << z << endl ;
+\}
+
+\section{Compiling and Running}
+
+Compile Blue Gene emulator programs using {\tt charmc} as one would
+in the case of normal \charmpp{} programs. In order to link the
+Blue Gene programs, use \texttt{-language bluegene} as an argument
+to the {\tt charmc} linker.
+
+\input{index}
+\end{document}
diff --git a/src/langs/bluegene/BlueGene.C b/src/langs/bluegene/BlueGene.C
new file mode 100644 (file)
index 0000000..8a4a804
--- /dev/null
@@ -0,0 +1,437 @@
+// File: BlueGene.C
+
+#define protected public
+#include "BlueGene.h"
+
+#define CYCLES_PER_HOP    5
+#define CYCLES_PER_CORNER  75
+#define CYCLE_TIME_FACTOR  0.001  // one cycle = nanosecond = 10^(-3) us  
+
+CkChareID mainID ;
+CkArrayID bgArrayID ;
+
+//Main methods 
+/*
+ * 'Main' calls 'BgInit', defined in user application for initialization 
+ * of bluegene machine.
+ */
+Main::Main(CkArgMsg *msg)
+{
+  args = msg ;
+  mainID = thishandle ;
+
+  if (msg->argc < 6) { 
+    CkAbort("Usage: <program> <x> <y> <z> <numCommTh> <numWorkTh>\n"); 
+  }
+    
+  CreateBgNodeMsg *bgNodeMsg = new CreateBgNodeMsg;
+  numBgX = bgNodeMsg->numBgX = atoi(msg->argv[1]) ;
+  numBgY = bgNodeMsg->numBgY = atoi(msg->argv[2]) ; 
+  numBgZ = bgNodeMsg->numBgZ = atoi(msg->argv[3]) ;
+  bgNodeMsg->numCTh = atoi(msg->argv[4]) ;
+  bgNodeMsg->numWTh = atoi(msg->argv[5]) ;
+
+  CreateBlueGene(bgNodeMsg) ;
+
+  BgInit(this) ;
+  starttime = CkWallTimer();
+  return ;
+}
+
+Main::~Main()
+{
+  CProxy_BgNode bgArray(bgArrayID) ;
+
+  for( int i=0; i<numBgX; i++ )
+  for( int j=0; j<numBgY; j++ )
+  for( int k=0; k<numBgZ; k++ )
+  bgArray(i, j, k).destroy() ;
+}
+
+int Main::getNumArgs()
+{
+  return args->argc ;
+}
+
+const char** Main::getArgs()
+{
+  return (const char**)args->argv ;
+}
+
+/*
+ * 'CreateBlueGene' initializes BlueGene machine
+ * Specifies the machine configuration
+ *   - Number of BgNodes in X, Y, and Z dimension
+ *  - Number of Communication threads per BgNode
+ *  - Number of Worker threads per BgNode
+ *  - more: would also include latencies, cycles per hop, cycles per corner, etc
+ */
+void Main::CreateBlueGene(CreateBgNodeMsg *msg)
+{
+  bgArrayID = CProxy_BgNode::ckNew() ;
+  CProxy_BgNode bgArray(bgArrayID) ;  
+  for( int i=0; i<msg->numBgX; i++ )
+  for( int j=0; j<msg->numBgY; j++ )
+  for( int k=0; k<msg->numBgZ; k++ )
+  {
+    CreateBgNodeMsg *tempMsg = new CreateBgNodeMsg ;
+    tempMsg->numCTh = msg->numCTh ;
+    tempMsg->numWTh = msg->numWTh ;
+    tempMsg->numBgX = msg->numBgX ;
+    tempMsg->numBgY = msg->numBgY ;
+    tempMsg->numBgZ = msg->numBgZ ;
+    bgArray(i, j, k).insert(tempMsg) ;
+  }
+  bgArray.doneInserting() ;
+  delete msg ;
+}
+
+/*
+ * 'Finish' is a simple implementation for informing the system that 
+ * application has finished.
+ * more: should be modified to include quiescense detection: no hurry.
+ */
+void Main::Finish(void) 
+{
+  endtime = CkWallTimer();
+  ckout << "Total time : " << (endtime-starttime)*10.0 
+        << " microseconds per ring" << endl;
+  CkExit() ;
+}
+
+static void defaultHandler(ThreadInfo *)
+{
+  CkAbort("BG> Invalid Handler called.\n");
+}
+
+//BgNode methods~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+/*
+ * 'BgNode' is initialization of a Blue Gene Node/CHIP.
+ *   - Create a (node-private) inBuffer, schedulerQ's, internal tables
+ *  - Creates all communication and worker threads.
+ *  - Calls 'BgNodeInit', user defined application function, where user registers 
+ *    the handlers for this BgNode and may trigger some message as microtasks or may 
+ *    send some messages to other nodes.
+ */
+BgNode::BgNode(CreateBgNodeMsg *msg)
+{
+  numCTh = msg->numCTh ;
+  numWTh = msg->numWTh ;
+  numBgX = msg->numBgX ;
+  numBgY = msg->numBgY ;
+  numBgZ = msg->numBgZ ;
+
+  inBuffer     = new InBuffer(this) ;
+  workThQ      = new SchedulerQ(numWTh) ;
+  commForMsg   = new SchedulerQ(numCTh) ;
+  commForWork  = new SchedulerQ(numCTh) ;
+  matchTable   = new PacketMsg*[numCTh+numWTh] ;
+  threadTable  = new CthThread[numCTh+numWTh] ;
+  handlerTable = new BgHandler[MAX_HANDLERS] ;
+  addMsgQ      = new MsgQ;
+
+  for(int i=0; i<MAX_HANDLERS; i++)
+    handlerTable[i] = (BgHandler) defaultHandler;
+  for(int i=0; i<(numCTh+numWTh); i++)
+    matchTable[i] = 0;
+  proxies = new CProxy_BgNode***[numBgX];
+  for(int i=0;i<numBgX;i++) {
+    proxies[i] = new CProxy_BgNode**[numBgY];
+    for(int j=0;j<numBgY;j++) {
+      proxies[i][j] = new CProxy_BgNode*[numBgZ];
+      for(int k=0;k<numBgZ;k++) {
+        proxies[i][j][k] = new CProxy_BgNode(bgArrayID, 
+                                             new CkArrayIndex3D(i,j,k));;
+      }
+    }
+  }
+
+  delete msg ;
+
+  //Create Communication Thread and enter in threadTable and sleep them in commForMsg
+  for(int i=0; i<numCTh; i++)
+  {
+    ThreadInfo *info = new ThreadInfo() ;
+    info->bgNode = this ;
+    info->selfID = i ;
+    CthThread t = CthCreate((CthVoidFn)::startCommTh, (void*)info , 0) ;
+    threadTable[i] = t ;
+    CthAwaken(t) ;
+  }
+
+  //Create worker Thread and enter in threadTable and sleep them in workThQ
+  for(int i=0; i<numWTh; i++)
+  {
+    ThreadInfo *info = new ThreadInfo() ;
+    info->bgNode = this ;
+    info->selfID = i + numCTh ;
+    CthThread t = CthCreate((CthVoidFn)::startWorkTh, (void*)info , 0) ;
+    threadTable[i+numCTh] = t;
+    CthAwaken(t) ;
+  }
+
+  nvData = (void*)BgNodeInit(this) ;
+}
+
+BgNode::~BgNode()
+{
+  delete inBuffer ;
+  delete[] matchTable ;
+  delete[] threadTable ;
+  delete[] handlerTable ;
+  delete workThQ ;
+  delete commForMsg ;
+}
+
+void BgNode::registerHandler(int handlerID, BgHandler h) 
+{
+  if(handlerID >= MAX_HANDLERS)
+    CkAbort("BG> Handler ID exceeded maximum.\n");
+  handlerTable[handlerID] = h;
+}
+
+/*
+ * Assign the MicroTask in PacketMsg to a free communication thread of the same BgNode.
+ * If all the communication threads are busy, allocate it to default communication thread '0'.
+ * The communication thread would schedule it.
+ * more: change this default stuff to an appropriate load-balanced-strategy
+ */
+ //more: change it
+void BgNode::addMessage(PacketMsg *msgPtr, int handlerID, WorkType type)
+{
+  msgPtr->handlerID  = handlerID ;
+  msgPtr->type = type ;
+
+  //get a communication thread ID, if available, else  enque to added messages
+  int commThID ;
+  if(-1 == (commThID = commForMsg->dequeThread()))
+  {
+    addMsgQ->enq(msgPtr);
+    return;
+  }
+
+  matchTable[commThID] = msgPtr;
+
+  //get thread address and awaken it 
+  CthThread t = threadTable[commThID] ;
+  CthAwaken(t) ;
+}
+
+/* 
+ * Put PacketMsg to inBuffer
+ * If inBuffer is Full then sleep for some time and retry.
+ */
+void BgNode::putMessage(PacketMsg *msgPtr)
+{
+  inBuffer->putMessage(msgPtr);
+}
+
+#define ABS(x) (((x)<0)? -(x) : (x))
+
+static inline double MSGTIME(int ox, int oy, int oz, int nx, int ny, int nz)
+{
+  int xd=ABS(ox-nx), yd=ABS(oy-ny), zd=ABS(oz-nz);
+  int ncorners = 2;
+  ncorners -= (xd?1:0 + yd?1:0 + zd?1:0);
+  ncorners = (ncorners<0)?0:ncorners;
+  return ncorners*CYCLES_PER_CORNER + (xd+yd+zd)*CYCLES_PER_HOP;
+}
+/*
+ * Send PacketMsg to BgNode[x,y,z]
+ * Set appropriate timestamps:
+ *  sendTime = currTime
+ *      recvTime = estimated time to reach the destination BgNode
+ */
+void 
+BgNode::sendPacket(int x, int y, int z, PacketMsg *msgPtr, 
+                   int handlerID, WorkType type)
+{
+  msgPtr->handlerID = handlerID ;
+  msgPtr->type = type ;
+
+  msgPtr->recvTime = MSGTIME(thisIndex.x,thisIndex.y,thisIndex.z,x,y,z)
+                   + msgPtr->sendTime ;
+
+  proxies[x][y][z]->putMessage(msgPtr) ;
+}
+
+/*
+ * Assign the new Message in inBuffer to a free communication thread for scheduling.
+ * If all the communication threads are busy, then leave message in inBuffer and don't worry.
+ */
+void BgNode::assignMsg()
+{
+  int commThID = commForMsg->dequeThread() ;
+  
+  if(-1 == commThID)
+  {
+    /* ckout << "leaving assignMsg: didn't find commTh " << endl ; */
+    return ;
+  }
+
+  CthThread t = threadTable[commThID] ;
+  CthAwaken(t) ;
+
+  return ;
+}
+
+/*
+ * Start the communication thread as soon as it is created.
+ * The thread calls 'getMessage' on inBuffer to see if there is any 
+ * pending message.
+ *   If any, then get it from inBuffer and schedule it.
+ *  If new message is a small piece of work i.e. type == SMALL_WORK, execute it
+ *      else assign it to a free worker thread
+ *
+ * If there is no pending message in inBuffer, it looks in MatchTable to see if there is
+ * any microtask allocated to it. If any, it schedules it.
+ *  If the microtask is small piece of work then execute it and remove from matchTable 
+ *   else assign it to a free worker thread
+ *
+ * If no message, then sleep until no new message or microtask awakens it.
+ */
+void BgNode::startCommTh(ThreadInfo *info)
+{
+  PacketMsg *msgPtr = 0;
+  int selfID = info->selfID;
+  info->currTime = 0 ;
+
+  double tp1, tp2 ;
+  tp1 = BGTimer()*1e6;
+  while(true)
+  {
+    msgPtr = 0; 
+
+    msgPtr = inBuffer->getMessage();
+    if(msgPtr==0) { msgPtr=matchTable[selfID]; matchTable[selfID] = 0; }
+    if(msgPtr==0) { msgPtr=addMsgQ->deq(); }
+      
+    if(msgPtr==0)
+    {
+      //suspend thread
+      tp2 = BGTimer()*1e6;
+      info->currTime += (tp2-tp1) ;
+      commForMsg->enqueThread(selfID) ;
+      CthSuspend() ;
+      tp1 = BGTimer()*1e6;
+      continue ;
+    }
+
+    if(SMALL_WORK==msgPtr->type)
+    {
+      BgHandler handler = handlerTable[msgPtr->handlerID];
+      info->msg    = (void*)msgPtr ; 
+  
+      tp2 = BGTimer()*1e6;
+      info->currTime += (tp2-tp1) ;
+      //make timing adjustments for thread
+      if(msgPtr->recvTime > info->currTime)
+      info->currTime = msgPtr->recvTime ;
+      info->handlerStartTime = tp2 ;
+  
+      tp1 = tp2 ;
+      handler(info) ;
+      continue ;
+    }
+    else if(msgPtr->type==LARGE_WORK)
+    {
+      //get a worker thread ID, if available, else do polling
+      int workThID ; 
+      while(-1 == (workThID = workThQ->dequeThread()))
+      {
+        tp2 = BGTimer()*1e6;
+        info->currTime += (tp2-tp1) ;
+        commForWork->enqueThread(selfID);
+        CthSuspend();
+        tp1 = BGTimer()*1e6;
+      }
+
+      matchTable[workThID] = msgPtr;
+
+      //get thread address and awaken it 
+      CthThread t = threadTable[workThID] ;
+      CthAwaken(t) ;
+      continue ;
+    }
+    else
+      ckout << "Unidentified thread category, error" << endl ;
+  }
+}
+
+/*
+ * Start the worker thread as soon as it is created.
+ * It looks in matchTable to see if there is any message or microtask allocated to it.
+ *  If any, then execute it.
+ * If no work, then sleep until communication thread awakens it.
+ */
+void BgNode::startWorkTh(ThreadInfo *info)
+{
+  PacketMsg *msgPtr = 0;
+  int selfID = info->selfID;
+  info->currTime = 0 ;
+
+  double tp1, tp2 ;
+  tp1 = BGTimer()*1e6;
+  while(true)
+  {
+    msgPtr = 0 ;
+
+    msgPtr = matchTable[selfID];
+    matchTable[selfID] = 0;
+
+    if(NULL==msgPtr) 
+    {
+      tp2 = BGTimer()*1e6;
+      info->currTime += (tp2-tp1) ;
+      workThQ->enqueThread(selfID) ;
+      int commID = commForWork->dequeThread();
+      if (commID!=(-1))
+        CthAwaken(threadTable[commID]);
+      CthSuspend() ;
+      tp1 = BGTimer()*1e6;
+      continue ;
+    }
+
+    //get handler for this message and execute it
+    BgHandler handler = handlerTable[msgPtr->handlerID] ;  
+    info->msg    = (void*)msgPtr ; 
+
+    tp2 = BGTimer()*1e6;
+    info->currTime += (tp2-tp1) ;
+    //make timing adjustments for thread
+    if(msgPtr->recvTime > info->currTime)
+      info->currTime = msgPtr->recvTime ;
+    info->handlerStartTime = tp2 ;
+
+    tp1 = tp2 ;
+    handler(info) ;
+  }
+}
+
+void BgNode::getXYZ(int& i, int& j, int& k)
+{
+  i = thisIndex.x ; j = thisIndex.y ; k = thisIndex.z ;
+}
+
+void BgNode::finish(void)
+{
+  //more: should I delete all the node components here
+  CProxy_Main main(mainID) ;
+  main.Finish() ;
+}
+
+/***************************************************************************/
+/*
+ * Convere system requires the startfunction of threads should be in C
+ */
+extern "C" void startCommTh(ThreadInfo *info) 
+{
+  (info->bgNode)->startCommTh(info) ;
+}
+
+extern "C" void startWorkTh(ThreadInfo *info)
+{
+  (info->bgNode)->startWorkTh(info) ;
+}
+
+#include "BlueGene.def.h"
diff --git a/src/langs/bluegene/BlueGene.ci b/src/langs/bluegene/BlueGene.ci
new file mode 100644 (file)
index 0000000..5577ffe
--- /dev/null
@@ -0,0 +1,23 @@
+// File: BlueGene.ci
+
+mainmodule BlueGene
+{
+  readonly CkChareID mainID ;
+  readonly CkArrayID bgArrayID ;
+
+  message CreateBgNodeMsg ;
+  message PacketMsg ;
+
+  mainchare Main
+  {
+       entry      Main() ;
+       entry void Finish(void) ;
+  } ;
+
+  array [3D] BgNode 
+  {
+       entry      BgNode(CreateBgNodeMsg *) ;
+       entry void putMessage(PacketMsg *) ;
+  } ;
+
+} ;
diff --git a/src/langs/bluegene/BlueGene.h b/src/langs/bluegene/BlueGene.h
new file mode 100644 (file)
index 0000000..2679729
--- /dev/null
@@ -0,0 +1,230 @@
+// File: BlueGene.h
+
+#ifndef _BlueGene_h
+#define _BlueGene_h
+
+#include "BlueGene.decl.h"
+#include "charm++.h"
+
+#define SIZE_INBUFFER     32
+#define MAX_NUM_THREADS   200
+#define MAX_HANDLERS      16
+
+enum WorkType {LARGE_WORK=0, SMALL_WORK=1};
+
+#if BG_TIMER
+#define BGTimer() CkWallTimer()
+#else
+#define BGTimer() 0.0
+#endif
+
+class BgNode ;
+class InBuffer ;
+class SchedulerQ ;
+class ThreadInfo ;
+class PacketMsg ;
+class Main ;
+// CkQ is defined in charm++.h
+typedef CkQ<PacketMsg*> MsgQ;
+
+extern "C" void  BgInit(Main *) ;
+extern "C" void* BgNodeInit(BgNode *) ;
+extern "C" void  BgFinish() ;
+
+typedef void (*BgHandler)(ThreadInfo *) ;
+
+class CreateBgNodeMsg: public CMessage_CreateBgNodeMsg
+{
+public:
+  int numCTh ;
+  int numWTh ;
+  int numBgX ;
+  int numBgY ;
+  int numBgZ ;
+} ;
+//~~~ end of class CreateBgNodeMsg ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class PacketMsg: public CMessage_PacketMsg
+{
+public:
+  int handlerID ;
+  WorkType type;
+  double sendTime ;
+  double recvTime ;
+} ;
+//~~~ end of class PacketMsg ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class Main: public Chare 
+{
+private:
+  CkArgMsg *args ;
+  int       numBgX, numBgY, numBgZ ;   
+  double starttime, endtime;
+
+public:
+       Main(CkArgMsg *msg) ;
+       ~Main() ;
+  void Finish(void) ;
+
+  void CreateBlueGene(CreateBgNodeMsg *msg) ;
+  int          getNumArgs() ;
+  const char** getArgs() ;
+} ;
+
+//~~~ end of class Main ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class BgNode: public ArrayElement3D
+{
+private:
+  int          numCTh;
+  int          numWTh;
+  InBuffer*    inBuffer;
+  PacketMsg**  matchTable;
+  CthThread*   threadTable;
+  BgHandler*   handlerTable;
+  SchedulerQ*  workThQ;
+  SchedulerQ*  commForMsg;
+  SchedulerQ*  commForWork;
+  MsgQ*        addMsgQ;
+  CProxy_BgNode**** proxies;
+
+public:
+  int         numBgX ;
+  int         numBgY ;
+  int         numBgZ ;
+  void*       nvData ;
+
+public:   
+       BgNode(CreateBgNodeMsg *msgPtr) ;
+       ~BgNode() ; 
+       BgNode(CkMigrateMessage *msgPtr) {} ;
+
+  void registerHandler(int handlerID, BgHandler h) ;
+  void addMessage(PacketMsg *msgPtr, int handlerID, WorkType type) ;
+
+  void putMessage(PacketMsg *msgPtr) ;
+  void assignMsg() ;
+  void startCommTh(ThreadInfo *info) ;
+  void startWorkTh(ThreadInfo *info) ;
+
+  void sendPacket(int x, int y, int z, PacketMsg *msgPtr, 
+                  int handlerID, WorkType type) ;
+  void getXYZ(int& x, int& y, int& z) ;
+  double getNumCTh() { return numCTh; }
+  double getNumWTh() { return numWTh; }
+  void finish() ;
+} ;
+//~~~ end of class BgNode
+
+
+class InBuffer
+{
+  PacketMsg *msgs[SIZE_INBUFFER];
+  int first, count;
+  BgNode *bgNode ;
+  MsgQ *mq;
+
+public:
+  InBuffer(BgNode *bgNodeRef) : 
+    bgNode(bgNodeRef), first(0), count(0) 
+  {
+    for(int i=0;i<SIZE_INBUFFER;i++)
+      msgs[i] = 0;
+    mq = new MsgQ;
+  }
+  ~InBuffer()
+  {
+    for(int i=first, n=0; n < count; n++)
+    {
+      delete msgs[i];
+      i = (i+1)%SIZE_INBUFFER;
+    }
+    delete mq;
+  } 
+  PacketMsg* getMessage(void)
+  {
+    PacketMsg *m = msgs[first];
+    if(count) {
+      msgs[first] = 0;
+      first = (first+1)%SIZE_INBUFFER;
+      count --;
+      if(count==SIZE_INBUFFER-1) {
+        PacketMsg *m1;
+        if(m1=mq->deq())
+          putMessage(m1);
+      }
+    }
+    return m;
+  }
+  void putMessage(PacketMsg *msgPtr)
+  {
+    if(count==SIZE_INBUFFER)
+    {
+      mq->enq(msgPtr);
+      return;
+    }
+    msgs[(first+count)%SIZE_INBUFFER] = msgPtr;
+    count++;
+    bgNode->assignMsg();
+  }
+} ;
+//~~~ end of InBuffer ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+class SchedulerQ
+{
+private:
+  int *q;
+  int front, count, max ;
+
+public:
+  SchedulerQ(int _max) : front(0), count(0), max(_max) { q = new int[_max]; }
+  ~SchedulerQ() { delete[] q; }
+  int  dequeThread(void)
+  {
+    int ret = (-1);
+    if( count>0)
+    { 
+      ret = q[front]; 
+      front = (front+1)%max; 
+      count--;
+    }
+    return ret;
+  }
+  void enqueThread(int threadID)
+  {
+    q[(front+count)%max] = threadID;
+    count++;
+  }
+} ;
+//~~~ end of SchedulerQ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+
+class ThreadInfo
+{
+public:
+  BgNode *bgNode ;
+  int     selfID ;
+  void   *msg ;
+  double currTime;
+  double handlerStartTime;
+
+public:
+  double getTime(void)
+  {
+    double tp2 ;
+    tp2 = BGTimer()*1e6;
+    return (tp2 - handlerStartTime + currTime);
+  }
+  void sendPacket(int x, int y, int z, PacketMsg *msgPtr, int handlerID, 
+                  WorkType type)
+  {
+    msgPtr->sendTime = getTime();
+    bgNode->sendPacket(x,y,z,msgPtr,handlerID,type);
+  }
+} ;
+//~~~ end of ThreadInfo ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+extern "C" void startCommTh(ThreadInfo *info) ;
+extern "C" void startWorkTh(ThreadInfo *info) ;
+
+#endif
index ea6fbcbecf3aa4f12579e5ba8d978ba877e0cc53..2e36614c28d95fc13f294949188ec9aced2a4866 100644 (file)
 
 SHELL=/bin/sh
 
-all: charm++ LIBS ampi tsm sm pvm sdag doc
+all: charm++ bluegene LIBS ampi tsm sm pvm sdag doc
 
 charm++: converse libck.a charmxi
 
+bluegene: charm++ libbluegene.a
+
 for-namd: charm++ pvm AMPIC
 
 tsm: converse libtsm.a
@@ -93,7 +95,7 @@ CVHEADERS=cpthreads.h converse.h conv-mach.h conv-mach.sh \
       WSLB.decl.h GreedyRefLB.decl.h RandRefLB.decl.h \
       tempo.decl.h waitqd.decl.h \
          CommLB.decl.h Comm1LB.decl.h  \
-         ampi.decl.h ampimain.decl.h
+         ampi.decl.h ampimain.decl.h BlueGene.decl.h
 
 # The .c files are there to be #included by clients whole
 # This is a bit unusual, but makes client linking simpler.
@@ -109,7 +111,7 @@ CKHEADERS=ck.h ckstream.h envelope.h init.h qd.h charm.h charm++.h \
          RefineLB.h HeapCentLB.h CommLB.h Comm1LB.h \
          MetisLB.h NborBaseLB.h \
          NeighborLB.h WSLB.h GreedyRefLB.h RandRefLB.h CkLists.h \
-      ampi.h ampif.h \
+      ampi.h ampif.h BlueGene.h \
          $(CVHEADERS)
 
 ALLHEADERS=$(CKHEADERS) \
@@ -152,6 +154,7 @@ dirs+sources:
        ./gatherflat ../../src/Common/langs/simplemsg  .
        ./gatherflat ../../src/Common/langs/pvmc       .
        ./gatherflat ../../src/Common/langs/ampi       .
+       ./gatherflat ../../src/Common/langs/bluegene   .
        ./gatherflat ../../src/Common/langs/sdag/xlator       .
        ./gatherflat ../../src/Common/langs/sdag/runtime      .
        ./gatherflat ../../src/Common/xlat-i           .
@@ -524,6 +527,20 @@ trace-summary.o:trace-summary.C trace-summary.h trace.h $(CKHEADERS)
        $(CHARMC) -o trace-summary.o trace-summary.C
 
 
+###############################################################################
+#
+# BlueGene Emulator
+#
+###############################################################################
+
+BlueGene.decl.h BlueGene.def.h : BlueGene.ci charmxi
+       $(CHARMC) BlueGene.ci
+
+libbluegene.a: BlueGene.C BlueGene.h BlueGene.decl.h BlueGene.def.h
+       $(CHARMC) -c BlueGene.C
+       $(CHARMC) -cp ../lib -o libbluegene.a BlueGene.o
+
+
 ###############################################################################
 #
 # The CPM scanner
index c2107c69efe59b4fbf1d73d4b59730b6295a636c..75e15564cf9468fdced1393aef1b4e3d16dbf2cf 100755 (executable)
@@ -591,7 +591,7 @@ case "$LANGUAGE" in
 "charm"|"charm++"|"converse"|"converse++"|"idl")
        [ -z "$SEQUENTIAL" ] || Abort "Language $LANGUAGE is for parallel programs"
        ;;
-"fem"|"femf"|"ampi"|"ampif"|"f90charm")
+"fem"|"femf"|"ampi"|"ampif"|"f90charm"|"bluegene")
        [ -z "$SEQUENTIAL" ] || Abort "Language $LANGUAGE is for parallel programs"
        ;;
 *)
@@ -910,6 +910,9 @@ case "$LANGUAGE" in
           done
         fi
        ;;
+"bluegene")
+        POST_LIBRARIES="$POST_LIBRARIES -lbluegene"
+       ;;
 esac
 
 LANG_LIBS="-L$CHARMLIB -I$CHARMINC $BAL_OBJ $OBJECTFILES $PRE_LIBRARIES -lck $POST_LIBRARIES"
@@ -928,7 +931,7 @@ case "$LANGUAGE" in
        Do $CMK_LDXX $OPTSL $OPTS_LDXX -o $OBJECT \
                $LANG_LIBS -lconv-cplus-y $CORE_LIBS -lidl -lm $CMK_LIBS
        ;;
-"ampi"|"ampif"|"fem"|"femf")
+"ampi"|"ampif"|"fem"|"femf"|"bluegene")
        Do $CMK_LDXX $OPTSL $OPTS_LDXX -o $OBJECT \
                $LANG_LIBS -lconv-cplus-y $CORE_LIBS -lm $CMK_LIBS
        ;;