mte/unikernel/duniverse/eqaf/test/test_branch.ml
2025-11-11 02:07:51 +01:00

140 lines
4.8 KiB
OCaml

let exit_success = 0
let exit_failure = 1
(* First computation wants to count operations needed by
- one_if_not_zero
- zero_if_not_zero
- select_int
For each /assembly instructions/, we update a counter. This way is not
totally true. Even if we check by hands that bitwise operations don't
emit branches, this is our only assumption! *)
let operation = ref 0
let logical_shift_right a b = incr operation ; a lsr b
let logical_or a b = incr operation ; a lor b
let shift_right a b = incr operation ; a asr b
let logical_and a b = incr operation ; a land b
let logical_not a = incr operation ; lnot a
let minus a = incr operation ; (- a)
let sub a b = incr operation ; a - b
let[@inline always] minus_one_or_less n =
logical_shift_right n (sub Sys.int_size 1)
let[@inline always] one_if_not_zero n = minus_one_or_less (logical_or (minus n) n)
let[@inline always] zero_if_not_zero n = sub (one_if_not_zero n) 1
let[@inline always] select_int choose_b a b =
let mask = shift_right (logical_or (minus choose_b) choose_b) Sys.int_size in
logical_or (logical_and a (logical_not mask)) (logical_and b mask)
let one_if_not_zero_ops =
let _ = one_if_not_zero 0x7eadbeef in
Format.printf "[one_if_not_zero]: %d operation(s).\n%!" !operation ;
!operation
let () = operation := 0
let zero_if_not_zero_ops =
let _ = zero_if_not_zero 0x7eadbeef in
Format.printf "[zero_if_not_zero]: %d operation(s).\n%!" !operation ;
!operation
let () = operation := 0
let select_int_ops =
let _ = select_int 0 1 2 in
Format.printf "[select_int]: %d operation(s).\n%!" !operation ;
!operation
let eqaf_sleep () = Unix.sleep 1
let logical_shift_right a b = eqaf_sleep () ; a lsr b
let logical_or a b = eqaf_sleep () ; a lor b
let shift_right a b = eqaf_sleep () ; a asr b
let logical_and a b = eqaf_sleep () ; a land b
let logical_not a = eqaf_sleep () ; lnot a
let minus a = eqaf_sleep () ; (- a)
let sub a b = eqaf_sleep () ; a - b
let[@inline always] minus_one_or_less n =
logical_shift_right n (sub Sys.int_size 1)
let[@inline always] one_if_not_zero n = minus_one_or_less (logical_or (minus n) n)
let[@inline always] zero_if_not_zero n = sub (one_if_not_zero n) 1
let[@inline always] select_int choose_b a b =
let mask = shift_right (logical_or (minus choose_b) choose_b) Sys.int_size in
logical_or (logical_and a (logical_not mask)) (logical_and b mask)
(* Finally, we count how many time we spend when we call our
functions. [eqaf_sleep] spends 1 second, so our bitwise operators
should spend 1 second + some nanosecond. At the end, execution of
them should be closely equal to our operation counter where:
1 operation ~= 1 second
To be able to count time, we use [caml_time] which is available only
on Linux and for a native compilation (see [@unboxed]). Because bitwise
operation spend at least 1 second, we finally [floor] our results to
delete noise.
NOTE: [check/check] does a linear regression to delete noise and really
get how long is our functions. We think that for our functions:
- zero_if_not_zero
- one_if_not_zero
- select_int
[check/check] is too huge. *)
let time () = Clock.now ()
let fdiv a b = a /. b
let () =
let t0 = time () in
let _ = one_if_not_zero 0x7eadbeef in
let t1 = time () in
let v0 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[one_if_not_zero 0x7eadbeef]: %fs.\n%!" v0 ;
let t0 = time () in
let _ = one_if_not_zero 0x0 in
let t1 = time () in
let v1 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[one_if_not_zero 0x0]: %fs.\n%!" v0 ;
if v0 = v1
&& int_of_float v0 = one_if_not_zero_ops
&& int_of_float v1 = one_if_not_zero_ops
then () else exit exit_failure
let () =
let t0 = time () in
let _ = zero_if_not_zero 0x7eadbeef in
let t1 = time () in
let v0 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[zero_if_not_zero 0x7eadbeef]: %fs.\n%!" v0 ;
let t0 = time () in
let _ = zero_if_not_zero 0x0 in
let t1 = time () in
let v1 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[zero_if_not_zero 0x0]: %fs.\n%!" v0 ;
if v0 = v1
&& int_of_float v0 = zero_if_not_zero_ops
&& int_of_float v1 = zero_if_not_zero_ops
then () else exit exit_failure
let () =
let t0 = time () in
let _ = select_int 0 1 2 in
let t1 = time () in
let v0 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[select_int 0 1 2]: %fs.\n%!" v0 ;
let t0 = time () in
let _ = select_int 2 1 0 in
let t1 = time () in
let v1 = Int64.(floor (fdiv (to_float (sub t1 t0)) 1000000000.)) in
Format.printf "[select_int 2 1 0]: %fs.\n%!" v1 ;
if v0 = v1
&& int_of_float v0 = select_int_ops
&& int_of_float v1 = select_int_ops
then () else exit exit_failure
;;