File: bench_hashtbl.ml

package info (click to toggle)
ocaml-multicore-bench 0.1.7-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 320 kB
  • sloc: ml: 1,476; sh: 60; makefile: 6
file content (122 lines) | stat: -rw-r--r-- 3,625 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
open Multicore_bench

module Int = struct
  include Int

  let hash = Fun.id
end

module Htbl = Hashtbl.Make (Int)

let mutex = Mutex.create ()

let run_one ~budgetf ~n_domains ~use_mutex ?(n_keys = 1000) ~percent_mem
    ?(percent_add = (100 - percent_mem + 1) / 2) ?(prepopulate = true) () =
  let limit_mem = percent_mem in
  let limit_add = percent_mem + percent_add in

  assert (0 <= limit_mem && limit_mem <= 100);
  assert (limit_mem <= limit_add && limit_add <= 100);

  let t = Htbl.create n_keys in

  if prepopulate then
    for _ = 1 to n_keys do
      let value = Random.bits () in
      let key = value mod n_keys in
      Htbl.replace t key value
    done;

  let n_ops = (if use_mutex then 100 else 400) * Util.iter_factor in
  let n_ops = (100 + percent_mem) * n_ops / 100 in

  let n_ops_todo = Countdown.create ~n_domains () in

  let init _ =
    Countdown.non_atomic_set n_ops_todo n_ops;
    Random.State.make_self_init ()
  in
  let work_no_mutex domain_index state =
    let rec work () =
      let n = Countdown.alloc n_ops_todo ~domain_index ~batch:100 in
      if n <> 0 then
        let rec loop n =
          if 0 < n then
            let value = Random.State.bits state in
            let op = (value asr 20) mod 100 in
            let key = value mod n_keys in
            if op < percent_mem then begin
              begin
                match Htbl.find t key with _ -> () | exception Not_found -> ()
              end;
              loop (n - 1)
            end
            else if op < limit_add then begin
              Htbl.replace t key value;
              loop (n - 1)
            end
            else begin
              Htbl.remove t key;
              loop (n - 1)
            end
          else work ()
        in
        loop n
    in
    work ()
  in
  let work_mutex domain_index state =
    let rec work () =
      let n = Countdown.alloc n_ops_todo ~domain_index ~batch:100 in
      if n <> 0 then
        let rec loop n =
          if 0 < n then
            let value = Random.State.bits state in
            let op = (value asr 20) mod 100 in
            let key = value mod n_keys in
            if op < percent_mem then begin
              Mutex.lock mutex;
              begin
                match Htbl.find t key with _ -> () | exception Not_found -> ()
              end;
              Mutex.unlock mutex;
              loop (n - 1)
            end
            else if op < limit_add then begin
              Mutex.lock mutex;
              Htbl.replace t key value;
              Mutex.unlock mutex;
              loop (n - 1)
            end
            else begin
              Mutex.lock mutex;
              Htbl.remove t key;
              Mutex.unlock mutex;
              loop (n - 1)
            end
          else work ()
        in
        loop n
    in
    work ()
  in

  let config =
    let percent_mem = Printf.sprintf "%d%% reads" percent_mem in
    if use_mutex then
      Printf.sprintf "%d worker%s, %s" n_domains
        (if n_domains = 1 then "" else "s")
        percent_mem
    else Printf.sprintf "one domain, %s" percent_mem
  in
  let work = if use_mutex then work_mutex else work_no_mutex in
  Times.record ~budgetf ~n_domains ~init ~work ()
  |> Times.to_thruput_metrics ~n:n_ops ~singular:"operation" ~config

let run_suite ~budgetf =
  ([ 10; 50; 90 ]
  |> List.concat_map @@ fun percent_mem ->
     run_one ~budgetf ~n_domains:1 ~use_mutex:false ~percent_mem ())
  @ (Util.cross [ 10; 50; 90 ] [ 1; 2; 4; 8 ]
    |> List.concat_map @@ fun (percent_mem, n_domains) ->
       run_one ~budgetf ~n_domains ~use_mutex:true ~percent_mem ())