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 ;;