Skip to content

Commit 61838c0

Browse files
committed
Add benchmark of operations using thread-atomic refs
1 parent 305066b commit 61838c0

File tree

2 files changed

+84
-0
lines changed

2 files changed

+84
-0
lines changed

bench/bench_ref.ml

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
open Bench
2+
3+
module Ref = struct
4+
type 'a t = 'a ref
5+
6+
let make = ref
7+
let get = ( ! )
8+
let[@poll error] [@inline never] incr x = x := !x + 1
9+
10+
let[@poll error] [@inline never] compare_and_set x before after =
11+
!x == before
12+
&& begin
13+
x := after;
14+
true
15+
end
16+
17+
let[@poll error] [@inline never] exchange x after =
18+
let before = !x in
19+
x := after;
20+
before
21+
22+
let rec modify ?(backoff = Backoff.default) x f =
23+
let before = get x in
24+
let after = f before in
25+
if not (compare_and_set x before after) then
26+
modify ~backoff:(Backoff.once backoff) x f
27+
end
28+
29+
type t = Op : string * int * 'a * ('a Ref.t -> unit) * ('a Ref.t -> unit) -> t
30+
31+
let run_one ~budgetf ?(n_iter = 500 * Util.iter_factor)
32+
(Op (name, extra, value, op1, op2)) =
33+
let n_iter = n_iter * extra in
34+
35+
let loc = Ref.make value in
36+
37+
let init _ = () in
38+
let work _ () =
39+
let rec loop i =
40+
if i > 0 then begin
41+
op1 loc;
42+
op2 loc;
43+
loop (i - 2)
44+
end
45+
in
46+
loop n_iter
47+
in
48+
49+
let times = Times.record ~n_domains:1 ~budgetf ~init ~work () in
50+
51+
List.concat
52+
[
53+
Stats.of_times times
54+
|> Stats.scale (1_000_000_000.0 /. Float.of_int n_iter)
55+
|> Stats.to_json
56+
~name:(Printf.sprintf "time per op/%s" name)
57+
~description:"Time to perform a single op" ~units:"ns";
58+
Times.invert times |> Stats.of_times
59+
|> Stats.scale (Float.of_int n_iter /. 1_000_000.0)
60+
|> Stats.to_json
61+
~name:(Printf.sprintf "ops over time/%s" name)
62+
~description:"Number of operations performed over time" ~units:"M/s";
63+
]
64+
65+
let run_suite ~budgetf =
66+
[
67+
(let get x = Ref.get x |> ignore in
68+
Op ("get", 10, 42, get, get));
69+
(let incr x = Ref.incr x in
70+
Op ("incr", 1, 0, incr, incr));
71+
(let push x = Ref.modify x (fun xs -> 101 :: xs)
72+
and pop x = Ref.modify x (function [] -> [] | _ :: xs -> xs) in
73+
Op ("push & pop", 2, [], push, pop));
74+
(let cas01 x = Ref.compare_and_set x 0 1 |> ignore
75+
and cas10 x = Ref.compare_and_set x 1 0 |> ignore in
76+
Op ("cas int", 1, 0, cas01, cas10));
77+
(let xchg1 x = Ref.exchange x 1 |> ignore
78+
and xchg0 x = Ref.exchange x 0 |> ignore in
79+
Op ("xchg int", 1, 0, xchg1, xchg0));
80+
(let swap x = Ref.modify x (fun (x, y) -> (y, x)) in
81+
Op ("swap", 2, (4, 2), swap, swap));
82+
]
83+
|> List.concat_map @@ run_one ~budgetf

bench/main.ml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
let benchmarks =
22
[
3+
("Ref with [@poll error]", Bench_ref.run_suite);
34
("Atomic", Bench_atomic.run_suite);
45
("Kcas Loc", Bench_loc.run_suite);
56
("Kcas Xt", Bench_xt.run_suite);

0 commit comments

Comments
 (0)