mirage-clock icon indicating copy to clipboard operation
mirage-clock copied to clipboard

Solo5 pclock experiment

Open reynir opened this issue 2 years ago • 7 comments

This is work in progress experimentation of moving offset calculations of the monotonic clock relative to the wall clock out of solo5 bindings into Mirage land. Related to https://github.com/Solo5/solo5/pull/550

CC/ @dinosaure

reynir avatar Mar 22 '23 16:03 reynir

If you have the time to see if it's work with hvt, it will be superbe 👍 .

dinosaure avatar Mar 23 '23 09:03 dinosaure

I will test it next week :+1:

reynir avatar Mar 24 '23 09:03 reynir

I created a unikernel that prints out the current time every second, and built it with the latest release and with this branch and the solo5 branch. I then started them both roughly concurrently and suspended my laptop for about two minutes before resuming

            |      ___|
  __|  _ \  |  _ \ __ \
\__ \ (   | | (   |  ) |
____/\___/ _|\___/____/
Solo5: Bindings version v0.7.5
Solo5: Memory map: 512 MB addressable:
Solo5:   reserved @ (0x0 - 0xfffff)
Solo5:       text @ (0x100000 - 0x1e0fff)
Solo5:     rodata @ (0x1e1000 - 0x216fff)
Solo5:       data @ (0x217000 - 0x2c1fff)
Solo5:       heap >= 0x2c2000 < stack < 0x20000000
2023-03-31 10:33:47 -00:00: INF [application] 2023-03-31 10:33:47 -00:00
2023-03-31 10:33:48 -00:00: INF [application] 2023-03-31 10:33:48 -00:00
2023-03-31 10:33:49 -00:00: INF [application] 2023-03-31 10:33:49 -00:00
2023-03-31 10:33:50 -00:00: INF [application] 2023-03-31 10:33:50 -00:00
2023-03-31 10:33:51 -00:00: INF [application] 2023-03-31 10:33:51 -00:00
2023-03-31 10:33:52 -00:00: INF [application] 2023-03-31 10:33:52 -00:00
2023-03-31 10:33:53 -00:00: INF [application] 2023-03-31 10:33:53 -00:00
2023-03-31 10:33:54 -00:00: INF [application] 2023-03-31 10:33:54 -00:00
2023-03-31 10:33:55 -00:00: INF [application] 2023-03-31 10:33:55 -00:00
2023-03-31 10:33:56 -00:00: INF [application] 2023-03-31 10:33:56 -00:00
2023-03-31 10:33:57 -00:00: INF [application] 2023-03-31 10:33:57 -00:00
2023-03-31 10:34:00 -00:00: INF [application] 2023-03-31 10:34:00 -00:00
2023-03-31 10:34:01 -00:00: INF [application] 2023-03-31 10:34:01 -00:00
2023-03-31 10:34:02 -00:00: INF [application] 2023-03-31 10:34:02 -00:00
2023-03-31 10:34:03 -00:00: INF [application] 2023-03-31 10:34:03 -00:00
2023-03-31 10:34:04 -00:00: INF [application] 2023-03-31 10:34:04 -00:00
2023-03-31 10:34:05 -00:00: INF [application] 2023-03-31 10:34:05 -00:00
2023-03-31 10:34:06 -00:00: INF [application] 2023-03-31 10:34:06 -00:00
2023-03-31 10:34:07 -00:00: INF [application] 2023-03-31 10:34:07 -00:00
2023-03-31 10:34:08 -00:00: INF [application] 2023-03-31 10:34:08 -00:00
            |      ___|
  __|  _ \  |  _ \ __ \
\__ \ (   | | (   |  ) |
____/\___/ _|\___/____/
Solo5: Bindings version v0.7.5-23-g30bb0a8
Solo5: Memory map: 512 MB addressable:
Solo5:   reserved @ (0x0 - 0xfffff)
Solo5:       text @ (0x100000 - 0x1e0fff)
Solo5:     rodata @ (0x1e1000 - 0x216fff)
Solo5:       data @ (0x217000 - 0x2c1fff)
Solo5:       heap >= 0x2c2000 < stack < 0x20000000
2023-03-31 10:33:43 -00:00: INF [application] 2023-03-31 10:33:43 -00:00
2023-03-31 10:33:44 -00:00: INF [application] 2023-03-31 10:33:44 -00:00
2023-03-31 10:33:45 -00:00: INF [application] 2023-03-31 10:33:45 -00:00
2023-03-31 10:33:46 -00:00: INF [application] 2023-03-31 10:33:46 -00:00
2023-03-31 10:33:47 -00:00: INF [application] 2023-03-31 10:33:47 -00:00
2023-03-31 10:33:48 -00:00: INF [application] 2023-03-31 10:33:48 -00:00
2023-03-31 10:33:49 -00:00: INF [application] 2023-03-31 10:33:49 -00:00
2023-03-31 10:33:50 -00:00: INF [application] 2023-03-31 10:33:50 -00:00
2023-03-31 10:33:51 -00:00: INF [application] 2023-03-31 10:33:51 -00:00
2023-03-31 10:33:52 -00:00: INF [application] 2023-03-31 10:33:52 -00:00
2023-03-31 10:33:53 -00:00: INF [application] 2023-03-31 10:33:53 -00:00
2023-03-31 10:33:54 -00:00: INF [application] 2023-03-31 10:33:54 -00:00
2023-03-31 10:33:55 -00:00: INF [application] 2023-03-31 10:33:55 -00:00
2023-03-31 10:33:56 -00:00: INF [application] 2023-03-31 10:33:56 -00:00
2023-03-31 10:33:57 -00:00: INF [application] 2023-03-31 10:33:57 -00:00
2023-03-31 10:35:55 -00:00: INF [application] 2023-03-31 10:35:55 -00:00
2023-03-31 10:35:56 -00:00: INF [application] 2023-03-31 10:35:56 -00:00
2023-03-31 10:35:57 -00:00: INF [application] 2023-03-31 10:35:57 -00:00
2023-03-31 10:35:58 -00:00: INF [application] 2023-03-31 10:35:58 -00:00
2023-03-31 10:35:59 -00:00: INF [application] 2023-03-31 10:35:59 -00:00

The unikernel.ml for the latter unikernel is as below (based on the hello example):

open Lwt.Infix

module Hello (Time : Mirage_time.S) (Pclock : sig include Mirage_clock.PCLOCK val refresh : unit -> unit e↳nd) = struct
  let start _time _pclock =
    let rec loop () =
      Pclock.refresh ();
      Logs.info (fun f -> f "%a" (Ptime.pp_human ()) (Ptime.v (Pclock.now_d_ps ())));
      Time.sleep_ns (Duration.of_sec 1) >>= fun () -> loop ()
    in
    loop ()
end

What is noteworthy here is that:

  1. the signature of Mirage_clock.PCLOCK is extended with the new refresh function,
  2. before logging, Pclock.refresh () is called.

As you can see the clock jumps forward almost two minutes after 10:33:57 with the patches while the unpatched unikernel is stuck in the past.

reynir avatar Mar 31 '23 10:03 reynir

There are some things to consider:

Should the computation of offset and refresh () be implemented in C? It is a time sensitive computation, and it would be unfortunate if the garbage collector were to start in between.

The offset is a global value for the module. Is it time for a type t in the PCLOCK interface? Where type t := unit in existing modules.

reynir avatar Mar 31 '23 10:03 reynir

Hey, thanks for your patch. Could you clarify why we may need a refresh function? Unless I'm mistaken, I don't expect a wall clock to be called in performance-critical situations.

Relevant work is happening in the WASM Clock proposal: https://github.com/WebAssembly/wasi-clocks/blob/main/wit/wall-clock.wit (with relevant discussion for the upcoming multi-domain support: https://github.com/WebAssembly/wasi-clocks#per-process-and-per-thread-clocks). I'm in favour of simplifying/aligning our base device signature to what comes out of it.

samoht avatar Mar 31 '23 11:03 samoht

the signature of Mirage_clock.PCLOCK is extended with the new refresh function,

The refresh() function can be register with Mirage_runtime.run_enter_iter_hooks :+1:.

dinosaure avatar Mar 31 '23 11:03 dinosaure

Sure. The current state of solo5 is that an offset from the monotonic clock relative to the system clock (wall clock) is computed once at boot. The code has a comment saying this is done in order to minimise the use of hypercalls https://github.com/Solo5/solo5/blob/7d5b70f5937abf1e18c2353ffb93d0581ec31a0f/bindings/hvt/tscclock.c#L110-L117. @dinosaure has worked on a patch for solo5 that makes solo5_wall_clock() do a hypercall always. This patch reintroduces the offset computation but now in OCaml. The function refresh redoes the offset computation allowing a unikernel to choose a strategy for updating its time with the host.

As reducing the number of hypercalls was the previous behavior it seems to me that we should have good arguments for increasing the number of hypercalls rather than the other way around. This patch rather keeps the status quo. I don't know what exactly the perfomance hit is for a hypercall and how often the wall clock is checked in unikernels.

The WASI resource seems to use a device handle. This would be another argument in favor of adding a type t to PCLOCK.

reynir avatar Mar 31 '23 11:03 reynir