Reflexes: programming abstractions for highly responsive computing in Java

Jesper Honig Spring
2008
Achieving sub-millisecond response times in a managed language environment such as Java introduces significant implementation challenges. The Achilles' heel of Java is its reliance on automatic memory management for reclaiming dead objects. Typically, the garbage collectors used in commercial Java virtual machines are designed to maximize the performance of applications at the expense of predictability. Moreover, it is non-deterministic as to when and for how long the garbage collector will
more » ... As a consequence garbage collection introduces execution interference that can easily reach hundreds of milliseconds, preventing the timeliness requirements of the real-time systems from being satisfied. Another source of interference relates to the integration of real-time tasks with a time-oblivious application. Typical programming practices for sharing data between threads involve synchronized access to some shared data structure through mutual exclusion. In a real-time system this might lead to unbounded blocking of the real-time thread, so-called priority inversion, causing serious deadlines infringements. Faced with these challenges a system designer typically has two options: to deploy a realtime garbage collector (RTGC), or to restrict the programming model. RTGCs achieve much improved predictability over traditional stop-the-world garbage collectors by interleaving the application execution with the garbage collection. Recent advances in real-time garbage collection algorithms have reduced latency to approximately 1 millisecond. Nevertheless, some applications, e.g., safety critical applications certified according to DO-178B, have temporal requirements beyond what is possible with state-of-the-art RTGCs. Moreover, real-time garbage collectors still face the problem of priority inversion. This thesis presents Reflexes, a simple, statically type-safe restricted programming model facilitating the construction of highly-responsive applications in Java. Reflexes are designed to make it easy to write and integrate simple periodic tasks or complex stream processors, both observing real-time timing constraints in the sub-millisecond range, into larger time-oblivious Java applications. Reflex tasks run in a part of memory free from garbage collection interference, and maintain a class-based separation between object lifetimes, enabling reclamation of periodic garbage in constant time. Tasks are organized in a graph and communicate through uni-directional, non-blocking channels. Furthermore, Reflexes enable non-blocking interaction between real-time tasks and time-oblivious code using methods with transactional semantics, circumventing typical problems of priority inversion when using common programming practices for synchronizing access to shared data. Reflexes specify a set of static safety checks preventing dangling pointers and preventing a Reflex from observing heap-allocated objects in an inconsisiii iv tent state as they are, e.g., when being copied by a garbage collector. These checks are enforced statically by an extension of the standard Java compiler to guarantee correctness. We describe two implementations of Reflexes: a stand-alone prototype implementation built on top of a research Java real-time virtual machine, and an implementation based on an integration of Reflexes with two existing restricted programming models into a single unified framework, Flexotask, running on top of an industrial-strength Java real-time virtual machine. Whereas the prototype implementation of Reflexes is limited to a virtual machine with uni-processor support and exploits non-standard features of the virtual machine, the latter implementation leverages the multi-processor support of an industrial-strength virtual machine with minimal extensions. For both implementations we report separately on a number of encouraging results from empirical experiments using benchmark and real-world applications. Specifically, our experiments show that Reflexes in both cases are capable of achieving sub-millisecond response time with a high degree of predictability. Résumé Dans un langage de programmation interprété comme Java, où les programmes s'exécutent a l'aide d'une machine virtuelle, il est difficile d'atteindre des temps de réponses en dessous de la milliseconde. Le talon d'Achille du langage Java dans un contexte temps réel est sa dépendance au ramasse-miettes collectant les objets morts. Les ramasses-miettes implémentés dans les machines virtuelles commerciales sont conĉus pour maximiser la performance au prix d'une baisse de leur prédictabilité. De plus, le moment où ils se déclenchent tout comme la durée de leur exécution sont non déterministes. L'exécution d'un ramasse-miettes interfère avec celle du programme, causant facilement des retards de plusieurs centaines de millisecondes, ce qui rend difficile le respect des contraintes temporelles du programme. Une autre source d'interférenceémerge lorsqu'une tâche temps réel se mêleà des tâches sans contrainte temporelle. Lorsque des tâches différentes accèdentà une même ressource, une abstraction d'exclusion mutuelle est utilisée pour réglementer l'ordre d'accèsà cette ressource. Dans un système temps réel, cette abstraction peut s'avérer dangereuse dans la mesure où une tâche temps réel peut se retrouver bloquéeà attendre une tâche de plus faible priorité. Ce phénomène est appelé inversion de priorité et peut causer de graves dépassement des délais impartisá la tâche temps réel. Faceà ces défis, un concepteur de systèmes a en général deux options: déployer un ramassemiettes temps réel (RTGC pour Real-Time Garbage Collector) ou restreindre le modèle de programmation. Un ramasse-miettes temps réel atteint une bien meilleure prédictabilité que les ramasses-miettes traditionnels, basés sur une approche pause-pour-maintenance (stop-theworld), en intercalant leur exécution tout au long de l'exécution du programme même. Des avancées récentes dans ce domaine ont réduit la latence aux environs d'une milliseconde. Néanmoins, certaines applications, comme les applications critiques certifiées D0-178B, ont des contraites temporelles que l'on ne peut atteindre avec ce type de ramasse-miettes. Cette thèse présente Reflexes, un modèle de programmation restreintà la fois simple, sûr au niveau du typage et qui facilite la conception d'applications Java hautement réactives demandant une prédictabilité en dessous de la milliseconde. Les Reflexes sont conĉus de manièreà faciliter l'écriture et l'intégration de tâches périodiques simples et de traitements complexes de flux dans des applications n'ayant pas de contraintes temporelles tout en respectant des délais impartis de moins d'une milliseconde. Pour ce faire, les tâches Reflex s'exécutent dans une partie mémoire où le ramasse-miette n'intervient pas et séparent en mémoire les objets de différentes classes, ce qui permet de récupérer l'espace alloué périodiquement par ces tâches en un temps constant. Ces tâches, communiquant par des canaux unidirectionnels non bloquants, forment un graphe. v vi De plus, Reflexes autorise l'interaction non bloquante entre des tâches temps réels et non temps réel en utilisant des sémantiques transactionnelles, ce quiévite le problème typique d'inversion de priorité. Le modèle de programmation Reflexes spécifie un ensemble de règles statiques de sécurité pouréviter des pointeurs pendants et empêche une tâche Reflex d'observer des objets, alloués sur le tas, dans unétat inconsistent (par exemple s'ils sont en train d'être manipulés par le ramasse-miettes). Ces règles sont contrlées statiquement par une extension du compilateur Java afin de garantir l'exécution correcte du programme. Ce document présente deux implémentations de Reflexes: un prototype autonome implémenté sur une machine virtuelle temps réel Java issue du monde de la recherche et une implémentation basée sur l'intégration de Reflexes dans deux modèles de programmation existant, sur la plateforme unifiée Flexotask. Cette dernière s'exécute sur une machine virtuelle temps réel industrielle Java de référence. Alors que le prototype de Reflexes est limité aux machines monoprocesseur et exploite des fonctions non standard de la machine virtuelle, la seconde implémentation tire parti des architectures multiprocesseurs en ajoutant un minimum d'extensionsà la machine virtuelle. Pour les deux implémentations, cette thèse présente des résultats encourageant d'expérimentations, utilisantà la fois des jeux d'essai et de vraies applications. Plus particulièrement, les expériences montrent que Reflexes est capable dans les deux cas de respecter des délais en dessous de la milliseconde tout en assurant un très haut degré de prédictabilité.
doi:10.5075/epfl-thesis-4228 fatcat:2iwmmzsipfbm7l3t6gwitalcri