File: bench.ml

package info (click to toggle)
ppx-hash 0.17.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 316 kB
  • sloc: ml: 1,961; ansic: 180; makefile: 14; sh: 11
file content (257 lines) | stat: -rw-r--r-- 6,082 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
open Core
module Hash = Base.Hash

module Bench (Hash : Hash.S) = struct
  let%bench_module ("" [@name_suffix Hash.description]) =
    (module struct
      module Ppx_hash_lib = struct
        module Std = struct
          module Hash = Base.Hash.F (Hash)
        end
      end

      module Hash = Ppx_hash_lib.Std.Hash
      open Hash.Builtin

      type a = int [@@deriving hash]
      type b = a * float [@@deriving hash]

      type c =
        | Foo
        | Bar
        | Baz of a * b * c
      [@@deriving hash]

      type d = (int * string) list [@@deriving hash]

      let hash_fold_d : Ppx_hash_lib.Std.Hash.state -> d -> Ppx_hash_lib.Std.Hash.state =
        (*fun hsv  ->
          fun arg  ->*)
        hash_fold_list (fun hsv arg ->
          let e0, e1 = arg in
          hash_fold_string (hash_fold_int hsv e0) e1)
      ;;

      (*hsv
        arg*)

      let _ = Foo, Bar
      let a = 32
      let b = 32, 42.0
      let c1 = Foo
      let c2 = Baz (a, b, c1)
      let rec cn n = if n <= 1 then c1 else Baz (n, (n, float_of_int n), cn (n - 1))
      let c10 = cn 10
      let c100 = cn 100

      let rec dn n =
        if n <= 0
        then []
        else
          (n, String.init n ~f:(fun i -> if i mod 2 = 0 then 'j' else 's')) :: dn (n - 1)
      ;;

      let d10 = dn 10
      let d100 = dn 100
      let%bench "hash_init" = Hash.alloc ()
      let state = Hash.alloc ()
      let run folder x = ignore (Hash.get_hash_value (folder (Hash.reset state) x))
      let%bench "hash a" = run hash_fold_a a
      let%bench "hash b" = run hash_fold_b b
      let%bench "hash c__1" = run hash_fold_c c1
      let%bench "hash c__2" = run hash_fold_c c2
      let%bench "hash c_10" = run hash_fold_c c10
      let%bench "hash c100" = run hash_fold_c c100
      let%bench "hash d_10" = run hash_fold_d d10
      let%bench "hash d100" = run hash_fold_d d100
      let _ = c2, c10, c100, d10, d100

      type enum =
        | A
        | B
        | C
        | D
        | E
        | F
        | G
        | H
      [@@deriving hash]

      let enum_list = [ A; B; C; D; E; F; G; H ]
      let%bench "hash enum" = run (hash_fold_list hash_fold_enum) enum_list
    end)
  ;;
end

module Bench_hashtbl_hash = struct
  (* This module is a verbatim copy of the above, except that we use Hashtbl.hash every
     where. *)
  let%bench_module "Hashtbl.hash" =
    (module struct
      type a = int
      type b = a * float

      type c =
        | Foo
        | Bar
        | Baz of a * b * c

      type d = (int * string) list

      let hash_a = Hashtbl.hash
      let hash_b = Hashtbl.hash
      let hash_c = Hashtbl.hash
      let hash_d = Hashtbl.hash
      let _ = Foo, Bar
      let a = 32
      let b = 32, 42.0
      let c1 = Foo
      let c2 = Baz (a, b, c1)
      let rec cn n = if n <= 1 then c1 else Baz (n, (n, float_of_int n), cn (n - 1))
      let c10 = cn 10
      let c100 = cn 100

      let rec dn n : d =
        if n <= 0
        then []
        else
          (n, String.init n ~f:(fun i -> if i mod 2 = 0 then 'j' else 's')) :: dn (n - 1)
      ;;

      let d10 = dn 10
      let d100 = dn 100
      let run f x = ignore (f x)
      let%bench "hash a" = run hash_a a
      let%bench "hash b" = run hash_b b
      let%bench "hash c__1" = run hash_c c1
      let%bench "hash c__2" = run hash_c c2
      let%bench "hash c_10" = run hash_c c10
      let%bench "hash c100" = run hash_c c100
      let%bench "hash d_10" = run hash_d d10
      let%bench "hash d100" = run hash_d d100
      let _ = c2, c10, c100, d10, d100
    end)
  ;;
end

module Traverse_only : Hash.S = struct
  let description = "Traverse_only"

  type hash_value = int
  type state = unit
  type seed = unit

  let alloc () = ()
  let reset ?seed:_ () = ()
  let get_hash_value () = 0
  let fold_int () _ = ()
  let fold_int64 () _ = ()
  let fold_float () _ = ()
  let fold_string () _ = ()

  module For_tests = struct
    let compare_state _ _ = 0
    let state_to_string () = "()"
  end
end

(* This module enforces the rules described in ../hash_intf.ml *)
module Check_initialized_correctly : Hash.S = struct
  let description = "Check_initialized_correctly"

  type hash_value = int

  type state =
    { me : int
    ; valid : int ref
    }

  type seed = unit

  let next_id =
    let x = ref 0 in
    fun () ->
      incr x;
      !x
  ;;

  let alloc () = { me = next_id (); valid = ref (next_id ()) }

  let reset ?seed:_ t =
    let me = next_id () in
    t.valid := me;
    { me; valid = t.valid }
  ;;

  let assert_valid t = assert (t.me = !(t.valid))

  let change t =
    assert_valid t;
    let me = next_id () in
    t.valid := me;
    { me; valid = t.valid }
  ;;

  let get_hash_value t =
    let _ = change t in
    0
  ;;

  let fold_int t _ = change t
  let fold_int64 t _ = change t
  let fold_float t _ = change t
  let fold_string t _ = change t

  module For_tests = struct
    let compare_state a b =
      assert_valid a;
      assert_valid b;
      0
    ;;

    let state_to_string _ = "<state>"
  end

  let should_fail f =
    match f () with
    | exception _e -> ()
    | _ -> failwith "should have failed"
  ;;

  let%test_unit _ =
    should_fail (fun () ->
      let x = alloc () in
      let y = reset x in
      ignore (fold_int y 1);
      fold_int y 2)
  ;;

  let%test_unit _ =
    should_fail (fun () ->
      let x = alloc () in
      let y = reset x in
      let y2 = reset x in
      ignore (fold_int y 1);
      ignore (fold_int y2 1))
  ;;

  let%test_unit _ =
    should_fail (fun () ->
      let x = alloc () in
      ignore (fold_int x 1))
  ;;

  let%test_unit _ =
    should_fail (fun () ->
      let x = alloc () in
      let x = reset x in
      ignore (get_hash_value x);
      ignore (fold_int x 1))
  ;;
end

let%bench_module "" = (module Bench (Traverse_only))
let%bench_module "" = (module Bench (Check_initialized_correctly))
let%bench_module "" = (module Bench (Base.Hash))
let%bench_module "" = (module Bench (Siphash_lib.Siphash))
let%bench_module "" = (module Bench (Ppx_hash_runtime_test.Perfect_hash))