Upload
aronvirginas
View
126
Download
1
Embed Size (px)
DESCRIPTION
Laboratory ProjectAuthor: Áron Virginás‐Tar Master of Information Technology, Year 1Faculty of Automation and Computers"Politehnica" University of Timisoara
Citation preview
1
Real-‐Time Java™ Variants: Javolution
Laboratory Project for Real-‐Time System Design
Áron VIRGINÁS-‐TAR Master of Information Technology, Year 1 Faculty of Automation and Computers “Politehnica” University of Timișoara Abstract: Managed programming languages such as Java and C# have become increasingly popular in enterprise computing. Nevertheless, they are still underused in real-‐time environments due to design limitations. In particular, the presence of garbage collection renders them impractical for low-‐level programming. On the other hand, real-‐time systems have reached a level of complexity beyond the scaling capabilities of the low-‐level languages traditionally employed in real-‐time programming. In consequence, there is an increasing demand for high-‐level languages prepared to meet the requirements of safety-‐critical applications. Techniques to overcome typical real-‐time difficulties in Java include ahead-‐of-‐time compilation, incremental garbage collection and the use of virtual machine implementations that conform to the Real-‐Time Specification for Java (RTSJ). However, these are insufficient, as the standard Java library exhibits design characteristics that can easily ruin time-‐predictability: lazy initialization, array resizing, etc. To achieve true real-‐time predictability, one must use a time-‐deterministic library. In this article we present Javolution, an open source library suitable for safety-‐critical embedded and server-‐side applications.
1. Introduction In real-‐time software systems time-‐predictability is cardinal. Real-‐time software is written to be analyzable, with a simple control flow and no dynamic memory allocation. Therefore, real-‐time programmers usually rely on static data allocation and object pooling, as well unmanaged programming languages – usually subsets of C – which provide unfettered access to the memory. [4] By contrast, modern object-‐oriented languages take the control of memory away from programmers and guarantee memory safety through garbage collection. While this approach has its undeniable benefits in terms of productivity, reliability and security, performance suffers beyond the limits of usability in hard real-‐time environments. [6] On the other hand, as the code bases of real-‐time software solutions keep increasing – million-‐line systems are not unusual – factors such as scalability and reusability have triggered interest in Java as an alternative to low-‐level languages and motivated the development of real-‐time extensions. [3] The Real-‐Time Specification for Java (RTSJ) is a set of interfaces and behavioral specifications that aim to extend the Java programming language with
2
the functionality needed for real-‐time processing. The RTSJ addresses the critical issues of real-‐time programming by defining a minimum specification for the threading model and by offering memory that is not subject to garbage collection, along with threads that are not pre-‐emptible by the garbage collector. The specification proposes a region-‐based memory model. Memory is arranged as a tree of regions, called scoped memory areas. Objects that are needed by real-‐time tasks can safely be allocated in regions where they will be protected from garbage collection and, when no longer required, can be deallocated in mass. In this case safety is not enforced by the compiler, run-‐time checks are used instead. At the time the RTSJ was published, real-‐time garbage collection was still in its infancy. [6] Since then, deterministic garbage collection solutions – the most prominent of which being IBM’s Metronome GC – have further secured the applicability of Java in the development of real-‐time software. However, all the solutions presented above can prove insufficient in the lack of a time-‐deterministic class library. General-‐purpose libraries, such as the .NET Base Class Library or the Java Class Library, provide solutions for common tasks and include components for networking, graphical user interfaces, XML processing, logging, database access and many more. These libraries are well tested and standardized. However, they are designed for good average-‐case performance rather then optimal worst-‐case performance. Therefore, execution times are highly variable, which renders these libraries unsuitable for real-‐time systems. [3] Javolution is a result of the endeavor to offer an alternative to the Java Class Library that was developed with time-‐predictability in mind. It is a real-‐time library aiming to make Java applications faster and more time-‐predictable by providing high-‐performance utility classes. It also proposes a more advanced allocation scheme, to mitigate the shortcomings of the RTSJ’s scoped memory model, which can – in certain conditions – lead to illegal assignment errors and memory leaks. [3] 2. Real-‐Time Java: State of the Art In this section we offer a more detailed presentation of the state of the art in real-‐time Java and the context in which Javolution was created. 2.1. Real-‐Time Extensions In 1999, a document was published by the National Institute of Standards and Technology (NIST), which outlines the requirements for real-‐time Java. Based on these requirements, two independent specifications have been developed. The Real-‐Time Core Extension is a specification published by J-‐Consortium, an organization focused on Java-‐based health technology. It is still in a draft version and there is no implementation available. Hence, it has more historical than practical value. The specification that forms the basis for real-‐time systems developed upon Java is the already mentioned RTSJ, which defines a new API with support from the JVM. The specification also includes a reference implementation. It is
3
backward compatible with existing non-‐real-‐time Java software and is intended to run on top of J2SE. [7] Hereupon we present a brief overview of the RTSJ: thread management:
The base scheduler is defined as a priority-‐based, pre-‐emptive scheduler with at least 28 priority levels for real-‐time threads. There are 10 additional levels for traditional Java threads. Custom schedulers, which extend the class Scheduler, can also be created. The scheduler is able to schedule instances of the classes that implement the Schedulable interface. In the reference implementation the schedulable classes are: RealtimeThread, NoHeap-RealtimeThread and AsyncEventHandler. The implementation of synchronized includes an algorithm to prevent priority inversion. The threads waiting to enter a synchronized block are ordered by priority. In case of identical priorities, the FIFO algorithm is used to determine precedence. The RTSJ also offers a solution to facilitate communication between instances of Thread and RealtimeThread.
memory management: In the scoped memory allocation scheme proposed by the RTSJ, scopes are memory regions with an associated lifetime. When a scope is entered, all new objects are allocated in this memory area. On exit of the last thread from a scope, all allocated objects are destroyed and the memory area is freed. Physical memory is used to control allocation in memories with different access time. Raw memory allows byte-‐level access to physical memory. Immortal memory is a memory shared between all threads. It is not subject to garbage collection; hence all objects created in this memory area have the same lifetime as the application. Heap memory is the traditional garbage collected memory. [7] The region-‐based allocation model proposed by the RTJS has been proven error-‐prone and incurs significant runtime overheads due to dynamic memory access checks. [5] Real-‐time garbage collectors offer an alternative solution and they will be discussed in a later section.
representation of time: The RTSJ introduces classes to represent relative and absolute time with nanosecond precision. Time parameters are composed of a long attribute that stands for milliseconds and an int that represents nanoseconds within the last millisecond. Each time object has an associated Clock object, whereas multiple clocks can represent different sources or resolutions of time. [7]
The most prominent implementation of the RTSJ is Oracle’s own Java Real-‐Time System (Java RTS). 2.2. Real-‐Time Virtual Machines and Garbage Collection Garbage colletion is arguably the most important potential source of non-‐determinism in Java. The development of time-‐predictable garbage collection (GC) schemes – and real-‐time virtual machines (VM) that implement them – represents the next major step toward real-‐time Java.
4
Garbage collection relieves the appication programmer from the burden of memory management by automatically freeing memory that is no longer in use. However, garbage collectors are typically designed to free all unused objects in bulk. This leads to an unpredictable timing behavior characterised by long pauses and tasks that occasionally take much longer than expected. In other words, typical garbage collector implementations have been optimized for troughput rather than uniform overhead and responsiveness. [6] The RTSJ overcomes these issues by disabling garbage collection in the memory scope accessible to real-‐time threads. This approach, however, has been proven error-‐prone and impractical. [7] Real-‐time garbage collection has been investigated as an alternative, several different approaches being proposed and implemented. The Metronome collector, for example, uses periodic scheduling to ensure predictable pause times. Jamaica, on the other hand, uses work-‐based to circumvent the need for a moving garbage collector. Java RTS uses a non-‐moving approach with a scheduler that only permits the collection of garbage when no reak-‐time task is active. There exist several Java virtual machine implementations – both commercial and open source – that support the RTSJ. The most significant implementations are IBM WebSphere, Java RTS, PERC and Jamaica. All of these systems support real-‐time garbage collection, though they use significantly different approaches, ranging from time-‐based to work-‐based techniques with varying degrees of support for concurrency. [5] 2.3. Real-‐Time Libraries The strength of Java, amongh others, lies in its extensive standard class library, which offers components for most common tasks. However, these components have never been intended to be used for safety critical systems, rather they have been optimize to perform best in average cases. [1] Even if some classes of the library are safe to be used in RealTimeThread or NoHeapRealTimeThread, it is not clearly specified which are these classes. [7] In [3] the authors analyze the requirements a library must meet in order to guarantee the level of predictibility expected in a real-‐time application. They propose the following two: predictable worst-‐case execution time (WCET)
To be suitable for real-‐time systems, all operations in the library must be statically analyzable for WCET. This implies that the maximum bound of any loop must be known beforehand. Information about all loop bounds must therefore be incorporated into the real-‐time library. In addition, all blocking calls to the operating system must be avoided. The unknown time of blocking calls defeats predictability. Instead, real-‐time libraries should offer support for periodic tasks, a form that is easily analyzable.
predictable worst-‐case memory consumption Time-‐predictable execution of tasks can usually be guaranteed only when virtual memory management is disabled. Hence, it is essential to guarantee that the application never runs out of memory. For this, dynamic memory management must be carefully analyzed: the maximum stack size of each
5
thread and interrupt handler must be determined and included in the link process. In order to be able to properly schedule the garbage collector, the allocation and deallocation rate of objects must also be known.
The authors prove the plausibility of their requirement system by implementing three real-‐time library prototypes: a library of collection classes [Canteen]
Canteen offers time-‐predictable implementations for the List, Set and Map interfaces declared in Java’s standard library, allowing them to act as time-‐predictable replacements for the standard collection classes.
a non-‐blocking network stack [ejip] The lowest level of the stack contains device drivers for Ethernet, SLIP, and a PPP implementation. The next level contains implementations for communication protocols: IP, UDP3 and a restricted subset of TCP. The library meets the proposed real-‐time requirements, as all of its operations are WCET analyzable and its memory consumption is known before runtime.
a set of trigonometric functions This library contains time-‐ and memory-‐predictable implementations of trigonometric functions. The implementations combine iterative calculations based on Taylor series and pre-‐computed values stored in lookup tables. This approach ensures predictability, as the number of iterations required for convergence can be determined beforehand and hardcoded.
Above we have presented a set of proof-‐of-‐concept libraries. In the following section we will present Javolution, a complete real-‐time Java library, which provides time-‐deterministic alternative implementations for the standard library interfaces. 3. Javolution Javolution is an open source real-‐time library for Java, developed by Jean-‐Marie Dautelle, the author of [1] and [2]. The main goal of Javolution is to assist Java developers in creating faster and more time-‐predictable applications. It addresses the main issues that block the standard Java library from being applicable in safety-‐critical systems. 3.1. Features The main features offered by the Javolution library are the following: algorithmic parallel computing support with concurrent contexts; high performance and time-‐deterministic implementation of standard Java
packages: util, lang, text, io and xml; context programming in order to achieve true separation of concerns
(logging, performance, etc.); support for two different allocation models: value-‐type and stack (in thread-‐
local pools or RTSJ scoped memory); Struct and Union base classes for direct interfacing with native
applications;
6
real-‐time StAX-‐like XML parser implementation, which does not rely on object creation;
hard real-‐time XML marshalling and unmarshalling, which works with existing Java classes and supports references;
simple yet powerful configuration management; a testing framework addressing not only unit tests, but also performance and
regression tests. [8] Another important aspect of the Javolution library is that all classes are RTSJ-‐safe. This means that if an object has to perform some lazy initialization or increase its capacity, this is always done in the same memory where the object itself is located. [1] In the following subsections we will present the most important features in a little more detail, based on the developer’s own presentation. 3.1.1. Real-‐Time I/O Real-‐time systems usually do not work in isolation. Instead, they have to communicate with other similar systems, legacy systems or with the hardware itself. The RTSJ allows direct access to physical memory, which means that device drivers can be written entirely in Java. However, unlike C or C++, Java does not support struct and union, which makes low-‐level programming difficult and error-‐prone. Unlike in C/C++, the storage layout of Java objects is not determined by the compiler, rather it is deferred to runtime and determined by the interpretor or the just-‐in-‐time compiler. This makes cooperation with C/C++ code difficult. Javolution addresses this issue by offering the following classes: Struct and Union. These two classes imitate the struct and union types from C. They follow the same alignment rules and support the same features, making it easy to convert C header files to Java classes. The following code fragment illustrates the usage of Struct:
3.1.2. Garbage-‐Free XML Serialization XML serialization in Java is normally rather messy, as it generates a lot of garbage. This happens because the standard XML readers and writers are based on String. The String class being immutable, its instances can only be recycled through garbage collection. This has a seriously negative impact on performance and memory footprint, leading to XML serialization being 2-‐4 times slower in Java than in C/C++. The XML engine implemented in Javolution uses buffer-‐based CharSequence instead of String. Thus no garbage is generated, which
class Clock extends Struct { // Hardware clock mapped to memory Unsigned16 seconds = new Unsigned16(5); Unsigned16 minutes = new Unsigned16(5); Unsigned16 hours = new Unsigned16(4); ... }
7
eliminates the garbage collection overhead and leads to an XML serializer of comparable performance to its C/C++ counterpart. 3.1.3. Separation of Concerns. Context Separation of concerns is a principle that aims to separate a computer program into distinct features that overlap in functionality as little as possible. In the standard library there are plenty of cases where the separation of concerns is far from perfect. One such case is logging. Using the standard logging solution a class has to know too much information about the logger. In order to achieve true separation of concerns, Javolution introduces the notion of context. Each thread has a context that can be customized by a higher authority. This allows for much cleaner and flexible code. Javolution offers the following out-‐of-‐the-‐box contexts: LocalContext
to define locally scoped environment settings; ConcurrentContext
to take advantage of concurrent algorithms on multi-‐processors systems; AllocatorContext
to control object allocation; LogContext
offerst thread-‐based or object-‐based logging capability; PersistentContext
to achieve persistency across multiple program execution; SecurityContext
to address application-‐level security concerns; TestContext
to address different aspects of testing such as performance and regression.
3.1.4. Performance and Regression Tests
Unit tests too often only focus on validation and neglect performance. However, in the context of real-‐time systems, not meeting timing requirements can be regarded as a critical failure. Therefore, it is extremely important not only to be able to measure the performance of a given code, but also to be able to detect automatically if any change in the code breaks the timing assumptions. To facilitate this, Javolution provides a specialized context called TimeContext, which is capable of measuring and verifying the minimum, average and maximum execution time of any test case. The following example code illustrates the use of TimeContext in performance testing:
class MyTestCase extends TestCase() { ... public void validate() { long ns = TimeContext.getMaximumTime("ns"); // Error if execution time is more than 100 ns TimeContext.assertTrue(ns < 100); ... } ... }
8
3.1.5. Package Structure Hereupon we will present the package structure of the Javolution API. The library is built around the following packages: javolution.context
provides real-‐time Context to facilitate the separation of concerns and achieve a higher level of performance and code predictability;
javolution.io provides utility classes for input and output (such as Struct and Union for direct interoperability with C/C++);
javolution.lang provides fundamental classes and interfaces; some of which are either missing from the java.lang package or are not available for all platforms (including J2ME CLDC);
javolution.testing provides classes and interfaces to facilitate all aspects of testing including unit tests, performance, regression, etc.;
javolution.text provides classes and interfaces to handle text;
javolution.util provides high-‐performance collection classes and miscellaneous utilities; although this package provides very few collection classes, they are substitutes for most of java.util.* classes (for example, java.util.IdentityHashMap would be a FastMap with an identity key comparator);
javolution.xml provides support for the encoding of objects, and the objects reachable from them, into XML; and the complementary reconstruction of the object graph from XML;
javolution.xml.sax provides SAX2 and SAX2-‐Like parsers; the later being several times faster than conventional SAX2 parsers (by avoiding String allocations while parsing);
javolution.xml.stream provides StAX-‐like XML readers/writers which do not require object creation (such as String) and are consequently faster and more time predictable than standard StAX classes;
javolution.xml.ws provides classes and interfaces to create and handle web services.
3.2. Performance The author of the library has published several benchmark results. These benchmarks examined the performance of Javolution collections in comparison with standard Java collections. The following charts present the benchmark results published by the developer on the project’s website:
9
10
11
Results show that the average performance of Javolution collection classes is not significantly better than that of their standard Java counterpart. However, the main advantage of Javolution collections is that they are time-‐deterministic (the maximum execution time is very close to the minimum execution time) and RTSJ-‐safe. 4. Summary With the publication of the RTSJ and the introduction of complying virtual machines, Java is becoming a viable alternative to low-‐level languages in real-‐time programming. However, Java’s vast standard library was developed to perform well in the average case, not with time-‐predictability in mind. Javolution aims to address this issue and offer developers a performance-‐oriented time-‐deterministic library, that is suitable for real-‐time application development.
12
Bibliography [1] J. M. Dautelle – Fully Time Deterministic Java, in Proceedings of AIAA Space 2007 Conference, 2007 [2] J. M. Dautelle – Validating Java for Safety-‐Critical Applications, in Proceedings of AIAA Space 2005 Conference, 2005 [3] T. Harmon, M. Schoeberl, R. Kirner, R. Klefstad – Toward Libraries for Real-‐Time Java, in Proceedings of the 2008 11th IEEE Symposium on Object Oriented Real-‐Time Distributed Computing, pp. 458-‐462, 2008 [4] D. F. Bacon, P. Cheng, D. Grove, M. Hind, V. T. Rajan, E. Yahav, M. Hauswirth, C. M. Kirsch, D. Spoonhower, M. T. Vechev Poellabauer – High-‐Level Real-‐Time Programming in Java, in Proceedings of the 5th ACM International Conference on Embedded Software, pp. 68 – 78, 2005 [5] F. Pizlo, L. Ziarek, E. Blanton, P. Maj, J. Vitek – High-‐Level Programming of Embedded Hard Real-‐Time Devices, in Proceedings of the 5th European Conference on Computer Systems, pp. 69-‐82, 2010 [6] F. Pizlo, J. Vitek – Memory Management for Real-‐Time Java: State of the Art, in Proceedings of the 11th IEEE Symposium on Object Oriented Real-‐Time Distributed Computing, pp. 248-‐254, 2008 [7] M. Schoeberl – Restrictions of Java for Embedded Real-‐Time Systems, in Proceedings of the 7th IEEE International Symposium on Object-‐Oriented Real-‐Time Distributed Computing, 2004 [8] Official Javolution website, available at http://javolution.org/ [9] Javolution API, available at http://javolution.org/target/site/apidocs/index.html