Our optimizations for serialization are centered on optimizing the serialization of arrays of primitive types (Characters, Integers, Reals, etc.). We believe that remote method invocations send arrays of primitive types in the common case, hence this optimization will have far reaching effects for a typical Java RMI. We have seen that the default method for serializing arrays is written in a general way which is concise and handles all cases, but on the other hand misses out on many optimizations that can be made for primitive types and arrays. In addition to optimizing serialization for arrays of primitive types, we will also look at optimizing serialization for struct-like objects (objects that contain no fields that are objects). Our project focuses on improving RMI performance, but we also recognize that improving serialization will improve performance of other parts of the Java system since serialization is a mechanism used throughout Java, not just with RMI.
Our optimization for thread reuse leverages off the fact that three new threads are created for each RMI call. After many RMI calls, these threads accumulate and slow down the entire JVM until the threads are garbage collected. We propose to keep a pool of threads available for RMI calls so that threads don't have to be created and destroyed for each RMI call. This will allow us to keep the number of threads used by RMI calls at a constant, instead of having them scale up linearly with the number of RMI calls that the program has made. One challenge will be to assign threads efficiently to service each RMI call. That is, if the overhead of managing a pool of threads is greater than the overhead of creating and destroying three threads for each RMI call, our optimization will degrade performance.
Certain classes of applications are currently impractical to be implemented with Java RMI due to performance and scalability problems. It is our opinion that our optimizations will provide enough speedup to enable these certain classes of applications to be implemented with Java RMI. Transactional databases, network file-systems, and finer-grained distributed computing are just a few examples of applications that would benefit from our optimizations.
| Task | Description |
| Benchmark Suite | The purpose of the benchmark suite is two fold: 1) Familiarize ourselves with the performance characteristics of Java RMI and Serialization, and 2) Provide a metric for evaluating our optimizations. Serialization We believe that serialization is inherent bottleneck in Java RMI. We plan to test serialization performance across two dimensions: Data type of serialized object (primitive types, primitive arrays, object arrays, and objects) Mechanism of serialization (default Serialization, custom Serialization, Externalization) We will measure time to serialize just into a memory buffer. We hope this will isolate serialization from RMI. |
| General RMI | We also wish to provide general benchmarks for RMI. We plan to do this in three dimensions: Vary data type as in above Vary serialization mechanism as in above Vary locality (local JVM, local machine, and remote machine) Across all dimensions we will be interested in average time taken for a RMI whose body is null. |
| Thread Specific | We believe that thread management within the RMI runtime contributes significantly to the overall performance of the RMI system. Based on some preliminary research and reading of the news-groups we believe that 3 threads are created and destroyed for each remote method invocation. This section of benchmarks will attempt to verify this and characterize any other thread use characteristics. We will implement benchmarks to test the following two areas: Iterated RMI’s. By this we mean repeated RMI in a single user thread and measuring performance as number of iterations increases. Multiple User threads making RMI’s. So how many concurrent RMI’s can the RMI runtime handle, and its performance characteristics. |
| Serialization Optimizations | We feel that serialization contributes significantly to overall RMI performance. After having done some preliminary analysis of code we have determined several optimizations that are feasible without breaking the Java/JVM model: Optimize for primitive types. Serializing primitive types should be inlined. Optimize for primitive type arrays (includes multi-dimensions). Again, this can be inlined. Advanced Optimizations. Time permitting we would like to look at optimizing object arrays. If an array is all of one runtime type, then some optimization can be done in, else one must default to the more general method. In all cases these optimizations will apply to the default serialization case. This approach provides several optimization opportunities without relying on the programmer to do things differently, or for the JVM to be changed. |
| Thread Re-use Optimizations | It is our assumption, based on some preliminary research, that each RMI causes multiple threads to be created and destroyed. Since thread creation is expensive we would like to implement a thread management mechanism that allows thread re-use. The basic idea is to maintain a pool of re-usable threads, where each thread is capable of being re-used. So in general, threads will not be generated and destroyed for each RMI. We will pay an initial price to create several of these threads and use them on a demand basis. We will also allow for the pool to grow in size on demand. If time permits we will implement additional mechanism that allows the pool to shrink at appropriate times . |