MirageOS on OCaml 5

On behalf of all the numerous developers involved, it’s my pleasure to announce that the MirageOS ecosystem has seen the long-running work to port to OCaml 5 come to fruition: ocaml-solo5 v1.0 is now using OCaml 5.2.1!

What is ocaml-solo5

ocaml-solo5 is an OCaml cross compiler for producing Solo5 unikernels. Solo5 is the basis for MirageOS unikernels when they are not compiled as programs to run on a regular OS.

ocaml-solo5 responds to specific unikernel constraints. In particular it provides a placeholder for the standard C library that is complete enough that we can build the OCaml runtime without a full POSIX system to support it. That OCaml runtime can then be linked statically to OCaml programs in order to produce unikernels.

These constraints require us to keep track of developments of the OCaml compiler and particularly of its runtime. The major changes coming with OCaml 5 have required quite a lot of work (over 1 year) to bring our cross compiler up-to-date.

It should be noted that ocaml-solo5 is restricted to a single domain but it makes it possible to use the effects introduced with OCaml 5.

MirageOS & OCaml 5

The long road to bring Mirage on OCaml 5 started with adding support for Thread-Local Storage (TLS) in Solo5. Even if Solo5 doesn’t support the creation of threads, the OCaml 5 runtime stores domain-specific data, including for the first domain, in TLS. The main work was done in solo5#546 and solo5#542 with fixes in solo5#551 and solo5#554. It was released with Solo5 v0.8.0.

This foundational work on Solo5 unblocked the port of the compiler per se. As the OCaml runtime changed substantially between OCaml 4.x and 5.x, this required many changes in the minimal library, called nolibc, that provides simple implementations and stubs for the part of the libc interface the runtime uses. In particular, the memory management of the runtime is very different from OCaml 4.x (which is natural, due to the multicore support): it uses the mmap/munmap functions instead of malloc/free. mmap is a very versatile interface, tightly tied to the virtual memory. Providing adequate (correct but still simple) implementations of mmap/munmap in the context of Solo5, i.e. without virtualisation of the memory, required a careful review of how the interface is actually used in the runtime.

Besides that work on nolibc, building an OCaml compiler targeting Solo5 also requires a few patches to the compiler build system. As much work has been happening upstream to fix issues in building a cross compiler, this was taken as an opportunity to write clean patches in order to contribute them upstream and simplify the future of OCaml/Solo5 (along with other cross-compiler projects).

All this work has been combined in ocaml-solo5#134, which built on and completed ocaml-solo5#122, ocaml-solo5#124 and ocaml-solo5#129. It was released in ocaml-solo5 v1.0.0.

Now we are eager to learn how it behaves in your applications! Note in particular that, as already mentioned, the garbage collector is completely different from the one in OCaml 4. For example, the Mirage website currently runs the two versions, one on OCaml 4 and one on OCaml 5 with traffic being alternatively routed to one or the other, to monitor their behaviours. First experiments show that we must tweak the space_overhead parameter to have the OCaml 5 unikernel use the same amount of memory than the OCaml 4 one, at the price of some compute time. This generally means that you might have to experiment a bit if you run within very constrained memory limits.

How to give it a spin

To try the new OCaml 5, first create an OPAM switch with OCaml 5.2.1. Then, follow the standard procedure (see how to install it and how to build an hello-world unikernel). After installing ocaml-solo5, you can check with opam list ocaml-solo5 that it installed the version 1.x of the package.

People involved

Many people got involved at some point or another, either with code or comments, to that community effort (hopefully not forgetting anyone, in sort order):

  • Adam Steen
  • Adrian-Ken Rueegsegger
  • Christiano Haesbaert
  • Fabrice Buoro
  • Hannes Mehnert
  • Kate
  • Pierre Alain
  • Romain Calascibetta
  • Samuel Hym
  • Sébastien Hinderer
20 Likes