First version of the multiblock manual
authorPuneet Narula <pnarula@uiuc.edu>
Fri, 5 Oct 2001 22:26:17 +0000 (22:26 +0000)
committerPuneet Narula <pnarula@uiuc.edu>
Fri, 5 Oct 2001 22:26:17 +0000 (22:26 +0000)
doc/mblock/Makefile [new file with mode: 0644]
doc/mblock/manual.tex [new file with mode: 0644]

diff --git a/doc/mblock/Makefile b/doc/mblock/Makefile
new file mode 100644 (file)
index 0000000..caefa63
--- /dev/null
@@ -0,0 +1,48 @@
+DOCDIR=../../../doc
+WEBDIR=/expand6/groupMosaic/ppl_manuals
+
+all: ps pdf html
+
+ps:
+       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
+
+html:
+       touch index.tex
+       latex manual.tex
+       latex2html -local_icons manual.tex
+
+pdf:
+       touch index.tex
+       pdflatex manual.tex
+       if [ -f manual.idx ] ; then makeindex -o index.tex manual.idx ; fi
+       pdflatex manual.tex
+
+doc:
+       make all
+       if [ ! -d $(DOCDIR) ] ; then mkdir $(DOCDIR) ; fi
+       if [ ! -d $(DOCDIR)/ps ] ; then mkdir $(DOCDIR)/ps ; fi
+       if [ ! -d $(DOCDIR)/pdf ] ; then mkdir $(DOCDIR)/pdf ; fi
+       if [ ! -d $(DOCDIR)/html ] ; then mkdir $(DOCDIR)/html ; fi
+       /bin/cp manual.ps $(DOCDIR)/ps/fem.ps
+       /bin/cp manual.pdf $(DOCDIR)/pdf/fem.pdf
+       /bin/rm -rf $(DOCDIR)/html/fem
+       /bin/cp -R manual $(DOCDIR)/html/fem
+
+web:
+       make all
+       /bin/cp manual.ps $(WEBDIR)/ps/fem.ps
+       /bin/cp manual.pdf $(WEBDIR)/pdf/fem.pdf
+       /bin/rm -rf $(WEBDIR)/html/fem
+       /bin/cp -R manual $(WEBDIR)/html/fem
+       find $(WEBDIR) -type f -exec chmod 664 {} \;
+       find $(WEBDIR) -type d -exec chmod 775 {} \;
+
+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/mblock/manual.tex b/doc/mblock/manual.tex
new file mode 100644 (file)
index 0000000..25635c1
--- /dev/null
@@ -0,0 +1,556 @@
+\documentclass[10pt]{article}
+\usepackage{../pplmanual}
+\input{../pplmanual}
+
+\makeindex
+
+\title{\charmpp\\ MultiBlock Framework\\ Manual}
+\version{1.0}
+\credits{
+This version of \charmpp{} MultiBlock Framework was developed
+by Orion Lawlor and Milind Bhandarkar.
+}
+
+\begin{document}
+
+\maketitle
+
+\section{Motivation}
+
+
+
+\section{Introduction/Terminology}
+
+
+
+\section{Structure of a MultiBlock Framework Program}
+
+A MultiBlock framework program consists of three subroutines: \kw{init}, \kw{driver}, and \kw{finalize}.  \kw{init} and \kw{finalize} are called by the MultiBlock framework only on the first processor -- these routines typically do specialized I/O, startup and shutdown tasks.  \kw{driver} is called for every chunk on every processor, and does the main work of the program.
+
+\begin{alltt}
+     subroutine init
+          read the configuration data llike block prefix, 
+         number of blocks and dimension 
+     end subroutine
+
+     subroutine driver
+         allocate and initialize the grid
+         register boundary condition functions
+          time loop
+               MultiBlock computations
+               update shared node fields
+               more MultiBlock computations
+          end time loop
+     end subroutine
+
+     subroutine finalize
+           write results
+     end subroutine
+\end{alltt}
+
+\section{Compilation and Execution}
+
+A Multiblock framework program is a \charmpp\ program, so you must begin by
+downloading the latest source version of \charmpp\ from
+{\tt http://charm.cs.uiuc.edu/}.  Build the source with 
+{\tt ./build MBLOCK version} or {\tt cd} into the build directory, 
+{\tt version/tmp}, and type {\tt make MBLOCK}.
+To compile a MULTIBLOCK program, pass the {\tt -language mblock} (for C) or 
+{\tt -language mblockf} (for Fortran) option to {\tt charmc}.
+
+In a charm installation, see charm/version/pgms/charm++/mblock/
+for example and test programs.
+
+
+\section{MultiBlock Framework API Reference}
+
+\subsection{Initialization}
+All these methods should be called from the \kw{init} function by the user.The values
+passed to these functions are typically read from a file.
+\function{int MBLK\_Set\_prefix(const char *prefix);}
+\function{subroutine MBLK\_Set\_prefix(prefix,err)}
+\args{ Character, intent(in)::prefix}
+\args{integer, intent(out)::err}
+
+This function is called to set the prefix. It returns MBLK\_SUCCESS in case of 
+success else it returns MBLK\_FAILURE.
+
+\vspace{0.2in}
+
+\function{int MBLK\_Set\_nblocks(const int n);}
+\function{ subroutine MBLK\_Set\_nblocks(n,err)}
+\args{integer, intent(in)::n}
+\args{integer, intent(out)::err}
+This call is made to set the number of blocks to be used in the application.It 
+returns MBLK\_SUCCESS in case of success else it returns MBLK\_FAILURE.
+\vspace{0.2in}
+
+\function{int MBLK\_Set\_dim(const int n);}
+\function{subroutine MBLK\_Set\_dim(n, err)}
+\args{integer, intent(in)::n}
+\args{integer, intent(out):: err}
+This call is made to set the dimension. It returns MBLK\_SUCCESS in case of 
+success else it returns MBLK\_FAILURE.
+
+\subsection{Utility}
+
+\function{int MBLK\_Get\_nblocks(int* n);}
+\function{subroutine MBLK\_Get\_nblocks(n,err)}
+\args{ integer,intent(out)::n
+       integer,intent(out)::err}
+     Get the number of blocks in the current computation.  Can
+     only be called from the driver routine. Returns MBLK\_SUCCESS in case of
+     success and MBLK\_FAILURE in case of error.
+\vspace{0.2in}
+
+\function{int MBLK\_Get\_myblock(int* m);}
+\function{subroutine MBLK\_Get\_myblock(m,err)}
+\args{ integer,intent(out)::m
+       integer,intent(out)::err }
+
+     Get the id of the current block. Can only be called from the driver 
+     routine. Returns MBLK\_SUCCESS in case of success and MBLK\_FAILURE in 
+     case of error.
+\vspace{0.2in}
+
+\function{int MBLK\_Get\_blocksize(int* dims);}
+\function{subroutine MBLK\_Get\_blocksize(dimsm,err)}
+\args{ integer,intent(out)::dims(3)
+       integer,intent(out)::err }
+     Get the Interior dimensions, in voxels. The size of the array dims should
+     be 3. Can only be called from the driver routine. Returns MBLK\_SUCCESS 
+     in case of success and MBLK\_FAILURE in case of error.
+\vspace{0.2in}
+
+\function{double MBLK\_Timer(void);}
+\function{function double precision :: MBLK\_Timer()}
+
+     Return the current wall clock time, in seconds.  Resolution is
+     machine-dependent, but is at worst 10ms.
+\vspace{0.2in}
+
+\function{void MBLK\_Print\_block(void);}
+\function{subroutine MBLK\_Print\_block()}
+
+     Print a debugging representation of the current block.
+     Prints the entire blocks array, and data associated with
+     each block.
+\vspace{0.2in}
+
+\function{void MBLK\_Print(const char *str);}
+\function{subroutine MBLK\_Print(str)}
+\args{  character*, intent(in) :: str}
+
+     Print the given string, prepended by the block id if called from the 
+     driver. Works on all machines; unlike \kw{printf} or
+     \kw{print *}, which may not work on all parallel machines.
+
+
+\subsection{Block Fields}
+
+
+The MultiBlock framework handles the updating of the values of blocks.
+The basic mechanism to do this update is the field-- numeric data items associated with each block. We make no assumptions about the meaning of the block data, and allow various data types and non-communicated data associated with each
+block.  To do this, the framework must be able to find the data items
+associated with each block in memory.
+
+Each field represents a (set of) block data items stored in a contiguous array,
+indexed by block number.  You create a field once, with \kw{MBLK\_Create\_Field}, then pass the resulting field ID to \kw{MBLK\_Update\_Field} (which does the
+overlapping block communication) and/or \kw{MBLK\_Reduce\_Field} (which applies a reduction over block values).
+\vspace{0.2in}
+
+\function{int MBLK\_Create\_Field(int *dimensions,int isVoxel,const int base\_type,const int vec\_len,const int offset,const int dist, int *fid);}
+\function{subroutine MBLK\_Create\_Field(dimensions, isVoxel,base\_type, vec\_len, offset, dist, err)}
+  \args{integer, intent(in)  :: dimensions, isVoxel, base\_type, vec\_len, offset, dist
+       integer, intent(out) :: fid, err}
+
+     Creates and returns a MultiBlock field ID, which can be passed to
+\kw{MBLK\_Update\_Field} and \kw{MBLK\_Reduce\_Field.}  Can only be called from
+\kw{driver().}  A field is a range of values associated with each local block--
+the Multiblock framework uses the information you pass to find the values associated with overlapping blocks (for \kw{MBLk\_Update\_Field}) and primary blocks (for \kw{MBLK\_Reduce\_Field}). Returns MBLK\_SUCCESS in case of success and MBLK\_FAILURE in case of error.
+
+     \kw{dimensions} describes the number of dimensions should be in array of size 3
+     \kw{isVoxel} describes whether the dimenstions passed in are in voxel(=11) or not(= 0).
+     \kw{base\_type} describes the kind of data item associated with each
+     node, one of:
+
+     \begin{itemize}
+        \item \kw{MBLk\_BYTE}-- unsigned char, INTEGER*1, or CHARACTER*1
+        \item \kw{MBLK\_INT}-- int or INTEGER*4
+        \item \kw{MBLK\_REAL}-- float or REAL*4
+        \item \kw{MBLK\_DOUBLE}-- double, DOUBLE PRECISION, or REAL*8
+     \end{itemize}
+
+     \kw{vec\_len} describes the number of data items associated with each
+     node, an integer at least 1.
+
+     \kw{offset} is the byte offset from the start of the nodes array to the
+     data items, a non-negative integer.
+
+     \kw{dist} is the byte offset from the first node's data item to the
+     second, a positive integer.
+     \kw{fid} is the identifier for the field that is created by the function.
+     \kw{err} is returned as  MBLK\_SUCCESS in case of success otherwise MBLK\_FAILURE is returned.
+\vspace{0.2in}
+
+     For example, if each block has a 3D grid, over which we are performing Successive over relaxation.You can register the ghost regions for update with:
+\begin{alltt}
+       !In Fortran
+       
+       integer :: size(3), ni,nj,nk
+       integer :: si,sj,sk
+       integer :: fid, err
+       integer, parameter::ghostwidth=1;       
+       !Find the dimensions of the grid, from the framework to allocateit
+       MBLk_Get_blocksize(size,err);
+
+       !Add ghost region width to the dimensions obtained from the framework
+       ni=size(1)+2*ghostWidth; 
+       nj=size(2)+2*ghostWidth; 
+       nk=size(3)+2*ghostWidth;
+       si=1+ghostWidth; sj=1+ghostWidth; sk=1+ghostWidth;
+
+       ...allocate and initialize the grid 
+
+       !Create the field that needs to be updated
+       size(1)=ni; size(2)=nj; size(3)=nk;
+       call MBLK_Create_field(&
+              &size,1, MBLK_DOUBLE,1,&
+              &offsetof(grid(1,1,1),grid(si,sj,sk)),&
+              &offsetof(grid(1,1,1),grid(2,1,1)),fid,err)      
+       
+
+\end{alltt}
+     This example uses the Fortran-only helper routine \kw{offsetof}, which
+     returns the offset in bytes of memory between its two given
+     variables.  The C version uses pointer arithmetic to achieve the
+     same result.
+\vspace{0.2in}
+     
+
+\function{void MBLK\_Update\_field(const int fid,int ghostwidth, void *grid);}
+\function{subroutine MBLK\_Update\_field(fid,ghostwidth, grid,err)}
+  \args{integer, intent(in)  :: fid, ghostwidth}
+  \args{integer,intent(out) :: err}
+  \args{varies, intent(inout) :: grid}
+
+     Update the values in the ghost regions which specified when the
+     field was created. For the example above the ghost regions will be 
+     updated once for each step in the time loop.
+
+     \kw{MBLK\_Update\_field} can only be called from driver, and to be useful,
+     must be called from every block's driver routine.
+
+     \kw{MBLK\_Update\_field} blocks till the field has been updated.
+     After this routine returns, the given field will updated.
+     If the update was successful MBLK\_SUCCESS is returned and 
+     MBLk\_FAILURE is returned in case of error.
+\vspace{0.2in}
+
+\function{void MBLK\_Iupdate\_field(const int fid,int ghostwidth, void *ingrid, void* outgrid);}
+\function{subroutine MBLK\_Iupdate\_field(fid,ghostwidth, ingrid, outgrid,err)}
+  \args{integer, intent(in)  :: fid, ghostwidth}
+  \args{integer,intent(out) :: err}
+  \args{varies,intent(in) :: ingrid}
+  \args{varies,intent(out) :: outgrid}
+
+
+     Update the values in the ghost regions which were specified when the
+     field was created. For the example above the ghost regions will be 
+     updated once for each step in the time loop.
+
+     \kw{MBLK\_Iupdate\_field} can only be called from driver, and to be useful,
+     must be called from every block's driver routine.
+
+     \kw{MBLK\_Iupdate\_field} is a non blocking call like MPI\_IRecv
+     After the routine returns the update is not complete but is guranteed
+     to be complete in future. So before using the values the status of the
+     update should be checked using \kw{MBLk\_Test\_update} or should wait
+     for the completion of the call using \kw{MBLK\_Wait\_update}
+     
+     If the\kw{MBLK\_Iupdate\_field} call was successful MBLK\_SUCCESS is 
+     returned and MBLK\_FAILURE is returned in case of error.
+\vspace{0.2in}
+
+\function{int MBLK\_Test\_update(int *status);}
+\function{subroutine MBLK\_Test\_update(status,err)}
+\args{integer, intent(out) :: status,err}
+
+     \kw{MBLK\_Test\_update} is a call that is used in assosiation with 
+     \kw{MBLk\_Iupdate\_field} from the driver sub routine.It tests whether
+      the field has been updated or not.
+     \kw{status} is returned as MBLK\_DONE if the update was completed or 
+      MBLK\_NOTDONE if the update is still pending.
+     \kw{err} is returned as MBLK\_SUCCESS if the call was successful or 
+     MBLK\_FAILURE if there was an error.
+
+
+ORION: I think this function at this time is not updating the status I think it is returning MBLK\_DONE or MBLK\_NOTDONE or MBLK\_FAILURE in error instead of using the 
+status. Please have a look at that
+\vspace{0.2in}
+
+\function{void MBLk\_Wait\_update(void);}
+\function{subroutine MBLk\_Wait\_update()}
+
+     \kw{MBLk\_Wait\_update} call is a blocking call and is used in assoisation 
+     with \kw{MBLK\_Iupdate\_field} call. It blocks till the update is completed.
+\vspace{0.2 in}
+
+
+\function{void MBLK\_Reduce\_field(int fid,void *grid, void *out,int op);}
+\function{subroutine MBLK\_Reduce\_field(fid,grid,outVal,op)}
+  \args{integer, intent(in)  :: fid,op}
+  \args{varies, intent(in) :: grid}
+  \args{varies, intent(out) :: outVal}
+
+     Combine a field from each block, according to op, across all blocks.
+     After \kw{Reduce\_Field} returns, all blocks will have identical
+values in \kw{outVal,} which must be \kw{vec\_len} copies of \kw{base\_type}.
+
+     May only be called from driver, and to complete, must be called
+     from every chunk's driver routine.
+
+     \kw{op} must be one of:
+
+\begin{itemize}
+        \item \kw{MBLk\_SUM}-- each element of \kw{outVal} will be the sum 
+of the corresponding fields of all blocks
+        \item \kw{MBLK\_MIN}-- each element of \kw{outVal} will be the 
+smallest value among the corresponding field of all blocks
+        \item \kw{MBLK\_MAX}-- each element of \kw{outVal} will be the largest 
+value among the corresponding field of all blocks
+\end{itemize}
+\vspace{0.2in}
+
+\function{void MBLK\_Reduce(int fid,void *inVal,void *outVal,int op);}
+\function{subroutine MBLK\_Reduce(fid,inVal,outVal,op)}
+  \args{integer, intent(in)  :: fid,op}
+  \args{varies, intent(in) :: inVal}
+  \args{varies, intent(out) :: outVal}
+
+     Combine a field from each block, acoording to \kw{op}, across all blocks.
+\kw{Fid} is only used for the \kw{base\_type} and \kw{vec\_len}-- offset and
+\kw{dist} are not used.  After this call returns, all blocks will have
+identical values in \kw{outVal}.  Op has the same values and meaning as
+\kw{MBLK\_Reduce\_Field}.
+
+     May only be called from driver, and to complete, must be called
+     from every blocks driver routine.
+
+\vspace{0.2in}
+
+\subsection{Boundary Conditions}
+In most of the applications using the MultiBlock Framework the blocks have 
+boundary conditions for eaach block depending on the geometery. Various calls 
+are provided in the framework to register and apply the boundry conditions.
+
+\function{int MBLK\_Register\_bc(const int bcnum, int ghostWidth, const MBLK\_BcFn bcfn);}
+\function{subroutine MBLK\_Register\_bc(bcnum, ghostwidth, bcfn, err)}
+\args{integer,intent(in) :: bcnum, ghostWidth}
+\args{integer,intent(out) :: err}
+\args{subroutine :: bcfn}
+
+This is call is used to register the boundry condition function, for a block,
+with the framework.
+\begin{itemize}
+       \item \kw{bcnum} The boundry condtion number to be associated with the 
+       function.
+       \item \kw{ghostWidth} The width of the ghostcells where this boundry
+       condition is going to be applied.
+       \item \kw{bcfn} The user function that is to be used for applying the
+       the boundry conditions.
+\end{itemize}
+\kw{MBLK\_Register\_bc} should only be called from the driver.
+This call returns MBLK\_SUCCESS in case of success or else returns MBLK\_FAILURE
+in case of an error.
+\vspace{0.2in}
+
+\function{ int MBLK\_Apply\_bc(const int bcnum, void *grid,void *size);}
+\function{subroutine MBLK\_Apply\_bc(bcnum, grid, size,err)}
+\args{ integer,intent(in)::bcnum}
+\args{integer,intent(out)::err}
+\args{varies,intent(inout)::grid}
+\args{varies, intent(in)::size}
+
+\kw{MBLK\_Apply\_bc} call is made to apply the boundry condition function
+associated to \kw{bcnum} to the block.The grid specifies the place where 
+the boundary condition are to be applied adn sizes array gives the dimensions
+of the grid.
+It returns MBLK\_SUCCESS if the call is successful else it returns
+MBLK\_FAILURE in case of error. 
+
+\function{ int MBLK\_Apply\_bc\_all(void* grid, void* size);} 
+\function{subroutine MBLK\_Apply\_bc\_all(grid, size, err)}
+\args{integer,intent(out)::err}
+\args{varies,intent(inout)::grid}
+\args{varies, intent(in)::size}
+This call is same as \kw{MBLK\_Apply\_bc} except it applies all the boundary 
+functions to the block.
+
+\subsection{Migration}
+
+The \charmpp\ runtime framework includes an automated, run-time load balancer,
+which will automatically monitor the performance of your parallel program.
+If needed, the load balancer can ``migrate'' mesh chunks from heavily-loaded
+processors to more lightly-loaded processors, improving the load balance and
+speeding up the program.  For this to be useful, pass the \kw{+vpN} argument
+with a larger number of blocks \kw{N} than processors
+Because this is somewhat involved, you may refrain from calling 
+\kw{MBLK\_Migrate} and migration will never take place.
+
+The runtime system can automatically move your thread stack to the new
+processor, but you must write a PUP function to move any global or
+heap-allocated data to the new processor (global data is declared at file scope
+or \kw{static} in C and \kw{COMMON} in Fortran77; heap allocated data comes
+from C \kw{malloc}, C++ \kw{new}, or Fortran90 \kw{ALLOCATE}).  A PUP
+(Pack/UnPack) function performs both packing (converting heap data into a
+message) and unpacking (converting a message back into heap data).  All your
+global and heap data must be collected into a single block (\kw{struct} in C;
+user-defined \kw{TYPE} in Fortran) so the PUP function can access it all.
+
+Your PUP function will be passed a pointer to your heap data block and a
+special handle called a ``pupper'', which contains the network message to be
+sent.  Your PUP function returns a pointer to your heap data block.  In a PUP
+function, you pass all your heap data to routines named \kw{pup\_type}, where
+type is either a basic type (such as int, char, float, or double) or an array
+type (as before, but with a ``s'' suffix).  Depending on the direction of
+packing, the pupper will either read from or write to the values you pass--
+normally, you shouldn't even know which.  The only time you need to know the
+direction is when you are leaving a processor or just arriving.
+Correspondingly, the pupper passed to you may be deleting (indicating that you
+are leaving the processor, and should delete your heap storage after packing),
+unpacking (indicating you've just arrived on a processor, and should allocate
+your heap storage before unpacking), or neither (indicating the system is
+merely sizing a buffer, or checkpointing your values).
+
+PUP functions are much easier to write than explain-- a simple C heap block
+and the corresponding PUP function is:
+
+\begin{alltt}
+     typedef struct {
+       int n1;/*Length of first array below*/
+       int n2;/*Length of second array below*/
+       double *arr1; /*Some doubles, allocated on the heap*/
+       int *arr2; /*Some ints, allocated on the heap*/
+     } my_block;
+     my_block *pup_my_block(pup_er p,my_block *m)
+     {
+       if (pup_isUnpacking(p)) m=malloc(sizeof(my_block));
+       pup_int(p,\&m->n1);
+       pup_int(p,\&m->n2);
+       if (pup_isUnpacking(p)) {
+         m->arr1=malloc(m->n1*sizeof(double));
+         m->arr2=malloc(m->n2*sizeof(int));
+       }
+       pup_doubles(p,m->arr1,m->n1);
+       pup_ints(p,m->arr2,m->n2);
+       if (pup_isDeleting(p)) {
+         free(m->arr1);
+         free(m->arr2);
+         free(m);
+       }
+       return m;
+     }
+\end{alltt}
+
+This single PUP function can be used to copy the \kw{my\_block} data into a
+message buffer and free the old heap storage (deleting pupper); allocate
+storage on the new processor and copy the message data back (unpacking pupper);
+or save the heap data for debugging or checkpointing.
+
+A Fortran block TYPE and corresponding PUP routine is as follows:
+
+\begin{alltt}
+     MODULE my_block_mod
+       TYPE my_block
+         INTEGER :: n1,n2x,n2y
+         REAL*8, POINTER, DIMENSION(:) :: arr1
+         INTEGER, POINTER, DIMENSION(:,:) :: arr2
+       END TYPE
+     END MODULE
+     SUBROUTINE pup_my_block(p,m)
+       IMPLICIT NONE
+       USE my_block_mod
+       USE pupmod
+       INTEGER :: p
+       TYPE(my_block) :: m
+       call pup_int(p,m%n1)
+       call pup_int(p,m%n2x)
+       call pup_int(p,m%n2y)
+       IF (pup_isUnpacking(p)) THEN
+         ALLOCATE(m%arr1(m%n1))
+         ALLOCATE(m%arr2(m%n2x,m%n2y))
+       END IF
+       call pup_doubles(p,m%arr1,m%n1)
+       call pup_ints(p,m%arr2,m%n2x*m%n2y)
+       IF (pup_isDeleting(p)) THEN
+         DEALLOCATE(m%arr1)
+         DEALLOCATE(m%arr2)
+       END IF
+     END SUBROUTINE
+\end{alltt}
+
+\function{int MBLK\_Register(void *block, MBLk\_PupFn pup\_ud, int* rid)}
+\function{subroutine MBLK\_Register(block,pup\_ud, rid)}
+    \args{integer, intent(out)::rid}
+    \args{TYPE(varies), POINTER :: block}
+    \args{SUBROUTINE :: pup\_ud}
+
+     Associates the given data block and PUP function.  Returns a block
+     ID, which can be passed to \kw{MBLK\_Get\_registered} later.  Can only be
+     called from driver.  It returns MBLK\_SUCESS if the call was successful
+     and MBLK\_FAILURE in case of error. For the declarations above, you call
+     \kw{MBLK\_Register} as:
+
+\begin{alltt}
+          /*C/C++ driver() function*/
+         int myId, err;
+          my_block *m=malloc(sizeof(my_block));
+          err =MBLK_Register(m,(MBLK_PupFn)pup_my_block,&rid);
+          !- Fortran driver subroutine
+          use my_block_mod
+          interface
+            subroutine pup_my_block(p,m)
+              use my_block_mod
+              INTEGER :: p
+              TYPE(my_block) :: m
+            end subroutine
+          end interface
+          TYPE(my_block) :: m
+          INTEGER :: myId,err
+          MBLK_Register(m,pup_my_block,myId,err)
+\end{alltt}
+
+     Note that Fortran blocks must be allocated on the stack in driver;
+     while C/C++ blocks may be allocated on the heap.
+\vspace{0.2in}
+
+\function{void MBLK\_Migrate()}
+\function{subroutine MBLK\_Migrate()}
+
+     Informs the load balancing system that you are ready to be
+     migrated, if needed.  If the system decides to migrate you, the
+     PUP function passed to \kw{MBLK\_Register} will be called with a sizing
+     pupper, then a packing, deleting pupper.  Your stack (and pupped
+     data) will then be sent to the destination machine, where your PUP
+     function will be called with an unpacking pupper.  \kw{MBLK\_Migrate}
+     will then return, whereupon you should call \kw{MBLK\_Get\_registered} to
+     get your unpacked data block.  Can only be called from driver.
+
+
+
+\function{int MBLK\_Get\_Userdata(int n, void** block)}
+
+     Return your unpacked userdata after migration-- that is, the
+     return value of the unpacking call to your PUP function.  Takes
+     the userdata ID returned by \kw{MBLK\_Register}.  Can be called from
+     driver at any time.
+
+     Since Fortran blocks are always allocated on the stack, the system
+     migrates them to the same location on the new processor, so no
+     \kw{Get\_registered} call is needed from Fortran.
+\input{index}
+\end{document}