Generalizing Java RMI to Support Efficient Group Communication Jason Maassen, Thilo Kielmann, Henri E. Bal Faculty of Sciences, Division of Mathematics and Computer Science Vrije Universiteit, Amsterdam, The Netherlands fjason,kielmann,
[email protected] http://www.cs.vu.nl/manta/
ABSTRACT This paper presents a generalization of the Java Remote Method Invocation model (RMI) providing an efficient group communication mechanism for parallel programming. In our Group Method Invocation model (GMI), methods can be invoked on a local object, on a remote object or on a group of objects (possibly with personalized parameters). Likewise, result values and exceptions can be returned normally, discarded, or, when multiple results are produced, combined into a single result. The different method invocation and reply handling schemes can be combined orthogonally, allowing us to express a large spectrum of communication mechanisms of which standard RMI and MPI-style collective communication are special cases. For each method, the invocation and reply scheme can be selected at runtime. GMI has been implemented in the Manta high-performance Java system. Using several micro-benchmarks and three applications, we compare GMI’s expressiveness and runtime efficiency to plain Java RMI and to the collective communication operations from the mpiJava library. Our results show that GMI significantly simplifies program complexity while our prototype implementation performs even faster than mpiJava (except for one test case).
1.
INTRODUCTION
Java supports distributed programming using the Remote Method Invocation (RMI) framework. The key advantage of RMI is that programmers can use the normal Java object model to express communication. All the complexities of the actual communication are hidden in the RMI libraries and in the stubs and skeletons generated by the compiler. For parallel applications, however, many authors have noticed that RMI is inflexible and that support for (collective) communication between groups of objects should be added [11, 23, 24]. Most proposals for such an extension merely provide Java language bindings to a native library for collective communication, such as MPI [11]. That approach adds to Java’s expressiveness, at the cost of adding a separate model that does not integrate well with Java’s objects, lacking some of RMI’s advantages, such as polymorphism.
In this paper, we introduce a different approach to adding group communication to Java. Our goal is to let the programmer express group communication using Java’s object model, just like RMI is used to express point-to-point communication. We therefore generalize the RMI framework in such a way that it can express communication with a group of objects. Our extended framework, called Group Method Invocation (GMI), hides the details of the group communication in the libraries, stubs, and skeletons. In particular, the RMI stub/skeleton mechanism has been modified to support different invocation and result-handling mechanisms required for group communication. The key insight of our work is that both the invocation of a remote method and the processing of its result value can be generalized to support group communication, and that these extensions can be combined in all possible manners, yielding a rich set of communication primitives (RMI being one of the simplest combinations). Using GMI it is possible to implement MPI-style collective communication where all members of a group collectively invoke the same method. However, GMI is more general than MPI in that it also allows a single group member to execute such an operation on multiple objects (without active involvement from the other members). Like Java RMI, GMI fully supports polymorphism which is necessary for Java’s model of objects and threads. The contibutions of this paper are as follows:
We generalize Java RMI to support a rich variety of group communication schemes that can be implemented efficiently while fitting seamlessly with Java’s object model. Our group communication model subsumes local and remote method invocation, as well as MPI’s collective communication. Our extensions can be orthogonally combined, making the model highly expressive, despite a small and simple Application Programming Interface (API). We compare our model and performance to mpiJava, an MPI language binding to Java [11]. The remainder of the paper is structured as follows. In Section 2 we describe our extended Java RMI framework for efficient collective communication. In Section 3 we describe the API and the implementation of this model in the Manta high-performance Java system [24]. In Section 4 we describe the performance of benchmark programs and applications. Section 5 presents related work, and Section 6 concludes.
2. THE MODEL In this section, we describe our group model, and how it is used to implement group communication. We will first briefly describe
the Java RMI model, and show how this model can be extended to support groups of objects. We will then describe how the communication patterns in these groups can be generalized to implement various types of group communication
0000 1111 1111 0000 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111
2.1 Remote Method Invocation Java RMI allows methods of an object to be invoked remotely. Although the object is located on one Java Virtual Machine (JVM), its methods can be invoked from another JVM. To make methods suitable for remote invocation, a special remote interface must be created, which extends the interface java.rmi.Remote. All methods which may be invoked remotely must be defined in this remote interface. An object can then be made suitable for RMI by implementing this remote interface (i.e. provide an implementation for these methods), and extending the java.rmi.UnicastRemoteObject (which contains some basic functionality required for Java RMI).
SumImpl
JVM 3
stub JVM 2
Figure 2: Stubs as remote references.
import java.rmi.*; done
interface Sum extends Remote { public void add(double v); public double get(); }
skeleton
0000 1111 1111 0000 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111
add(3.8)
class SumImpl extends UnicastRemoteObject implements Sum
1111 0000 0000 1111 0000 1111 0000 1111
stub JVM 1
thread
1111 0000 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111
invoke message return message
stub
JVM 1
1111 0000 0000 1111 0000 1111 0000 1111
add(3.8)
done
skeleton
SumImpl
JVM 3
Figure 3: An invocation on a stub. {
private double value = 0;
the invoker. public void add(double v) throws RemoteException { value += v; } public double get() throws RemoteException { return value; } }
Figure 1: A simple Java RMI example Figure 1 shows a simple Java RMI example. The Sum interface defines that the add and get methods may be invoked remotely. The SumImpl object provides an implementation for this interface. This SumImpl object can be used to determine the sum of a number of double values. Using the add method, a value can be added to the sum. The current value of the object can be retrieved using the get method. When this program is compiled, two extra objects are generated, a stub and a skeleton. The stub implements the remote interface. It contains special compiler-generated implementations of the methods in the remote interface. This stub can be used as a remote reference to the object. Figure 2 shows an example, where two stubs (on JVMs 1 and 2) are acting as remote references to the same object (on JVM 3). This is the RMI equivalent of having multiple references to an object. The skeleton (on JVM 3) serves as a bridge between the stubs and the object. When a method is invoked on a stub (see Figure 3), the stub sends a network message to the skeleton. This message contains a description of which method is invoked and the parameters needed for the invocation. The skeleton waits for such a message to arrive, retrieves the method description and parameters, and invokes the requested method on the object. The result of the method is returned to the stub (using a network message), which returns it to
2.2 Group Method Invocation Our GMI framework generalizes the RMI mechanism by allowing the method invocation to be forwarded to multiple objects, instead of just one. The replies from these invocations can also be handled in several different ways. The different forwarding and reply-handling schemes can be combined in all possible ways, giving a rich variety of group communication mechanisms. Below, we will first describe the notion of object groups, and then discuss the forwarding schemes, the reply-handling schemes, and their combinations.
2.2.1 Object Groups An object group consists of a number of objects, possibly on different JVMs. The objects are ordered: each object is assigned a rank. Groups can be created dynamically (i.e., at runtime), but their size (the number of objects they can contain) has to be given at the time of creation. All objects in a group must implement the same group interface. This group interface serves a similar function as a remote interface in Java RMI (shown in Figure 1). It defines the methods that are common to the objects of a group. These methods can be implemented by a generated stub. With Java RMI only the methods in a remote interface can be invoked on the stub. Likewise, with GMI, only the methods in a group interface can be invoked on the stub. All other methods of the group object can only be accessed locally. Information about rank and size of group objects is made available for use by application threads.
2.2.2 Forwarding Schemes In Java RMI, a stub always serves as a remote reference for a single object. All method invocations on a stub have the same object as a destination, which can not be changed. To support communication between multiple objects, GMI allows a stub to act as a reference to a group of objects, as shown in Figure 4.
1111 0000 0000 1111 0000 1111 0000 1111
stub JVM 1
SumImpl
ge
sa
es
JVM 2
m ke
vo
in
get()
1111 0000 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 result 7.0 1111
1111 0000 0000 1111 0000 1111 0000 1111 skeleton
1111 0000 0000 1111 0000 1111 0000 1111
JVM 2
inv
oke
ssa
com
bin
SumImpl
JVM 3
Figure 4: Group example
thread JVM 1
stub
me
ed
ge
res
ult
(3.0
1111 0000 0000 1111 .0) 1111 0000 0000 1111
local invocation The invocation is forwarded to a group object located on the same JVM as the stub. remote invocation The invocation is forwarded to a single object of the group, possibly on a different JVM as the stub. group invocation The invocation is forwarded to every object of the group. personalized group invocation The invocation is forwarded to every object of the group, but is personalized for each destination. Before the invocation is forwarded to a group object, a user defined method is invoked which may change the parameters of the invocation. Thus a personalized version of the call is sent to each group object. The first two schemes correspond to a normal (local) method invocation and a Remote Method Invocation (RMI); the last two schemes are used to express a variety of group communication patterns. Because, the forwarding scheme is selected individually for each method, the group stub can be configured in such a way that each of its methods behaves differently.
2.2.3 Reply-Handling Schemes In Java, a (local or remote) method either yields a result value or raises an exception. Concerning the method invocation mechanisms, both cases are treated uniformly. Accordingly, GMI uniformly returns regular result values or exceptions. In Java RMI, the manner in which stub and skeleton handle the method result is also fixed: they are always synchronous. After the stub forwards the method to the skeleton, it waits for a reply from the skeleton before continuing. The skeleton must therefore always send a reply back to the stub (even if the method has no result). However, in group communication, this may not be the desired behavior. When a thread invoking a method on a stub is not interested in the result, an asynchronous invocation (without reply) may be more desirable. If a stub forwards a method to multiple objects in a group, more than one reply is generated. GMI supports several mechanisms to combine these replies into a single reply that is returned to the original invoker. An example is shown in Figure 5, where an invocation is forwarded to a group of two objects. Both group objects execute
get()
result 3.0
SumImpl
get()
+4
skeleton JVM 3
Depending on the application requirements, the stub must be able to forward invocations to one or more objects in the group. GMI offers several forwarding schemes, which can be selected and changed at runtime:
result message (3.0)
skeleton 1111 0000 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111 0000 1111
skeleton
result 4.0
SumImpl object group
Figure 5: An example of result combining
this method, and return their result to the local skeleton object. Instead of returning the result to the stub, the skeletons communicate amongst each other to combine these two results to one. In the example, the first skeleton forwards its result to the second skeleton, which waits for its own result and the remote result to arrive, and then combines these two results into one (this is explained in more detail in Section 3.4). Similar to the stub offering multiple forwarding schemes, the skeleton offers multiple reply schemes, which can be selected at runtime:
discard result No result or exception is returned to the stub. Both are simply discarded by the skeleton. return (one) result The result is returned to the stub. If the method is invoked on a single object (i.e. local or remote invocation), the result can be returned directly. If it is invoked on multiple objects (i.e. group or personalized group invocation), one arbitrarily selected result is returned to the stub. combine result When multiple results are produced, they can be combined into a single result. A user-defined method is invoked which may combine the results, two at a time, in an application specific manner. Note that multiple results can be produced by a single (personalized) group invocation, or by multiple, related local or remote invocations. If one of the invocations raises an exception instead of a result, the combine will result in this exception. As with the forwarding scheme of the stub, the result handling of the skeleton can be changed at runtime, and selected separately for each method.
2.2.4 Orthogonal Combination of the Forwarding and Reply-Handling Schemes We have described four different schemes to forward a method invocation and three schemes for handling the replies. GMI allows these schemes to be combined in all possible ways, as shown in Table 1.
invocation local remote group personalized
discard asynchronous invocation asynchronous RMI asynchronous group invocation asynchronous personalized group inv.
result return (one) normal invocation RMI group invocation personalized group invocation
combine MPI-style combine MPI-style combine group combine personalized group combine
Table 1: Possible combinations of stub-skeleton behavior
For each of the four invocation schemes, we can choose between an asynchronous invocation (by discarding the result), a normal invocation (by returning a result), and an invocation in which all results are combined into a single value. All twelve combinations result in useful communication patterns. We will illustrate several forms of group communication with examples in the next section. GMI also subsumes asynchronous RMI, which is known to be a useful mechanism [29]. GMI also subsumes MPI’s collective group communication style, where all group members actively have to invoke the same primitive. This form of collective communication fits in well with MPI’s SPMD (Single Program Multiple Data) style, where all processes execute the same program. Java, however, has a more general model based on objects and threads, so Java programs are not limited to using the SPMD style. In GMI, a single thread can invoke a method on every object in the group, without requiring active participation of any other user threads. This style of group communication integrates seamlessly with the RMI model. Note that using GMI, an MPI-style combine operation can be done by locally invoking a method on all group members and then combining the results. Other types of MPI-style collective communication can be simulated using our GMI framework (while doing the reverse is much harder). It is therefore still possible to write SPMD-style Java programs using our framework.
2.3 Synchronization of Group Invocations In Java RMI, no guarantees are given about the order in which method invocations are received. For example, if the two stubs in Figure 2 simultaneously forward a method to the skeleton, the order in which the skeleton receives (or handles) these invocations is not defined. It may handle the call from JVM 1 before handling the call from JVM 2, do it in reverse order, or run the two invocations concurrently, depending on the behavior of the network and the implementation of the skeleton. It is the responsibility of the programmer to ensure that the object behaves correctly, independent of the order in which the methods invocations are received. This can be achieved by using the regular Java monitor mechanism (wait/notify). Similarly, our model does not guarantee any ordering of group invocations. For example, when two group invocations are done simultaneously on the same group, they may be received in different orders by different group objects. In this sense, a group invocation is equivalent to doing multiple RMI calls, and synchronization problems have to be addressed by the programmer in the same way as with RMI. The advantage of using group invocations, however, is that all the details of message forwarding and processing the results are handled efficiently by the implementation. In previous work [22] we have explored the possibilities of extending Java’s method invocation to groups of objects that can be replicated and updated as a whole, using a totally-ordered multicast to forward group invocations. We found that, although this model is useful, its consistency model is too strict for the needs of many applications, degrading their performance unnecessarily.
Furthermore, only a single group operation was supported, namely non-personalized broadcast with a single (uncombined) result. Our GMI model overcomes both limitations. Each group operation can have its own, application-specific consistency model, and a rich set of group communication operations is provided.
3. PROGRAMMING INTERFACE In this section we will describe the Application Programming Interface (API) of GMI and we will show three example applications to illustrate how the programmer can use this API. We will also briefly compare GMI to mpiJava and describe our implementation of the framework. The API can be implemented in any Java system. For our research we use the Manta high-performance Java system [24]. We will describe how we have extended this system to support the group model.
3.1 API We have designed an Applications Programming Interface for the GMI group model. Just like Java’s RMI, this API uses special interfaces and library classes, but no language extensions. The special interfaces have to be recognized by a compiler, which needs to generate the required stub and skeleton classes, just as with the java.rmi.Remote interface. The library routines are written entirely in Java and therefore are fully portable. We have defined a new Java package group which contains the necessary classes and interfaces for using groups of objects. The two main primitives of the package are the setInvoke and setResult methods, which are used to select the forwarding schemes and reply-handing schemes discussed in the previous section. The group package is shown in Figure 6. For brevity, the exceptions thrown by the methods are not shown. We will briefly describe the classes and interfaces in this package. The GroupMethods interface is similar to the java.rmi.Remote interface. It does not define any methods, but serves as a signal to the compiler. When the compiler encounters an interface extending GroupMethods, it recognizes it as a group interface (see Section 2.2), and generates the required stub and skeleton classes. The GroupStub class is the parent class for generated stubs. It is needed because, when the program is written, the names of generated stub classes are unknown (they are generated at compile time). Therefore, a generic stub class is needed to allow the programmer to use references to these unknown generated stub classes. The GroupMember class contains basic functionality required for group objects (which must always extend this class) and is similar to the java.rmi.UnicastRemoteObject of Java RMI. It contains two fields rank and size, which give the rank of the object in the group, and the total size of the group. These fields are left uninitialized after a new GroupMember object has been created. When the object joins a group, the rank and size fields are initialized, and the groupInit method is invoked. Although this method is empty in the GroupMember class, it can be overridden in subclasses, so initialization is postponed until the object joins a group (and the
package group; public interface GroupMethods { /* empty */ } public class GroupStub { /* empty */ } public class GroupMember { public int rank, size; public void groupInit() public GroupStub createGroupStub() } public class ParameterVector { public void addParameter(byte value); public void addParameter(char value); public void addParameter(int value); ... etc } public class Group { // Forwarding schemes public static final int LOCAL = 0, REMOTE = 1, GROUP = 2, PERSONALIZE = 3; // Reply-handling schemes public static final int DISCARD = 4, RETURN = 5, COMBINE = 6; public static void create(String name, int size) public static void join(String name, GroupMember m) public static void setInvoke(GroupStub stub, String method, int mode) public static void setInvoke(GroupStub stub, String method, int mode, int rank) public static void setInvoke(GroupStub stub, String method, int mode, String personal) public static void setResult(GroupStub stub, String method, int mode) public static void setResult(GroupStub stub, String method, int mode, String combine) }
Figure 6: The group package ranks and group size are known). The createGroupStub method returns a new stub for the group of this object. By default, method invocations are forwarded to the (local) group object that created the stub. The Group class contains static methods that can be used to manipulate object groups, and set the forwarding schemes and replyhandling schemes of stubs. A new group is created with create, which takes the group name (a string) and the number of members as parameters. If the group already exists, an exception will be thrown (not shown in Figure 6). GroupMember objects can be added using the join method. This method waits until the group exists and verifies that the group object implements the same group interface as the other members. It then blocks until the group is complete (i.e. size members have joined). When join returns, the group object has been initialized and is ready for use. The methods setInvoke and setResult are used to select the forwarding scheme and reply-handing scheme for a group method of stub. The method is passed in the method parameter, which, due to Java’s lack of function parameters, is a String. The String contains the description of a method as it appears in the program. After the setInvoke or setResult method has verified that the method is present in the stub, its behavior can then be changed according to the mode parameter. The possible values for the mode are LOCAL, REMOTE, GROUP and PERSONALIZE for the forwarding scheme, and DISCARD,
RETURN, and COMBINE for the reply-handling scheme. When the reply-handling scheme of a method is set to REMOTE, the parameter rank contains the rank of the destination group object. When the forwarding scheme is set to PERSONALIZE, the parameter personal contains the description of the method used to personalize the parameters for each destination. For a setResult method with a reply-handling scheme set to COMBINE, the parameter combine contains the description of the method used to combine the result. The method descriptions in the personal and combine parameters will be explained in more detail in Sections 3.2.2 and 3.2.3. The ParameterVector class will also be explained in Section 3.2.2 Both setInvoke and setResult check their parameters for consistency. If the number of parameters does not correspond to the mode, or any of the method, combine or personal methods is not found, an exception will be thrown (not shown in Figure 6), and the forwarding scheme and reply-handling scheme of the group method will remain unchanged.
3.2 Examples Using the API described above, creating a group object is similar to creating a Java RMI object. A group interface (extending the interface group.GroupMethods) must be created, which defines the methods that are common to the group objects. To be part of a group, the object must implement this group interface and extend the group.GroupMember class. An example is shown in Figure 7.
and takes group member sum and group stub stub as parameters.
import group.*; interface Sum extends GroupMethods { public void add(double v); public double get(); } class SumImpl extends GroupMember implements Sum
{
private double value = 0.0; public void add(double v) { value += v; } public double get() { return value; } }
Figure 7: A simple group object This example is the group-equivalent of the Java RMI example shown in Figure 1. A group interface Sum is created containing two methods, add and get. A group object is defined, SumImpl, which implements these methods. The implementation is the same as in the Java RMI example. The add method is used to add a value to the sum, while the get method can be used to retrieve the current value of the object.
3.2.1 Group Invocation public static void doWork(SumImpl sum, Sum stub) { if (sum.rank == 0) { Group.setInvoke(stub, "void add(double v)", Group.GROUP); stub.add(42.0); } }
Figure 9: A group invocation We now illustrate how a group invocation can be expressed in GMI (see Figure 9). One of the group members sets the forwarding scheme for the add method to Group.GROUP (using setInvoke) and then invokes this method. This invocation will be forwarded to all objects in the SumGroup (adding 42.0 to each of their value fields). This example illustrates the ease of expressing group communication in GMI, and the seamless integration with Java RMI.
3.2.2 Personalized Group Invocation public static void split(double value, int rank, int size, ParameterVector v) { v.addParameter(value/(size-rank));
class Main { public static void main(String [] args) { // if program rank is 0 // and number of programs is N Group.create("SumGroup", N); SumImpl sum = new SumImpl(); Group.join("SumGroup", sum); Sum stub = (Sum) sum.createGroupStub(); doWork(sum, stub); }
} public static void doWork(SumImpl sum, Sum stub) { if (sum.rank == 0) { Group.setInvoke(stub, "void add(double v)", Group.PERSONAL, "Main.split"); stub.add(42.0); } }
Figure 10: A personalized send
}
Figure 8: A simple group application The Main class, shown in Figure 8, contains the main program, which is run on each of the participating JVMs. One of the JVMs creates a new group called SumGroup.1 All JVMs then create a new SumImpl object, add this object to the group, and create a new stub (using the createGroupStub). The object group is now ready for use. This simple example illustrates how a group of objects is created. In the following sections we will extend the SumGroup example to illustrate three important forms of group communication: a group invocation, a personalized group invocation, and the combining of result values. We do so by giving different implementations of the method doWork, which is called from the main method of Figure 8
1 We assume that some infrastructure is present to allow multiple Java programs running on different JVMs to participate in a parallel computation. E.g., every JVM is capable to contact each other participating JVM, and the JVMs are ordered by a ranking scheme.
Personalized group invocations are frequently used in parallel computations. Figure 10 shows a toy example. We use setInvoke to set the forwarding scheme of the add method to PERSONAL. As described in Section 3.1, the description of the add method (“void add(double v)”) is passed to setInvoke in a String. The setInvoke method also needs an extra parameter containing the name of the personalization method, in this case Main.split. Explicitly stating in which class the method is defined (instead of forcing the method to be defined in the group object), gives the programmer more flexibility. It allows the programmer to reuse a previously defined group object with a new personalization or combine method. However, it does force the personalization method to be static. It is not necessary to specify the parameter types of Main.split, as they are derived from the parameter types of the group method, add. Since the group method is used to modify the parameters of the add method, it must be able to accept the same parameters as add. The rank of the destination object and the size of the object group are also made available to the personalization method. A problem is that the personalization method may need to modify multiple parameters. This is difficult to express in Java, because
Java methods can only return a single result and cannot have output parameters. To work around this limitation in Java, we introduce a new ParameterVector class for the last parameter of the personalization method. This class contains multiple versions of a single method, addParameter, each with a different parameter type. Before the personalization method is invoked, the stub checks the parameters of the group method (e.g. add), and creates a ParameterVector object which will accept the same parameters as the group invocation (e.g. double). The programmer can then modify the parameters, and store them in the ParameterVector object using addMethod calls. After the personalization method returns, the stub forwards the method invocation to the group object, using the modified parameters from the ParameterVector object, instead of the original ones. In the example shown here, the setInvoke method thus derives that the personalization method should have the description void Main.split(double value, int rank, int size, ParameterVector v). When the add method is now invoked on the stub, the invocation is forwarded to every object in the group, using the Main.split method to personalize the parameter. In this example, Main.split divides the parameter value by the size of the group, and adds this new value to the ParameterVector using the addParameter method. The invocation is then forwarded to the group object, after which this process is repeated for the next object in the group. In our example, a parameter value of 42.0/(size-rank) will be forwarded to each object in the SumGroup.
3.2.3 Result Combining public static double sum(double result1, int rank1, double result2, int rank2, int size) { return (result1 + result2); } public static void doWork(SumImpl sum, Sum stub) { if (sum.rank == 0) { Group.setInvoke(stub, "double get()", Group.GROUP); Group.setResult(stub, "double get()", Group.COMBINE, "Main.sum"); double result = stub.get(); } }
Figure 11: Combining a result In the example shown in Figure 11, result combining is used to retrieve the value of each object in the SumGroup (using the get method), and to sum up these values. The forwarding scheme of the get method is set to GROUP, to forward the invocation to the entire group. Thus, every object in the group will produce a result. To combine all these results into a single result, the reply-handling scheme is set to COMBINE. Thus, setResult needs an extra parameter containing the name of the combine method, in this case Main.sum. As with the personalization method, the parameter types of the combine method Main.sum are derived from the description of the group method get. The combine method gets five parameters: two intermediate results, the ranks of the group members that produced
these results, and the size of the group. The combination of the two intermediate results is returned. In the example shown here, the setResult method derives that the combine method should have the description int Main.sum(double result1, int rank1, double result2, int rank2, int size). After selecting the schemes for forwarding and reply handling, the get method is invoked on the stub, and forwarded to every object in the SumGroup. The results are then combined by repeatedly invoking the Main.sum method, until a single result value remains. This value is then returned to the stub.
3.3 Comparison to mpiJava In this section we compare our GMI framework to mpiJava using the All-Pairs Shortest Path application (ASP), which computes the shortest paths between all pairs of nodes in a given graph with N nodes. The program performs N iterations, and at the beginning of each iteration, one JVM has to forward a row of a distance matrix to all other JVMs. In our framework, this can be expressed using a group of BroadcastImp objects (one object per JVM) that each contains an array of rows. interface Broadcast extends GroupMethods { public void put(int i, int [] row); public int [] get(int i); } class BroadcastImpl extends GroupMember implements Broadcast { int [][] tab; BroadcastImpl(int n) { tab = new int[n][]; } public synchronized void put(int i, int [] r) { tab[i] = r; notifyAll(); } public synchronized void get(int i) { while (tab[num] == null) wait(); return tab[i]; } }
Figure 12: GMI code for the broadcast used in ASP The BroadcastImp is shown in Figure 12. To broadcast a row, the method put is invoked, which stores the row for iteration k at the corresponding entry in the array tab. A JVM that needs the next row invokes the get method, which waits until the row for the given iteration has been inserted and then returns it. As we discuss below, put will be configured to use the GROUP forwarding scheme, while get will be executed locally and not do any communication. Synchronization between the put and get methods uses the regular Java monitor mechanism (wait/notify). Figure 13 shows pseudo code for the actual ASP application. In the main method (which is started on all JVMs), a group of BroadcastImpl objects is created (as explained in Section 3.2). A stub for this group is then created, and, using setInvoke and setResult, the forwarding scheme and reply-handling scheme for the put method are set to GROUP and DISCARD. This stub is passed to the Asp object, which then starts the calculation using the doWork method. In doWork, a row can be forwarded by simply invoking the put method on the stub. A forwarded row can be received using the get method. For comparison, Figure 14 shows some of the code of the mpiJava version of ASP. We will use this program in Section 4 for a
class Asp { int n, rank; int [][] tab; Broadcast stub; Asp(Broadcast stub, int n, int rank) { this.n = n; this.rank = rank; // initialize the local data. } void doWork() { for (int k=0; k