I have the following code of which I don’t quite understand the performance behaviour.
This is a CRC-32 computation made with int32
OCaml integers (I would like to get rid of this int32 unboxing hack in a library, especially since it makes Adler-32 computation actually slower).
Basically on my machine (arm64, ocaml 14.1.0) the runs with the code below are done in 80ms (which is larger than when using the unboxing trick).
But if I replace in the string
function the k
indexing the table by say the byte
and Sys.opaque
identity the k
, I get runs of 30ms. So something seems not to quite add up, I have looked at the assembly or the lambda code but nothing jumps to my eyes (though I’m rusty on that).
Has maybe someone a hint about what may be happening ?
cat - > /tmp/crc.ml <<EOF
let poly = 0xedb88320l
let table =
let init i =
let c = ref (Int32.of_int i) in
for k = 0 to 7 do
c :=
if Int32.logand !c 1l <> 0l
then (Int32.logxor poly (Int32.shift_right_logical !c 1))
else (Int32.shift_right_logical !c 1);
done; !c
in
Bigarray.Array1.init Bigarray.int32 Bigarray.c_layout 256 init
let string s =
let i = ref 0 and max = String.length s - 1 in
let c = ref 0xFFFF_FFFFl in
while (!i <= max) do
let ci = Int32.to_int !c in
let byte = String.get_uint8 s !i in
let k = (ci lxor byte) land 0xFF in
c := Int32.logxor
(Bigarray.Array1.get table k : int32)
(Int32.shift_right_logical !c 8);
incr i;
done;
Int32.logxor !c 0xFFFF_FFFFl
let random ~length =
let ic = In_channel.open_bin "/dev/random" in
let finally () = In_channel.close_noerr ic in
Fun.protect ~finally @@ fun () ->
In_channel.really_input_string ic length |> Option.get
let test_speed crc_of_string s =
let start = Sys.time () in
let crc = crc_of_string s in
let stop = Sys.time () in
let dur = (stop -. start) *. 1000. in
Format.printf "%dms %lx\n" (truncate dur) crc
let main () =
let length = (20 * 1024 * 1024) in
let s = random ~length in
test_speed string s;
test_speed string s
let () = if !Sys.interactive then () else main ()
EOF
cd /tmp && ocamlopt crc.ml && ./a.out