Artifact for Jmvx: Fast Multi-threaded Multi-Version eXecution and Record-Replay for Managed Languages
Description
Introduction
Java Multi-Version Execution (JMVX) is a tool for performing Multi-Version Execution (MVX) and Record Replay (RR) in Java.
Most tools for MVX and RR observe the behavior of a program at a low level, e.g., by looking at system calls.
Unfortunately, this approach fails for high level language virtual machines due to benign divergences (differences in behavior that accomplish that same result) introduced by the virtual machine -- particularly by garbage collection and just-in-time compilation.
In other words, the management of the virtual machines creates differing sequences of system calls that lead existing tools to believe a program has diverged, when in practice, the application running on top of the VM has not.
JMVX takes a different approach, opting instead to add MVX and RR logic into the bytecode of compiled programs running in the VM to avoid benign divergences related to VM management.
This artifact is a docker image that will create a container holding our source code, compiled system, and experiments with JMVX.
The image allows you to run the experiments we used to address the research questions from the paper (from Section 4).
This artifact is desiged to show:
- [Supported] JMVX performs MVX for Java
- [Supported] JMVX performs RR for Java
- [Supported] JMVX is performant
In the "Step by Step" section, we will point out how to run experiments to generate data supporting these claims.
The 3rd claim is supported, however, it may not be easily reproducible.
For the paper we measured performance on bare metal rather than in a docker container.
When testing the containerized artifact on a Macbook (Sonoma v14.5), JMVX ran slower than expected.
Similarly, see the section on "Differences From Experiment" to see properties of the artifact that were altered (and could affect runtime results).
Thanks for taking the time to explore our artifact.
Hardware Requirements
- x86 machine running Linux, preferably Ubuntu 22.04 (Jammy)
- 120 Gb of storage
- About 10 Gb of RAM to spare
- 2+ cores
Getting Started Guide
Section is broken into 2 parts, setting up the docker container and running a quick experiment to test if everything is working.
Container Setup
- Download the container image (DOI 10.5281/zenodo.12637140).
- If using docker desktop, increase the size of the virtual disk to 120 gb.
- In the GUI goto Settings > Resources > Virtual Disk (should be a slider).
- From the terminal, modify `diskSizeMiB` field in docker's `settings.json` and restart docker.
- Linux location:
~/.docker/desktop/settings.json
. - Mac location :
~/Library/Group Containers/group.com.docker/settings.json
.
- Linux location:
- Install with
docker load -i java-mvx-image.tar.gz
- This process takes can take 30 minutes to 1 hour.
- Start the container via:
docker run --name jmvx -it --shm-size="10g" java-mvx
- The `
--shm-size
` parameter is important as JMVX will crash the JVM if not enough space is available (detected via a SIGBUS error).
- The `
Quick Start
The container starts you off in an environment with JMVX already prepared, e.g., JMVX has been built and the instrumentation is done.
The script test-quick.sh
will test all of JMVX's features for DaCapo's avrora
benchmark.
The script has comments explaining each command.
It should take about 10 minutes to run.
The script starts by running our system call tracer tool.
This phase of the script will create the directory /java-mvx/artifact/trace
, which will contain:
natives-avrora.log
-- (serialized) map of methods, that resulted in system calls, to the stack trace that generated the call./java-mvx/artifact/scripts/tracer/analyze2.sh
is used to analyze this log and generate other files in this directory.
table.txt
- a table showing how many unique stack traces led to the invocation of a native method that called a system call.recommended.txt
- A list of methods JMVX recommends to instrument for the benchmark.dump.txt
- A textual dump of the last 8 methods from every stack trace logged.
- This allows us to reduce the number of methods we need to instrument by choosing a wrapper that can handle multiple system calls.
- `FileSystemProvider.checkAccess` is an example of this.
JMVX will recommend functions to instrument, these are included in recommended.txt
.
If you inspect the file, you'll see some simple candidates for instrumentation, e.g., available
, open
, and read
, from FileInputStream
.
The instrumentation code for FileInputInputStream
can be found in /java-mvx/src/main/java/edu/uic/cs/jmvx/bytecode/FileInputStreamClassVisitor.java
.
The recommendations work in many cases, but for some, e.g. FileDescriptor.closeAll
, we chose a different method (e.g., FileInputStream.close
) by manually inspecting dump.txt
.
After tracing, runtime data is gathered, starting with measuring the overhead caused by instrumentation.
Next it will move onto getting data on MVX, and finally RR.
The raw output of the benchmark runs for these phases is saved in /java-mvx/artifact/data/quick
.
Tables showing the benchmark's runtime performance will be placed in /java-mvx/artifact/tables/quick
.
That directory will contain:
instr.txt
-- Measures the overhead of instrumentation.mvx.txt
-- Performance for multi-version execution mode.rec.txt
-- Performance for recording.rep.txt
-- Performance for replaying.
This script captures data for research claims 1-3 albeit for a single benchmark and with a single iteration.
Note, data is captured for the benchmark's memory usage, but the txt tables only display runtime data.
For more, see readme.pdf
or readme.md
.