diff --git a/benchs/dune b/benchs/dune index 936b04c2..374bd297 100644 --- a/benchs/dune +++ b/benchs/dune @@ -1,11 +1,9 @@ - -(executables - (names run_benchs run_bench_hash) + (executables + (names run_benchs run_bench_hash run_objsize) (libraries containers containers.data containers.iter containers.thread benchmark gen iter qcheck oseq - batteries) + batteries base sek) (flags :standard -warn-error -3 -safe-string -color always -open CCShims_) (ocamlopt_flags :standard -O3 -color always -unbox-closures -unbox-closures-factor 20) ) - diff --git a/benchs/objsize.ml b/benchs/objsize.ml index 668be91c..b05298cc 100644 --- a/benchs/objsize.ml +++ b/benchs/objsize.ml @@ -23,12 +23,12 @@ open Obj comparisons are done using physical equality. *) module H = Hashtbl.Make( - struct - type t = Obj.t - let equal = (==) + struct + type t = Obj.t + let equal = (==) let hash o = Hashtbl.hash (magic o : int) end) - + let node_table = (H.create 257 : unit H.t) let in_table o = try H.find node_table o; true with Not_found -> false @@ -53,15 +53,15 @@ let rec traverse t = if tag < no_scan_tag then begin count := !count + 1 + n; for i = 0 to n - 1 do - let f = field t i in + let f = field t i in if is_block f then traverse f done end else if tag = string_tag then - count := !count + 1 + n + count := !count + 1 + n else if tag = double_tag then count := !count + size_of_double else if tag = double_array_tag then - count := !count + 1 + size_of_double * n + count := !count + 1 + size_of_double * n else incr count end diff --git a/benchs/run_benchs.ml b/benchs/run_benchs.ml index 1d9fa1f4..cedf2f60 100644 --- a/benchs/run_benchs.ml +++ b/benchs/run_benchs.ml @@ -17,7 +17,27 @@ let repeat = 3 (* composition *) let (%%) f g x = f (g x) +let opaque_ignore x = ignore (Sys.opaque_identity x) + module L = struct + let bench_iter ?(time=2) n = + let f i = opaque_ignore i in + let l = CCList.(1 -- n) in + let ral = CCRAL.of_list l in + let vec = CCFun_vec.of_list l in + let sek = Sek.Persistent.of_array 0 (Array.of_list l) in + let iter_list () = List.iter f l + and raliter () = CCRAL.iter ~f ral + and funvec_iter () = CCFun_vec.iter ~f vec + and sek_iter () = Sek.Persistent.iter Sek.forward f sek + in + B.throughputN time ~repeat + [ "List.iter", iter_list, () + ; "CCRAL.iter", raliter, () + ; "CCFun_vec.iter", funvec_iter, () + ; "Sek.Persistent.iter", sek_iter, () + ] + (* MAP *) let f_ x = x+1 @@ -81,10 +101,21 @@ module L = struct let l1 = CCList.(1 -- n) in let l2 = CCList.(n+1 -- 2*n) in let l3 = CCList.(2*n+1 -- 3*n) in - let arg = l1, l2, l3 in + let v1 = CCFun_vec.of_list l1 in + let v2 = CCFun_vec.of_list l2 in + let v3 = CCFun_vec.of_list l3 in + let s1 = Sek.Persistent.of_array 0 (Array.of_list l1) in + let s2 = Sek.Persistent.of_array 0 (Array.of_list l2) in + let s3 = Sek.Persistent.of_array 0 (Array.of_list l3) in + let bench_list l1 l2 l3 () = opaque_ignore (List.(append (append l1 l2) l3)) in + let bench_cclist l1 l2 l3 () = opaque_ignore (CCList.(append (append l1 l2) l3)) in + let bench_funvec l1 l2 l3 () = opaque_ignore (CCFun_vec.(append (append l1 l2) l3)) in + let bench_sek l1 l2 l3 () = opaque_ignore (Sek.Persistent.(concat (concat l1 l2) l3)) in B.throughputN time ~repeat - [ "CCList.append", append_ CCList.append, arg - ; "List.append", append_ List.append, arg + [ "CCList.append", bench_list l1 l2 l3, () + ; "List.append", bench_cclist l1 l2 l3, () + ; "CCFun_vec.append", bench_funvec v1 v2 v3, () + ; "Sek.concat", bench_sek s1 s2 s3, () ] (* FLATTEN *) @@ -115,16 +146,19 @@ module L = struct let v = CCFun_vec.of_list l in let bv = BatVect.of_list l in let map = List.fold_left (fun map i -> Int_map.add i i map) Int_map.empty l in + let sek = Sek.Persistent.of_array 0 (Array.of_list l) in let bench_list l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (List.nth l i)) done + for i = 0 to n-1 do opaque_ignore (List.nth l i) done and bench_map l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (Int_map.find i l)) done + for i = 0 to n-1 do opaque_ignore (Int_map.find i l) done and bench_ral l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (CCRAL.get_exn l i)) done + for i = 0 to n-1 do opaque_ignore (CCRAL.get_exn l i) done and bench_funvec l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (CCFun_vec.get_exn i l)) done + for i = 0 to n-1 do opaque_ignore (CCFun_vec.get_exn i l) done and bench_batvec l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (BatVect.get l i)) done + for i = 0 to n-1 do opaque_ignore (BatVect.get l i) done + and bench_sek l () = + for i = 0 to n-1 do opaque_ignore (Sek.Persistent.get l i) done in B.throughputN time ~repeat [ "List.nth", bench_list l, () @@ -132,6 +166,7 @@ module L = struct ; "RAL.get", bench_ral ral, () ; "funvec.get", bench_funvec v, () ; "batvec.get", bench_batvec bv, () + ; "Sek.Persistent.get", bench_sek sek, () ] let bench_set ?(time=2) n = @@ -139,23 +174,27 @@ module L = struct let ral = CCRAL.of_list l in (* let v = CCFun_vec.of_list l in *) let bv = BatVect.of_list l in + let sek = Sek.Persistent.of_array 0 (Array.of_list l) in let map = List.fold_left (fun map i -> Int_map.add i i map) Int_map.empty l in let bench_map l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (Int_map.add i (-i) l)) done + for i = 0 to n-1 do opaque_ignore (Int_map.add i (-i) l) done and bench_ral l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (CCRAL.set l i (-i))) done + for i = 0 to n-1 do opaque_ignore (CCRAL.set l i (-i)) done (* and bench_funvec l () = - for _i = 0 to n-1 do Sys.opaque_identity (ignore ((* TODO *))) done + for _i = 0 to n-1 do opaque_ignore ((* TODO *)) done *) and bench_batvec l () = - for i = 0 to n-1 do Sys.opaque_identity (ignore (BatVect.set l i (-i))) done + for i = 0 to n-1 do opaque_ignore (BatVect.set l i (-i)) done + and bench_sek l () = + for i = 0 to n-1 do opaque_ignore (Sek.Persistent.set l i (-i)) done in B.throughputN time ~repeat [ "Map.add", bench_map map, () ; "RAL.set", bench_ral ral, () (* ; "funvec.set", bench_funvec v, () *) ; "batvec.set", bench_batvec bv, () + ; "Sek.Persistent.set", bench_sek sek, () ] let bench_push ?(time=2) n = @@ -163,30 +202,70 @@ module L = struct let v = ref CCFun_vec.empty in let bv = ref BatVect.empty in let map = ref Int_map.empty in + let sek = ref (Sek.Persistent.create 0) in let bench_map l () = - for i = 0 to n-1 do Sys.opaque_identity (l := Int_map.add i i !l) done + for i = 0 to n-1 do l := Int_map.add i i !l done; opaque_ignore l (* and bench_ral l () = (* Note: Better implementation probably possible *) - for i = 0 to n-1 do Sys.opaque_identity (l := CCRAL.append !l (CCRAL.return i)) done + for i = 0 to n-1 do l := CCRAL.append !l (CCRAL.return i) done; opaque_ignore l *) and bench_funvec l () = - for i = 0 to n-1 do Sys.opaque_identity (l := CCFun_vec.push i !l) done + for i = 0 to n-1 do l := CCFun_vec.push i !l done; opaque_ignore l and bench_batvec l () = - for i = 0 to n-1 do Sys.opaque_identity (l := BatVect.append i !l) done + for i = 0 to n-1 do l := BatVect.append i !l done; opaque_ignore l + and bench_sek l () = + for i = 0 to n-1 do l := Sek.Persistent.push Sek.front !l i done; opaque_ignore l in B.throughputN time ~repeat [ "Map.add", bench_map map, () (* ; "RAL.append", bench_ral ral, () *) (* too slow *) + ; "Sek.Persistent.push", bench_sek sek, () ; "funvec.push", bench_funvec v, () ; "batvec.append", bench_batvec bv, () ] + let bench_pop ?(time=2) n = + let l = CCList.(0 -- (n - 1)) in + let ral = CCRAL.of_list l in + let v = CCFun_vec.of_list l in + let bv = BatVect.of_list l in + let map = List.fold_left (fun map i -> Int_map.add i i map) Int_map.empty l in + let sek = Sek.Persistent.of_array 0 (Array.of_list l) in + let bench_map l () = + let l = ref l in + for i = 0 to n-1 do l := Int_map.remove i !l done; opaque_ignore l + and bench_ral l () = + let l = ref l in + for _ = 0 to n-1 do l := CCRAL.tl !l done; opaque_ignore l + and bench_funvec l () = + let l = ref l in + for _ = 0 to n-1 do l := snd (CCFun_vec.pop_exn !l) done; opaque_ignore l + and bench_batvec l () = + let l = ref l in + for _ = 0 to n-1 do l := snd (BatVect.pop !l) done; opaque_ignore l + and bench_sek l () = + let l = ref l in + for _ = 0 to n-1 do l := snd (Sek.Persistent.pop Sek.back !l) done; opaque_ignore l + in + B.throughputN time ~repeat + [ "Map.remove", bench_map map, () + ; "RAL.tl", bench_ral ral, () + ; "funvec.pop", bench_funvec v, () + ; "batvec.pop", bench_batvec bv, () + ; "Sek.Persistent.pop", bench_sek sek, () + ] + (* MAIN *) let () = B.Tree.register ( "list" @>>> - [ "map" @>> + [ "iter" @>> + B.Tree.concat + [ app_int (bench_iter ~time:2) 100 + ; app_int (bench_iter ~time:2) 10_000 + ; app_int (bench_iter ~time:4) 100_000 ] + ; "map" @>> B.Tree.concat [ app_int (bench_map ~time:2) 100 ; app_int (bench_map ~time:2) 10_000 @@ -222,6 +301,11 @@ module L = struct [ app_int (bench_push ~time:2) 100 ; app_int (bench_push ~time:2) 10_000 ; app_int (bench_push ~time:4) 100_000] + ; "pop" @>> + B.Tree.concat + [ app_int (bench_pop ~time:2) 100 + ; app_int (bench_pop ~time:2) 10_000 + ; app_int (bench_pop ~time:4) 100_000] ] ) end @@ -804,11 +888,11 @@ module Iter_ = struct let bench_fold n = let iter () = Iter.fold (+) 0 Iter.(0 --n) in let gen () = Gen.fold (+) 0 Gen.(0 -- n) in - let klist () = OSeq.fold (+) 0 OSeq.(0 -- n) in + let oseq () = OSeq.fold (+) 0 OSeq.(0 -- n) in B.throughputN 3 ~repeat [ "iter.fold", iter, (); "gen.fold", gen, (); - "klist.fold", klist, (); + "oseq.fold", oseq, (); ] let bench_flat_map n = @@ -823,7 +907,7 @@ module Iter_ = struct ) in B.throughputN 3 ~repeat - [ "sequence.flat_map", iter, (); + [ "iter.flat_map", iter, (); "gen.flat_map", gen, (); "oseq.flat_map", oseq, (); ] @@ -851,11 +935,58 @@ module Iter_ = struct "oseq.iter", oseq, (); ] + let bench_to_array n = + let iter () = Iter.to_array (Iter.(1 -- n)) + and gen () = Gen.to_array (Gen.(1 -- n)) + and oseq () = OSeq.to_array (OSeq.(1 -- n)) in + B.throughputN 3 ~repeat + [ "iter.to_array", iter, (); + "gen.to_array", gen, (); + "oseq.to_array", oseq, (); + ] + + let bench_cons n = + let gen_cons x xs = + let saw_x = ref false in + fun () -> + if !saw_x then (saw_x := true; Some x) + else xs () + in + let xs = Array.init n Fun.id in + let iter () = ignore (Array.fold_right Iter.cons xs Iter.empty : int Iter.t) in + let gen () = ignore (Array.fold_right gen_cons xs Gen.empty : int Gen.t) in + let oseq () = ignore (Array.fold_right OSeq.cons xs OSeq.empty : int OSeq.t) in + B.throughputN 3 ~repeat + [ "iter.cons", iter, (); + "gen.cons", gen, (); + "oseq.cons", oseq, (); + ] + + let bench_cons_fold n = + let gen_cons x xs = + let saw_x = ref false in + fun () -> + if !saw_x then (saw_x := true; Some x) + else xs () + in + let xs = Array.init n Fun.id in + let iter () = Iter.fold (+) 0 (Array.fold_right Iter.cons xs Iter.empty) in + let gen () = Gen.fold (+) 0 (Array.fold_right gen_cons xs Gen.empty) in + let oseq () = OSeq.fold (+) 0 (Array.fold_right OSeq.cons xs OSeq.empty) in + B.throughputN 3 ~repeat + [ "iter.cons_fold", iter, (); + "gen.cons_fold", gen, (); + "oseq.cons_fold", oseq, (); + ] + let () = B.Tree.register ( "iter" @>>> [ "fold" @>> app_ints bench_fold [100; 1_000; 10_000; 1_000_000] ; "flat_map" @>> app_ints bench_flat_map [1_000; 10_000] ; "iter" @>> app_ints bench_iter [1_000; 10_000] + ; "to_array" @>> app_ints bench_to_array [1_000; 10_000] + ; "cons" @>> app_ints bench_cons [1_000; 10_000; 100_000] + ; "cons_fold" @>> app_ints bench_cons_fold [1_000; 10_000; 100_000] ]) end diff --git a/benchs/run_objsize.ml b/benchs/run_objsize.ml new file mode 100644 index 00000000..98e378d5 --- /dev/null +++ b/benchs/run_objsize.ml @@ -0,0 +1,57 @@ +(* module Deque = Core_kernel.Deque *) +module Int_map = Map.Make(CCInt) +module Int_set = Set.Make(CCInt) + +let dup = CCPair.dup +let id = CCFun.id +let ns n = List.init n CCFun.id +let iter_range n f = List.iter f (ns n) + +let gen_cons x xs = + let saw_x = ref false in + fun () -> + if !saw_x then (saw_x := true; Some x) + else xs () + +let front = Sek.front +let dummy = 0 + +let types = [ + "Stdlib.List", (fun n -> Obj.magic @@ ns n); + "Stdlib.Array", (fun n -> Obj.magic @@ Array.init n id); + "Stdlib.Hashtbl", (fun n -> Obj.magic @@ Hashtbl.of_seq (OSeq.init ~n dup)); + "Base.Hashtbl", (fun n -> Obj.magic @@ Base.Hashtbl.Poly.of_alist_exn (List.init n dup)); + "Stdlib.Map", (fun n -> Obj.magic @@ Int_map.of_seq (OSeq.init ~n dup)); + "Stdlib.Set", (fun n -> Obj.magic @@ Int_set.of_seq (OSeq.init ~n id)); + "CCFun_vec", (fun n -> Obj.magic @@ CCFun_vec.of_list (ns n)); + "CCRAL", (fun n -> Obj.magic @@ CCRAL.of_list (ns n)); + "BatVect", (fun n -> Obj.magic @@ BatVect.of_list (ns n)); + "Sek.Persistent", (fun n -> Obj.magic @@ List.fold_left (Sek.Persistent.push front) (Sek.Persistent.create dummy) (ns n)); + "Sek.Ephemeral", (fun n -> Obj.magic @@ let c = Sek.Ephemeral.create dummy in iter_range n (Sek.Ephemeral.push front c); c); + "CCVector", (fun n -> Obj.magic @@ let c = CCVector.create () in iter_range n (CCVector.push c); c); + (* "Core_kernel.Deque", (fun n -> Obj.magic @@ let c = Deque.create () in iter_range n (Deque.enqueue_back c); c); *) + "Base.Queue", (fun n -> Obj.magic @@ let c = Base.Queue.create () in iter_range n (Base.Queue.enqueue c); c); + "Stdlib.Queue", (fun n -> Obj.magic @@ Queue.of_seq (OSeq.init ~n id)); + "CCQueue", (fun n -> Obj.magic @@ CCDeque.of_list (ns n)); + "Iter", (fun n -> Obj.magic @@ List.fold_right Iter.cons (ns n) Iter.empty); + "Gen", (fun n -> Obj.magic @@ List.fold_right gen_cons (ns n) Gen.empty); + "Stdlib.Seq", (fun n -> Obj.magic @@ List.fold_right OSeq.cons (ns n) OSeq.empty); +] + +let () = + let sizes = [0; 1; 10; 100; 1000; 10000] in + Printf.printf "%-20s " ""; + sizes |> List.iter (fun n -> Printf.printf "%6d " n); + Printf.printf "\n"; + types + |> List.iter (fun (name, create) -> + Printf.printf "%-20s: " name; + sizes + |> List.iter (fun n -> + let obj = create n in + let size = Objsize.size_w obj in + (* let size = Obj.reachable_words (Obj.repr obj) in *) + Printf.printf "%6d " size + ); + Printf.printf "\n" + )