Skip to content

Commit

Permalink
benchmark various implementations of Bench.to_seq discussed in ocaml-…
Browse files Browse the repository at this point in the history
…batteries-team#1006

Results on my machine:

    enumeration (89.71 us) is 77.5% faster than
    batseq (399.39 us) which is 3.8% faster than
    too strict (415.29 us) which is probably (alpha=40.06%) same speed as
    simple (416.74 us)
    Saving times to times.flat

This suggests that using an enumeration indeed provides a large
performance advantage over the simple approach.
  • Loading branch information
gasche committed Jan 30, 2021
1 parent 6cadc72 commit d7bbb65
Show file tree
Hide file tree
Showing 2 changed files with 81 additions and 0 deletions.
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ BENCH_TARGETS += benchsuite/lines_of.native
BENCH_TARGETS += benchsuite/bitset.native
BENCH_TARGETS += benchsuite/bench_map.native
BENCH_TARGETS += benchsuite/bench_nreplace.native
BENCH_TARGETS += benchsuite/bench_set_to_seq.native
TEST_TARGET = test-byte

ifeq ($(BATTERIES_NATIVE_SHLIB), yes)
Expand Down
80 changes: 80 additions & 0 deletions benchsuite/bench_set_to_seq.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
(* cd .. && ocamlbuild -use-ocamlfind benchsuite/bench_set_to_seq.native && _build/benchsuite/bench_set_to_seq.native *)

(* The purpose of this test is to compare different implementation of
BatSet.to_seq. *)

(* the type BatSet.t is abstract,
we break the abstraction boundary locally to implement our versions outside the module. *)
type 'a set =
| Empty
| Node of 'a set * 'a * 'a set * int
external hide : 'a set -> 'a BatSet.t = "%identity"
external reveal : 'a BatSet.t -> 'a set = "%identity"


module TooStrict = struct
let rec to_seq m =
match m with
| Empty -> BatSeq.nil
| Node(l, v, r, _) ->
BatSeq.append (to_seq l) (fun () -> BatSeq.Cons (v, to_seq r))

let to_seq s = to_seq (reveal s)
end

module Simple = struct
let rec to_seq m =
fun () ->
match m with
| Empty -> BatSeq.Nil
| Node(l, v, r, _) ->
BatSeq.append (to_seq l) (fun () -> BatSeq.Cons (v, to_seq r)) ()

let to_seq s = to_seq (reveal s)
end

module Enumeration = struct
type 'a iter = E | C of 'a * 'a set * 'a iter

let rec cons_iter s t = match s with
| Empty -> t
| Node (l, e, r, _) -> cons_iter l (C (e, r, t))

let to_seq s =
let rec to_seq iter () =
match iter with
| E -> BatSeq.Nil
| C (e, r, t) ->
BatSeq.Cons (e, to_seq (cons_iter r t))
in
to_seq (cons_iter s E)

let to_seq s = to_seq (reveal s)
end

let test_input =
let s = ref BatSet.empty in
for i = 0 to 9999 do
s := BatSet.add i !s;
done;
!s

let test to_seq =
test_input
|> to_seq
|> BatSeq.length

let () =
assert (test TooStrict.to_seq = test BatSet.to_seq);
assert (test Simple.to_seq = test BatSet.to_seq);
assert (test Enumeration.to_seq = test BatSet.to_seq);
()

let () =
let repeat f n = for i = 1 to n do ignore (f ()) done in
Bench.bench_n [
"too strict", repeat (fun () -> test TooStrict.to_seq);
"simple", repeat (fun () -> test Simple.to_seq);
"enumeration", repeat (fun () -> test Enumeration.to_seq);
"batseq", repeat (fun () -> test BatSet.to_seq);
] |> Bench.run_outputs

0 comments on commit d7bbb65

Please sign in to comment.