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