Code Cache Optimizations for Dynamically Compiled Languages

Tobias Hartmann
2014
Past activities in optimizing the performance of the HotSpot TM Java Virtual Machine focused on the performance of the dynamic compilers and the supporting runtime. Since dynamically compiled code is stored in a code cache to avoid recompilations, the organization and maintenance of the code cache has a significant impact on the overall performance. The organization of the code cache became even more important with the introduction of tiered compilation in Java Platform, Standard Edition (Java
more » ... dard Edition (Java SE) 7. By using two dynamic compilers with different characteristics, not only the amount, but also the number of different types of compiled code increased. The current code cache is optimized to handle homogeneous code, i.e., only one type of compiled code. The code cache is organized as a single heap data structure on top of a contiguous chunk of memory. Therefore, profiled code which has a predefined limited lifetime is mixed with non-profiled code, which potentially remains in the code cache forever. This leads to different performance and design problems. For example, the method sweeper has to scan the entire code cache while sweeping, even if some entries are never flushed or contain non-method code. This thesis addresses these issues at a lower layer by redesigning the structure of the code cache. The code cache is segmented into multiple code heaps, each of which contains compiled code of a particular type and therefore separates code with different properties. The disadvantage of having a fixed size per code heap is then minimized by lazily creating and dynamically resizing these code heaps at runtime. The main advantages of this design are (i) more efficient sweeping, (ii) improved code locality, (iii) the possibility for fine grained (per code heap) locking and (iv) improved management of heterogeneous code. A detailed evaluation shows that this approach improves overall performance. The execution time is improved by up to 7% and the more efficient code cache sweeping reduces the time taken by the sweeper by up to 46%. This, together with a decreased fragmentation of the non-profiled code heap by around 98%, leads to a reduced instruction translation lookaside buffer (44%) and instruction cache (14%) miss rate. iii Zusammenfassung Vergangene Bemühungen die Leistung der HotSpot TM Java Virtual Machine zu optimieren, konzentrierten sich vorrangig auf die Leistung der dynamischen Compiler und der unterstützenden Laufzeitumgebung. Da dynamisch kompilierter Code aber, um Rekompilierungen zu vermeiden, in einem Code Cache gespeichert wird, hat die Organisation und Verwaltung dieses Codes einen signifikanten Einfluss auf die Gesamtleistung. Dieser Sachverhalt gewann noch an Bedeutung als mit Java SE 7 die Tiered Compilation eingeführt wurde. Durch gleichzeitige Verwendung zweier dynamischer Compiler, die den Code teilweise instrumentieren, erhöhte sich nicht nur die Menge kompilierten Codes, sondern auch die Anzahl der verschiedenen Codetypen. Das Design des Code Caches basiert zur Zeit auf einer Heap Datenstrukturüber einem zusammenhängenden Speicherbereich und ist optimiert, homogenen Code, d.h. kompilierten Code eines Typs, zu speichern. Daher wird Profiled Code, welcher eine vordefinierte, beschränkte Lebenszeit hat, mit Non-Profiled Code, welcher potentiell dauerhaft im Code Cache bleibt, vermischt. Dies führt unweigerlich zu verschiedenen Leistungseinbußen und Designproblemen. Beispielsweise muss der Sweeper immer den gesamten Code Cache scannen, auch wenn einige Einträge nie gelöscht werden oder Non-Method Code enthalten. Der Ansatz welcher in dieser Arbeit präsentiert wird, geht die Probleme auf einer tieferen Ebene an, indem der Code Cache restrukturiert wird. Der Code Cache wird in mehrere Code Heaps aufgeteilt, welche nur kompilierten Code eines bestimmten Typs enthalten und deshalb Code mit verschiedenen Eigenschaften trennen. Der Nachteil einer festen Größe pro Code Heap wird dadurch minimiert, dass die Code Heaps lazy, d.h. erst wenn nötig, erstellt werden und zur Laufzeit ihre Größeändern können. Die Vorteile dieses Designs sind (i) effizienteres Sweepen, (ii) eine verbesserte räumliche Codelokalität, (iii) die Möglichkeit von präzisem Locking (pro Code Heap) und (iv) eine verbesserte Verwaltung von heterogenem Code. Eine detaillierte Auswertung der Implementierungen zeigt, dass der Ansatz vielversprechend ist. Die Laufzeit ist um bis zu 7% verringert, wobei das effizientere Sweepen die Zeit im Sweeper um bis zu 46% reduziert. Dies, zusammen mit der verringerten Fragmentierung des Non-Profiled Code Heaps um ca. 98%, führt zu einer geringeren Instruction TLB (44%) und Instruction Cache (14%) Miss Rate. v
doi:10.3929/ethz-a-010098048 fatcat:i3k65j2yurdydd64ozhydvk4fi