Seamless Thread and Execution Context Migration within a Java Virtual Machine Environment Student: Andrew Dorman s2009700@student.rmit.edu.au Supervisor: Dr. Caspar Ryan caspar@cs.rmit.edu.au ABSTRACT This paper describes a mechanism for preserving the execution state of a Java application during the migration process between two hosts. By using the Java Platform Debugging Architecture (JPDA), this project aims to seamlessly migrate both the object and its point of execution to a destination host, without session interruption. Keywords Java, code mobility, state migration, thread migration, distributed Java, JPDA. 1. INTRODUCTION With the introduction of cheap and powerful computers, there has been a shift away from centralised mainframes to Networks of Workstations (NOW) [2]. These workstations are often under utilised, performing light tasks and leaving the processor idle for substantial periods [13]. Mobile objects provide a means to better utilise resources by moving applications to lightly loaded or idle hosts. Java s ability to operate across heterogeneous environments has lead to it becoming a popular choice for mobile applications. While it provides support for object mobility through serialization, dynamic class loading and Remote Method Invocation (RMI), Java does not provide a framework for the migration of execution state. Current implementations of the Java Virtual Machine (JVM) do not allow the serialization of threads [5], leaving programmers to implement their own software solutions for state preservation. This project intends to investigate strong migration 1, using the Java Platform Debugging Architecture (JPDA) to capture the execution state of a thread, migrate it to a remote host, and resume processing at the point it left off. This 1 Strong Migration transfers the mobile object and its execution state See Background for a full description. system will allow for mobile objects to keep session state during host transfers. This paper is organised as follows. Section Two presents background material concerning mobile objects, while Section Three provides the rationale behind our project. Details of other systems implementing strong migration in Java are outlined in Section Four. Sections Five and Six explain our project goals and methodology respectively. 2. BACKGROUND With the increasing size and complexity of networks there has been much research into mobile objects. Their ability to suspend execution, migrate to a new host and resume processing provides a flexible approach to distributed computing. Object mobility falls into two categories: that of Weak Mobility and Strong Mobility [6]. Weak mobility transfers the object and its data to the target host, while strong mobility additionally transfers the execution state. This project is only concerned with strong mobility. Objects migrated using weak mobility must restart their execution afresh on the destination host, as there is no way to determine their point of execution before they were transferred. This approach may be suitable for maintaining fault tolerant systems, where it is acceptable for processes to restart and continue, but is not desirable for session dependant applications where execution state is important. In order to implement strong mobility we must have access to the object to be migrated, the object s state, the method call stack and the program counter [7]. Java is an interpreted language, wih programs executed in the Java Virtual Machine (JVM). The JVM emulates a host environment, acting as a layer of abstraction between the application and the platform. Stack frames and program counters for threads currently running are maintained in the JVM, which runs as one process on the host operating system. For this reason, it is not possible to obtain state information of a Java thread by acessing operating system processes, for this data is within the JVM. Java implements many key features to support code mobility in its Application Programming Interface, such as Remote Method Invocation for the transportation of objects between hosts, and serialization to save the current object
state. While serialization will persist object data it does not capture the point of execution, hence threads are not able to be serialized [11]. Java disallows dynamic inspection of the stack, preventing retrieval of the program counter, and does not currently support a mechanism for storing the execution point of a program. Debuggee Com. Channel JVM Back End JVMDI JDWP There exists implementations of techniques for strong migration in Java, which have sought to overcome the platform s short comings. Some of these include: Debugger Front End User Interface JDI Using a pre-processor to insert variables to checkpoint program execution. These variables are then evaluated on the target host to reconstruct execution [5]. Throwing Java Exceptions at migration time to capture execution state. The Exception Object is then transferred to the target host along with the object to reconstruct execution context [12][7]. Modifying the Java Virtual Machine to support the migration of execution context [3][4][1]. While these mechanism achieve strong migration, they suffer greatly in terms of performance and or portability. The Java Platform Debugging Architecture (JPDA) [9] is a request-event 2 based framework for the development of debugging applications. Debuggers are able to hook into programs running in the JPDA by requesting notification of events fired by the framework, eg. variable modification, exception, stepping, method entry and method exit events. Handler methods are activated in response to these events, allowing developers to implement the debugger s functionality and further query the running program. Once an event has been fired and caught by a handler, the JPDA permits the debugger to access information not normally available to Java applications. In particular the ability to obtain stack frames, variable values and the point at which execution was suspended are of particular interest to this project. Figure 1 shows how the JPDA is logically divided into a Back End and a Front End, connected via a Communication Channel. These layers are implemented using the Java Virtual Machine Debug Interface (JVMDI), the Java Debug Interface (JDI) and the Java Debug Wire Protocol (JDWP) respectively. The program being debugged is termed a Debuggee, while the application performing the debugging is the Debugger. The JVMDI defines the methods and functionality a Virtual Machine provides in JPDA. It contains a native code implementation of these methods, which developers with specialised debugging needs may choose to call directly from other native code applications. The JDWP specifies the format for communications between the debuggee (back end) and the debugger (front end). It 2 For more information on Java s event framework see [8]. Figure 1: JPDA Overview [9] does not specify the exchange mechanism, only the format of the data. The JDI contains high level interfaces, written in Java, that provide developers with convenient methods for debugger creation. The JDI utilises the lower layers of JPDA (JDWP and JVMDI), in order to obtain the required data and event notification. The division of the JPDA makes remote debugging of applications possible, as the front and back ends may be on separate hosts. In addition the debugger and debuggee may be running different Virtual Machines and/or on different platforms. Developers may choose to implement their product at any level of the JPDA. Debuggers not written in Java may connect directly to the JDWP for remote access the JVM, or the JVMDI for only local access. While it is recommended that applications use the JDI, developing at the JVMDI level may provide better support for more specific debugging requirements. It is using this framework that we intend to capture the execution state of a thread, migrate it to the destination host, and have it resume at the point it left off. 3. RATIONALE The Java programming language has been designed with portability in mind. Source code is compiled into an intermediate form called byte code, unlike C and C++ which are transformed into native machine code. The byte code is then interpreted into an executable form by a Java Virtual Machine (JVM), in which all Java programs are run. This allows developers to write and compile their applications once, and have them execute on any platform implementing a JVM. This ability to operate across heterogeneous environments, makes Java highly suitable for implementing distributed or mobile application. The JVM is disigned to act as a layer of abstraction between the application and the host operating system, defining a standard set of operations and functions available to a Java application. Modifying the JVM to incorperate additionaly functionality compromises the portability of the Java framework. Systems that require a non-standard JVM may only be deployed on hosts implemeting the vendor specific interpreter, removing an applications ability to operate in a
hetrogenious environment. Computing in today s society is no longer strictly confined to the office. Employees who are travelling to meet with customers or performing field work often switch between desktop, laptop and personal digital assistant throughout the day. Mobile objects implementing strong migration, allow applications to move with workers across devices without losing session state, thus seamlessly transferring between hosts. The implications for strong migration are not restricted to moving applications between devices. The ability to capture the execution state of threads allows for application check-pointing. Each checkpoint may be kept in non volatile storage and restored in the event of an application or host failure. We intend to address the lack of strong migration support within the language by using the Java Platform Debugging Architecture (JPDA), to preserve execution state. 4. LITERATURE REVIEW This section details implementations of existing techniques for strong migration in Java, and how this project intends to address their short comings. Exception Handling With the aid of a pre-processor and code insertion, Sekiguchi s JavaGo [12] utilises Java s exception handling capabilities to preserve execution state during migration. Methods capable of initiating object transfer are demarcated with the primitive migratory, and have try - catch blocks capable of responding to NotifyMigration exceptions inserted. Additionally, a variable acting as an artificial program counter is included and continuously updated during the program s session. For each method within the application, the preprocessor creates a state object, which is used to store local variable values at migration time. Upon the decision to migrate, a NotifyMigration exception is thrown and caught within the current method, allowing the saving of local variables to the state object. The exception is propagated to the calling method, repeating the state saving process for each method on the stack and chaining subsequent state objects together. To facilitate state restoration on the destination host, the pre-processor transforms method signatures to accept a state object as an extra parameter, and is used to initialise local variables upon reconstruction. Methods are also transformed to include switch-case blocks encompassing individual statements, which upon evaluation of the execution point variable, can resume the program at the correct point. Control structures such as for and while require a more complex code insertion technique involving code unfolding and duplication. This results in an increased method size of O(n 2 ) [12, p. 219], where n is depth of nested loops. Sekiguchi s technique of state preservation incurs a heavy performance reduction on the application, due to the preprocessor s code insertion. The approach described in this project will remove the requirement for large amounts of tracking and restoration code, instead utilising the JPDA to extract the required information to restore execution state on the destination host. Variable Insertion The Automatic Distribution of Java Applications (AdJava) [5] system, developed at the University of Adelaide, relies upon code insertion to maintain the execution state. By pre-processing the source code of a thread, a level variable is inserted and incremented after each statement in the run method, acting as an artificial program counter. Upon migration this variable is serialized with the object data, and transferred to the destination host. To resume execution, the level variable is evaluated through a series of switch-case statements, jumping to the current point of execution. The variable insertion technique used by AdJava causes a substantial increase in code size, an approximate ratio of 1:3 [5, p. 74]. This increase is responsible for higher memory consumption as well as longer transfer and execution time. A further limitation is that the artificial program counter is only inserted in the run method of the thread. Should the thread be suspended whilst in a called method, all computations completed since leaving run will be lost. This poses performance issues should migration be frequent, or if method calls are deeply nested, as more time is required to repeat calculations hence slowing program progression. This project intends to capture the state of a thread using the JPDA, eliminating the need for code insertion. By reducing the number of statements to be executed, a decrease in application running time will be achieved. Furthermore, this project aims to increase the granularity of state preservation, removing the need to repeat previously executed commands upon reconstruction. JVM Modification Systems based on exception handling and code insertion have all worked within the current confines of the JVM to transfer the execution state. However, researchers at IN- RIA s SIRAC Project [3] and the University of Meryland s Sumatra Project [1] have both modified the JVM to allow replication and access to internal data structures, making thread state capture and transfer possible. INRIA s implementation provides a more elegant and complete set of Java interfaces for development, and therefore shall be discussed in this paper. To support the changes made to the JVM, SIRAC provides two new classes, MobileThread (which extends Thread) and ExecutionEnvironment. MobileThread calls extractexecenv at migration time, storing the current execution state in a variable of type ExecutionEnvironment. transferexecenv is called to perform the migration to the destination host, where integrateexecenv creates a new thread initialised with the ExecutionEnvironment. For security reasons, all methods and data of ExecutionEnvironment are private (with the exception of the array of class names, which is required by the class loader), and may only be accessed by MobileThread s integrateexecenv. This
avoids the possibility of illegal access to objects on the stack, whilst still providing for the needs of migration. The advantages associated with JVM modification are primarily performance based, due to the lack of code insertion and complex restoration procedures seen in other implementations. Benchmarking performed by SIRAC shows that JVM modification can perform up to 13 times faster than Funfrocken s code insertion system Wasp [7]. This is achieved at the sacrifice of portability, as discussed earlier. By utilising the JPDA, we intend to provide a system that operates on a standard JVM, and deliver performance comparable to JVM modification. While it would be reasonable to expect considerable overhead involved in running an application through a debugger, the JPDA uses Full Speed Debugging [10]. This allows applications to run at normal speed, using only the interpreter. When an event of interest occurs, the full debugger is activated for interactive program querying. 5. PROJECT GOALS This project intends to produce a mechanism for capturing the execution state of a Java application using the Java Platform Debugging Architecture. By conducting quantitative analysis of our system and other strong migration implementations, this project will investigate the following research questions: 1. Is it possible to efficiently track and replicate module state and execution context with the Java Platform Debugging Architecture? 2. What impact does using the JPDA system have on the performance of applications in comparison to other strong migration systems implemented in Java? Due to Java s native support of transport protocols (eg sockets and RMI), this project will not be investigating frameworks for the transfer of objects, but will focus on the migration of the execution context. 6. METHODOLOGY The JPDA provides access to data previously unobtainable in a Java application. Upon capturing and handling a fired event, it is possible to access the execution stack, local variables and the point at which execution was suspended. In order to capitalise these features, our mobile object system will be developed in the following way: Develop software that will: - run a mobile object in the JPDA - add a request for stepping events to the mobile object at migration time - capture the stepping event - thereby suspending execution - obtain execution stack, variables and point of suspension - persist object and execution data - migrate object to destination host using RMI - rebuild object and resume execution of the thread The above approach requires a means of persisting the data obtained via the JPDA for migration to the destination host. This shall be developed as a part of this research project. Additionally processes to rebuild the object with the execution data and recommence at the point of suspension will also be developed. Initial research indicates that the following approach may provide the basis for resuming execution at the correct location. To recomence execution at the point of suspension, an if statement, that always evaluates to false, may be placed around previously executed commands, allowing them to be skipped at re-execution. Insertion of the if statement may be achieved by modifying the objects byte code and utilising the RedfineClasses method [10] provided by the JVMDI. RedfineClasses allows the substitution of byte code for an object currently executing, with a new byte code definition. Once the object has recommenced, the if statement may be removed to allow normal execution to continue. The evaluation of the developed framework will focus upon its efficiency in terms of both performance and portability in comparison to existing systems by: - replicating experiments of existing systems where source code is available - using experiment data from published systems if the source code is unavailable - benchmarking developed system against existing ones - comparative analysis of performance and portability. Performance metrics include: - time taken to pervade and restore both object and execution state data - general system overhead, a comparison of application running time in our system, and as a standard application. - time taken to migrate - size of both mobile object, and that of the execution data migrated to the destination host Timeline Figure 2 shows the intended schedule for our project. It is intended for initial software development to be completed by July, allowing for testing and modification. Similarly, thesis writing will also commence at an early stage, taking into consideration the possibility that further experiments are needed for a comprehensive report.
Software Development xxxxxxxxxxx Analysis of Existing implementations xxxxxx Testing xxx xx Experiments xxxxx xx Thesis Writing x xx xxxxxxxxxxxx +--- --- --- --- --- --- --- A M J J A S O Figure 2: Project Time Line [12] T. Sekiguchi, H. Masuhara, and A. Yonezawa. A simple extension of java language for controllable transparent migration and its portable implementation. In Coordination Models and Languages, pages 211 226. 1999. [13] F. Tandiary, S. Kothari, A. Dixit, and E. W. Anderson. Batrun: Utilizing idle workstations for large-scale computing. IEEE Parallel and Distributed Technology: Systems and Applications, 4(2):41 48, 1996. 7. REFERENCES [1] A. Acharya, M. Ranganathan, and J. Saltz. Sumatra: A language for resource-aware mobile programs. In J. V. Tschudin and C., editors, Mobile Object Systems: Towards the Programmable Internet, pages 111 130. Springer-Verlag, Heidelberg, Germany, 1997. [2] T. Anderson, D. Culler, and D. Patterson. A case for NOW. IEEE Micro, 15(1):54 64, 1995. [3] S. Bouchenak and D. Hagimont. Pickling threads state in the java system. In Third European Research Seminar on Advances in Distributed Systems (ERSADS 99),, Madeira Island, Portugal, 1999. http: //sardes.inrialpes.fr/~bouchena/publications/. [4] S. Bouchenak and D. Hagimont. Zero overhead java thread migration. Technical Report 0261, INRIA, 2002. http: //sardes.inrialpes.fr/~bouchena/publications/. [5] M. Fuad and M. Oudshoorn. AdJava - automatic distribution of java applications. In M. Oudshoorn, editor, Twenty-Fifth Australian Computer Science Conference, volume 4, pages 65 75, Melbourne, Australia, 2001. Australian Computer Society. [6] A. Fuggetta, G. Picco, and G. Vigna. Understanding code mobility. IEEE Transactions on Software Engineering, 24(5):342 361, 1998. [7] S. Funfrocken. Transparent migration of java-based mobile agents. In F. H. Kurt Rothermel, editor, Proceedings of the Second International Workshop on Mobile Agents (MA 98), pages 26 37, Stuttgart, Germany, 1998. Springer-Verlag. [8] D. M. Geary. Graphic Java 1.2, Mastering the JFC, volume 1 of Java Series. The Sun Microsystems Inc, Palo Alto, 3rd edition, 1999. [9] S. Microsystems. Java platform debugger architecture overview, 2000. http://java.sun.com/j2se/1.3/ docs/guide/jpda/jpda.html. [10] S. Microsystems. The java hotspot virtual machine v1.4.1 white paper, 2002. http://java.sun.com/ products/hotspot/docs/whitepaper/java_hotspot_ v1.4.%1/java_hspot_wp_v1.4.1_1002_3.html. [11] S. Microsystems. Object serialization: Frequently asked questions, 2003. http: //java.sun.com/products/jdk/serialization/faq.