|
| 1 | +open Lockfree.Mpmc_relaxed_queue |
| 2 | + |
| 3 | +let num_of_elements = ref 500_000 |
| 4 | +let num_of_pushers = ref 4 |
| 5 | +let num_of_takers = ref 4 |
| 6 | +let num_of_iterations = ref 10 |
| 7 | +let use_cas_intf = ref false |
| 8 | +let pop = ref Not_lockfree.pop |
| 9 | +let push = ref Not_lockfree.push |
| 10 | + |
| 11 | +let taker queue num_of_elements () = |
| 12 | + let i = ref 0 in |
| 13 | + while !i < num_of_elements do |
| 14 | + if Option.is_some (!pop queue) then i := !i + 1 |
| 15 | + done |
| 16 | + |
| 17 | +let pusher queue num_of_elements () = |
| 18 | + let i = ref 0 in |
| 19 | + while !i < num_of_elements do |
| 20 | + if !push queue !i then i := !i + 1 |
| 21 | + done |
| 22 | + |
| 23 | +let create_output ~time_median ~throughput_median ~throughput_stddev = |
| 24 | + let time = |
| 25 | + ({ |
| 26 | + name = "time"; |
| 27 | + value = `Numeric time_median; |
| 28 | + units = "s"; |
| 29 | + description = "median time"; |
| 30 | + } |
| 31 | + : Benchmark_result.Metric.t) |
| 32 | + in |
| 33 | + let throughput = |
| 34 | + ({ |
| 35 | + name = "throughput"; |
| 36 | + value = `Numeric throughput_median; |
| 37 | + units = "item/s"; |
| 38 | + description = "median throughput"; |
| 39 | + } |
| 40 | + : Benchmark_result.Metric.t) |
| 41 | + in |
| 42 | + let throughput_stddev = |
| 43 | + ({ |
| 44 | + name = "throughput-stddev"; |
| 45 | + value = `Numeric throughput_stddev; |
| 46 | + units = "item/s"; |
| 47 | + description = "stddev throughput"; |
| 48 | + } |
| 49 | + : Benchmark_result.Metric.t) |
| 50 | + in |
| 51 | + let metrics = [ time; throughput; throughput_stddev ] in |
| 52 | + let name = |
| 53 | + Printf.sprintf "mpmc-queue-pushers:%d,takers:%d,use-cas:%b" !num_of_pushers |
| 54 | + !num_of_takers !use_cas_intf |
| 55 | + in |
| 56 | + ({ name; metrics } : Benchmark_result.t) |
| 57 | + |
| 58 | +let run_bench () = |
| 59 | + if !use_cas_intf then ( |
| 60 | + push := Lockfree.Mpmc_relaxed_queue.Not_lockfree.CAS_interface.push; |
| 61 | + pop := Lockfree.Mpmc_relaxed_queue.Not_lockfree.CAS_interface.pop); |
| 62 | + let queue = create ~size_exponent:10 () in |
| 63 | + let orchestrator = |
| 64 | + Orchestrator.init |
| 65 | + ~total_domains:(!num_of_takers + !num_of_pushers) |
| 66 | + ~rounds:!num_of_iterations |
| 67 | + in |
| 68 | + (* define function to start domains *) |
| 69 | + let start_n_domains n f = |
| 70 | + assert (!num_of_elements mod n == 0); |
| 71 | + let items_per_pusher = !num_of_elements / n in |
| 72 | + List.init n (fun _ -> |
| 73 | + Domain.spawn (fun () -> |
| 74 | + Orchestrator.worker orchestrator (f queue items_per_pusher))) |
| 75 | + in |
| 76 | + (* start domains *) |
| 77 | + let domains = |
| 78 | + let takers = start_n_domains !num_of_takers taker in |
| 79 | + let pushers = start_n_domains !num_of_pushers pusher in |
| 80 | + Sys.opaque_identity (pushers @ takers) |
| 81 | + in |
| 82 | + (* run test *) |
| 83 | + let times = Orchestrator.run orchestrator in |
| 84 | + List.iter Domain.join domains; |
| 85 | + let time_median = Stats.median times in |
| 86 | + let throughputs = |
| 87 | + List.map (fun time -> Int.to_float !num_of_elements /. time) times |
| 88 | + in |
| 89 | + let throughput_median = Stats.median throughputs in |
| 90 | + let throughput_stddev = Stats.stddev throughputs in |
| 91 | + create_output ~time_median ~throughput_median ~throughput_stddev |
| 92 | + |
| 93 | +let bench ?takers ?pushers ?use_cas ?iterations ?elements () = |
| 94 | + num_of_takers := Option.value takers ~default:!num_of_takers; |
| 95 | + num_of_pushers := Option.value pushers ~default:!num_of_pushers; |
| 96 | + use_cas_intf := Option.value use_cas ~default:!use_cas_intf; |
| 97 | + num_of_iterations := Option.value iterations ~default:!num_of_iterations; |
| 98 | + num_of_elements := Option.value elements ~default:!num_of_elements; |
| 99 | + run_bench () |
0 commit comments