next up previous contents
Next: Data parallellism in Java Up: Message-passing case studies Previous: MPI Interface   Contents

Derived data types and higher-level MPI features

Figure 4: Life program using full MPI.
\begin{figure}\footnotesize\begin{verbatim}class Life {
void main(String args...
... block of board values.
Figure 5: Full MPI Life program (detail).
\begin{figure}\footnotesize\begin{verbatim}// Execute shifts...// Shift th...
... 0,
block, blockSizeY + 1, 1, edgeYType, nY.src, 0) ;\end{verbatim}\end{figure}

Description of the data buffers passed to communication operations presents some special problems in Java. Existing MPI bindings depend on a linear memory model and explicit or implicit use of pointers. Java does not have a linear memory model. Even behind the scenes a Java array has no uniquely defined address in memory, because the garbage collector is allowed to relocate objects unpredicatably during program execution to avoid fragmentation of its workspace. Our Java interface tries to retain as much of the MPI derived data-type mechanism as practical, but some functionality has been sacrificed. The buffer argument passed to a send or receive operation must be a one-dimensional array of primitive type. Any offset specified in a derived type argument then refers to a displacement within this one-dimensional array, never a displacement in memory.

All MPI derived types expressible through our interface have a uniquely defined base type--a Java primitive type. Interfaces to MPI_TYPE_HVECTOR and MPI_TYPE_HINDEXED are provided, but the strides and displacements are in units of the base type, not bytes. An interface to MPI_TYPE_STRUCT is provided, but all component types in the ``struct'' must have the same base type.

In the concrete Java binding of the send function, for example,

    void Send(Object buf, int offset, int count,
              Datatype datatype, int dest, int tag) ;
the formal buf argument is presented as a generic Java Object. As explained above, the actual argument must be a linear array. The second argument is the offset in this array of the first element of the message5. The remaining arguments correspond directly to arguments of MPI_Send. The base type of the datatype argument must be the type of the elements of buf.

Figures 4, 5 sketch a version of the Life program illustrating several of these features. As well as derived types, this program uses the Cartesian topologies of MPI. The Cart class is derived from Comm. In the example, the topology p represents a two dimensional periodic grid of processes. The Get member returns the coordinates of the local process. From these the parameters of the local array block are computed.

The values sX, sY represent the sides of the locally held array segment, including ghost regions. This segment is created as a one-dimensional Java array, block. The derived type edgeXType describes the structure of ghost area on the upper or lower x sides: contiguous regions of the block array of extent sY. The type edgeYType describes the y-side ghost areas: non-contiguous regions of count sX, regular stride sY.

The shift member of Cart corresponds to the MPI function MPI_CART_SHIFT: it returns the source and destination processors for a cyclic shift. The Java binding returns these values in an object of class CartShift which just contains two integers. Finally, in the main loop, the shifts are executed by using the Comm member Sendrecv, which corresponds to the standard MPI function MPI_Sendrecv. This performs a send and a receive concurrently (avoiding a potential deadlock in the implementations given in the previous sections).

next up previous contents
Next: Data parallellism in Java Up: Message-passing case studies Previous: MPI Interface   Contents
Bryan Carpenter 2002-07-11