|
1 |
| -open Saturn |
2 |
| - |
3 |
| -let workload num_elems num_threads add remove = |
4 |
| - let sl = Skiplist.create ~compare:Int.compare () in |
5 |
| - let elems = Array.init num_elems (fun _ -> Random.int 10000) in |
6 |
| - let push () = |
7 |
| - Domain.spawn (fun () -> |
8 |
| - let start_time = Unix.gettimeofday () in |
9 |
| - for i = 0 to (num_elems - 1) / num_threads do |
10 |
| - Domain.cpu_relax (); |
11 |
| - let prob = Random.float 1.0 in |
12 |
| - if prob < add then Skiplist.try_add sl (Random.int 10000) () |> ignore |
13 |
| - else if prob >= add && prob < add +. remove then |
14 |
| - Skiplist.try_remove sl (Random.int 10000) |> ignore |
15 |
| - else Skiplist.mem sl elems.(i) |> ignore |
16 |
| - done; |
17 |
| - start_time) |
| 1 | +open Multicore_bench |
| 2 | +module Skiplist = Saturn.Skiplist |
| 3 | + |
| 4 | +let run_one ~budgetf ~n_domains ?(n_ops = 20 * Util.iter_factor) |
| 5 | + ?(n_keys = 10000) ~percent_mem ?(percent_add = (100 - percent_mem + 1) / 2) |
| 6 | + ?(prepopulate = true) () = |
| 7 | + let percent_rem = 100 - (percent_mem + percent_add) in |
| 8 | + |
| 9 | + let limit_mem = percent_mem in |
| 10 | + let limit_add = percent_mem + percent_add in |
| 11 | + |
| 12 | + assert (0 <= limit_mem && limit_mem <= 100); |
| 13 | + assert (limit_mem <= limit_add && limit_add <= 100); |
| 14 | + |
| 15 | + let t = Skiplist.create ~compare:Int.compare () in |
| 16 | + if prepopulate then |
| 17 | + for _ = 1 to n_keys do |
| 18 | + let value = Random.bits () in |
| 19 | + let key = value mod n_keys in |
| 20 | + Skiplist.try_add t key value |> ignore |
| 21 | + done; |
| 22 | + |
| 23 | + let n_ops = (100 + percent_mem) * n_ops / 100 in |
| 24 | + let n_ops = n_ops * n_domains in |
| 25 | + |
| 26 | + let n_ops_todo = Atomic.make 0 |> Multicore_magic.copy_as_padded in |
| 27 | + |
| 28 | + let init _ = |
| 29 | + Atomic.set n_ops_todo n_ops; |
| 30 | + Random.State.make_self_init () |
18 | 31 | in
|
19 |
| - let threads = List.init num_threads (fun _ -> push ()) in |
20 |
| - let start_time_threads = |
21 |
| - List.map (fun domain -> Domain.join domain) threads |
| 32 | + let work _ state = |
| 33 | + let rec work () = |
| 34 | + let n = Util.alloc n_ops_todo in |
| 35 | + if n <> 0 then |
| 36 | + let rec loop n = |
| 37 | + if 0 < n then |
| 38 | + let value = Random.State.bits state in |
| 39 | + let op = (value asr 20) mod 100 in |
| 40 | + let key = value mod n_keys in |
| 41 | + if op < limit_mem then begin |
| 42 | + Skiplist.mem t key |> ignore; |
| 43 | + loop (n - 1) |
| 44 | + end |
| 45 | + else if op < limit_add then begin |
| 46 | + Skiplist.try_add t key value |> ignore; |
| 47 | + loop (n - 1) |
| 48 | + end |
| 49 | + else begin |
| 50 | + Skiplist.try_remove t key |> ignore; |
| 51 | + loop (n - 1) |
| 52 | + end |
| 53 | + else work () |
| 54 | + in |
| 55 | + loop n |
| 56 | + in |
| 57 | + work () |
22 | 58 | in
|
23 |
| - let end_time = Unix.gettimeofday () in |
24 |
| - let time_diff = end_time -. List.nth start_time_threads 0 in |
25 |
| - time_diff |
26 |
| - |
27 |
| -(* A write heavy workload with threads with 50% adds and 50% removes. *) |
28 |
| -let write_heavy_workload num_elems num_threads = |
29 |
| - workload num_elems num_threads 0.5 0.5 |
30 |
| - |
31 |
| -(* A regular workload with 90% reads, 9% adds and 1% removes. *) |
32 |
| -let read_heavy_workload num_elems num_threads = |
33 |
| - workload num_elems num_threads 0.09 0.01 |
34 |
| - |
35 |
| -let moderate_heavy_workload num_elems num_threads = |
36 |
| - workload num_elems num_threads 0.2 0.1 |
37 |
| - |
38 |
| -let balanced_heavy_workload num_elems num_threads = |
39 |
| - workload num_elems num_threads 0.3 0.2 |
40 |
| - |
41 |
| -let bench ~workload_type ~num_elems ~num_threads () = |
42 |
| - let workload = |
43 |
| - if workload_type = "read_heavy" then read_heavy_workload |
44 |
| - else if workload_type = "moderate_heavy" then moderate_heavy_workload |
45 |
| - else if workload_type = "balanced_heavy" then balanced_heavy_workload |
46 |
| - else write_heavy_workload |
| 59 | + |
| 60 | + let config = |
| 61 | + Printf.sprintf "%d workers, %d%% mem %d%% add %d%% rem" n_domains |
| 62 | + percent_mem percent_add percent_rem |
47 | 63 | in
|
48 |
| - let results = ref [] in |
49 |
| - for i = 1 to 10 do |
50 |
| - let time = workload num_elems num_threads in |
51 |
| - if i > 1 then results := time :: !results |
52 |
| - done; |
53 |
| - let results = List.sort Float.compare !results in |
54 |
| - let median_time = List.nth results 4 in |
55 |
| - let median_throughput = Float.of_int num_elems /. median_time in |
56 |
| - Benchmark_result.create_generic ~median_time ~median_throughput |
57 |
| - ("atomic_skiplist_" ^ workload_type) |
| 64 | + Times.record ~budgetf ~n_domains ~init ~work () |
| 65 | + |> Times.to_thruput_metrics ~n:n_ops ~singular:"operation" ~config |
| 66 | + |
| 67 | +let run_suite ~budgetf = |
| 68 | + Util.cross [ 10; 50; 90 ] [ 1; 2; 4 ] |
| 69 | + |> List.concat_map @@ fun (percent_mem, n_domains) -> |
| 70 | + run_one ~budgetf ~n_domains ~percent_mem () |
0 commit comments