The Inspector is the tool co-developed with the VM for debugging.
Launching the Inspector is as simple as using the
mx inspect command.
mx inspect -cp com.oracle.max.tests/bin test.output.GCTest2
The Inspector window should appear in a few moments. Go here for other ways of launching the Inspector.
The most useful way to test Maxine is to execute some of the standard
benchmarks on the image previously built with the
mx image command.
In this example, we will use the SpecJVM98 and DaCapo benchmarks.
After downloading the benchmarks, set the following environment
export SPECJVM98_ZIP=/Users/acme/benchmarks/specjvm98.zip export DACAPOBACH_JAR=/Users/acme/benchmarks/dacapo-9.12-bach.jar
Then execute the following command:
mx test -insitu -tests=specjvm98,dacapobach ---------------------------------------------------------------------------------------- Running reference SpecJVM98 _201_compress: 1607 ms Running maxvm (std) SpecJVM98 _201_compress: 3309 ms 2.059x ---------------------------------------------------------------------------------------- ... Running reference DaCapo-bach avrora: 3960 ms Running maxvm (std) DaCapo-bach avrora: 13815 ms 3.488x ---------------------------------------------------------------------------------------- ...
Note that the harness used to run the benchmarks against a reference VM
is a little brittle.
In particular, it compares the output written to
stdout by the two
executions and if they don’t match, it determines the Maxine VM
execution to have failed.
We’ve noticed that for some benchmarks on some platforms, the execution
output is not such a reliable fingerprint.
To see the actual output of the benchmark, and the exact command used to
run it, look in the
Maxine includes a set of tests that are useful in catching regressions and measuring progress when making changes. The three types of tests included in the distribution are described below.
Tests the Maxine code base prior to building and running the VM. For example, there are JUnit tests for the general purpose utility classes in the Base project. There are also JUnit tests that use the various IR interpreters to ensure that each level of IR in Maxine’s compiler produces the correct output.
These are tests that are executed on the VM. The first subcategory of VM tests are very simple unit tests that test a specific VM feature and/or Java bytecode instruction in isolation (i.e. avoiding as many other VM features as possible). To ensure strong isolation, these tests are built into the boot image and executed in such a way that precludes using a more general testing framework such as JUnit. The second subcategory of VM tests are called output tests. These tests are comprised of standard Java programs (i.e. they have a class containing a main method) that produce some deterministic output via System.out. These tests compare the output of these programs when run under Maxine VM and another trustworthy JVM (such as HotSpot).
When porting Maxine VM’s compilers to a new Instruction Set Architecture QEMU is utilized to virtually run unit tests and regress the correctness of the generated code.
To be able to run cross-ISA tests Maxine VM relies on gcc cross-compilers, gdb-multilib and qemu.
The easiest way to run the cross-ISA tests is by using the
beehivelab/maxine-dev docker image.
If you insist on running natively, assuming an Ubuntu 18.04 LTS installation, the following will install the required packages.
ARMv7 and AArch64¶
sudo apt-get install \ gdb-multilib qemu-system-arm \ gcc-aarch64-linux-gnu gcc-arm-none-eabi
sudo apt-get install gcc-riscv64-linux-gnu
sudo apt-get install wget texinfo mkdir /tmp/riscv cd /tmp/riscv/ wget https://ftp.gnu.org/gnu/gdb/gdb-8.2.1.tar.xz tar xf gdb-8.2.1.tar.xz cd /tmp/riscv/gdb-8.2.1 ./configure --target=riscv32-elf,riscv64-elf --disable-multilib --prefix=/opt/riscv make -j sudo make install
sudo apt-get install libglib2.0-dev libpixman-1-dev flex bison wget https://download.qemu.org/qemu-3.1.0.tar.xz tar xf qemu-3.1.0.tar.xz cd /tmp/riscv/qemu-3.1.0 ./configure --target-list=riscv64-softmmu,riscv32-softmmu,riscv64-linux-user,riscv32-linux-user --prefix=/opt/riscv make -j sudo make install
Don’t forget to add
Logging and Tracing¶
Maxine provides two related mechanisms for logging and/or tracing the
behavior of the VM, manual string-based logging using the
com.sun.max.vm.Log class, or more automated, type-based logging, that
is integrated with the Inspector, using
These are related in that
VMLogger includes string based logging as an
option and so can replace the use of
Currently the VM uses a mixture of these two mechanisms, with conversion
being done opportunistically.
For simplicity, we will use the term tracing to describe string-based
logging in the following.
If you are adding logging to a VM component you are strongly encouraged
to use the
Use the class
com.sun.max.vm.Log to do manual tracing.
The class includes a variety of methods for printing objects of various
By default the output goes to the standard output but can be re-directed
to a file by setting the environment variable
running the VM.
To selectively enable specific tracing in the VM, define a
com.sun.max.vm.VMOption with the name
identifies the tracing.
You should avoid string concatenation (or any other code involving
allocation) in tracing code, especially inside a
While this should not break the VM (allocation will fail fast with an
error message if a VM operation does not allow it), allocation can add
noise to your logs.
Lastly, if the logging sequence involves more than one logging
statement, you should bound the sequence with this pattern:
boolean lockDisabledSafepoints = Log.lock(); // multiple calls to Log.print...() methods Log.unlock(lockDisabledSafepoints);
This will serialize logging performed by multiple threads. Of course, it will also serialize the execution of the VM and may well make the race you are trying to debug disappear!
Native Code Tracing¶
Maxine provides some tracing of the small amount of native code that
supports the VM.
By default this is conditionally compiled out of the VM image but can be
selectively enabled by editing
and rebuilding with
mx build and rebuilding the VM image.
This is particularly useful if the the VM crashes during startup.
For example to enable all tracing set
log-ALL to 1.
In type-based logging, the actual values that you want to log are passed
to an instance of the
com.sun.max.vm.log.VMLogger class using methods
defined in the class.
Evidently, at the
VMLogger level, type-based logging is something of a
misnomer, as it cannot know the types of the actual values.
In practice the values are logged as untyped
Word values, but
extensive automated support is provided to handle the conversion to/from
The optional tracing support is driven from the values in the log.
For more details see Type-based Logging.
Debugging Maxine Java Tasks¶
The Maxine project includes a number of Java programs that can be
launched as commands of the
For example, the
mx image command described above runs the
com.sun.max.vm.prototype.BootImageGenerator class on a host JVM.
This simplest way to debug such a command is to use the
option of the mx script.
This will launch the Java program with extra options telling it to wait
and listen for a JDWP-capable debugger on port 8000.
You then configure a JDWP-enabled debugger to attach to this port.
The advantage of this approach is that you can easily launch the command with different command line arguments without having to create/modify an IDE launch configuration.
To get a core dump from a Maxine VM process, it is simplest to do
gcore <pid> from another shell.
This forces a core dump but does not terminate the process, which
continues after the dump is taken.
An alternative is to use
kill -s ABRT <pid> which does kill the
process after the dump is taken.
One other difference is that
gcore allows the path to the core dump
file to be specified with the
-c <corefile> option, whereas
puts it in a default location, typically
core in the current working
It is possible to force a core dump on a fatal VM error by setting the
-XX:+CoreOnError when running the VM.
The following invocation:
mx inspect --mode=attach --target=file --location=dumpfile
will then bring up the Inspector on the core dump.
If you omit the
--location argument, it will put up a dialog box.
Unfortunately this will only work if the associated Maxine VM was run
-XX:+MakeInspectable option, otherwise some key data
structures needed by the Inspector will not have been created.