|
| 1 | +open Multicore_bench |
| 2 | +module Ws_deque = Saturn_lockfree.Work_stealing_deque.M |
| 3 | + |
| 4 | +let run_one ~budgetf ?(n_domains = 1) () = |
| 5 | + let spawns = |
| 6 | + Array.init n_domains @@ fun _ -> ref 0 |> Multicore_magic.copy_as_padded |
| 7 | + in |
| 8 | + let deques = Array.init n_domains @@ fun _ -> Ws_deque.create () in |
| 9 | + let exit = ref false |> Multicore_magic.copy_as_padded in |
| 10 | + |
| 11 | + let next i = |
| 12 | + let i = i + 1 in |
| 13 | + if i = n_domains then 0 else i |
| 14 | + in |
| 15 | + |
| 16 | + let rec try_own own = |
| 17 | + match Ws_deque.pop (Array.unsafe_get deques own) with |
| 18 | + | work -> work |
| 19 | + | exception Exit -> try_steal own (next own) |
| 20 | + and try_steal own other = |
| 21 | + if other = own then raise_notrace Exit |
| 22 | + else |
| 23 | + match Ws_deque.steal (Array.unsafe_get deques other) with |
| 24 | + | work -> work |
| 25 | + | exception Exit -> try_steal own (next other) |
| 26 | + in |
| 27 | + let rec run own = |
| 28 | + match try_own own with |
| 29 | + | work -> |
| 30 | + work own; |
| 31 | + run own |
| 32 | + | exception Exit -> if not !exit then run own |
| 33 | + in |
| 34 | + |
| 35 | + let spawn own work = |
| 36 | + incr (Array.unsafe_get spawns own); |
| 37 | + let promise = ref (Obj.magic exit) in |
| 38 | + Ws_deque.push (Array.unsafe_get deques own) (fun own -> promise := work own); |
| 39 | + promise |
| 40 | + in |
| 41 | + let rec await own promise = |
| 42 | + let x = !promise in |
| 43 | + if x == Obj.magic exit then begin |
| 44 | + begin |
| 45 | + match try_own own with exception Exit -> () | work -> work own |
| 46 | + end; |
| 47 | + await own promise |
| 48 | + end |
| 49 | + else x |
| 50 | + in |
| 51 | + |
| 52 | + let rec fib n worker = |
| 53 | + if n < 2 then n |
| 54 | + else |
| 55 | + let n2 = spawn worker (fib (n - 2)) in |
| 56 | + let n1 = fib (n - 1) worker in |
| 57 | + await worker n2 + n1 |
| 58 | + in |
| 59 | + |
| 60 | + let rec bits n = if n <= 1 then 0 else 1 + bits (n lsr 1) in |
| 61 | + |
| 62 | + let init own = |
| 63 | + Array.unsafe_get spawns own := 0; |
| 64 | + if own = 0 then begin |
| 65 | + exit := false; |
| 66 | + let n = 29 + bits n_domains in |
| 67 | + spawn own (fun own -> |
| 68 | + fib n own |> ignore; |
| 69 | + exit := true) |
| 70 | + |> ignore |
| 71 | + end |
| 72 | + in |
| 73 | + let work own () = run own in |
| 74 | + |
| 75 | + let config = |
| 76 | + Printf.sprintf "%d worker%s" n_domains (if n_domains = 1 then "" else "s") |
| 77 | + in |
| 78 | + let times = Times.record ~budgetf ~n_domains ~init ~work () in |
| 79 | + let n = Array.fold_left (fun n c -> n + !c) 0 spawns in |
| 80 | + Util.thruput_metrics ~n ~singular:"spawn" ~config times |
| 81 | + |
| 82 | +let run_suite ~budgetf = |
| 83 | + [ 1; 2; 4; 8 ] |
| 84 | + |> List.concat_map @@ fun n_domains -> run_one ~budgetf ~n_domains () |
0 commit comments