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