Skip to content

Commit 890e668

Browse files
add seed, add generate cas, fad
1 parent 63a414d commit 890e668

File tree

1 file changed

+91
-25
lines changed

1 file changed

+91
-25
lines changed

tests/gen_program.ml

Lines changed: 91 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ type config = {
88
thread_count : int;
99
generate_conditionals : bool;
1010
print_tests : bool;
11+
seed : int option;
1112
}
1213

1314
let print_config t =
@@ -16,29 +17,60 @@ let print_config t =
1617
Printf.printf "value_limit: %d\n" t.value_limit;
1718
Printf.printf "operations_count: %d\n" t.operations_count;
1819
Printf.printf "thread_count: %d\n" t.thread_count;
19-
Printf.printf "generate_conditionals: %b\n%!" t.generate_conditionals
20+
Printf.printf "generate_conditionals: %b\n%!" t.generate_conditionals;
21+
Printf.printf "seed: %s\n%!"
22+
(Option.map Int.to_string t.seed |> Option.value ~default:"<random>")
2023

2124
let var_name i = Char.chr (i + 97)
2225

2326
module Function = struct
24-
(* Arbitrary function from int to bool *)
25-
type t = IntSet.t
27+
type t =
28+
| Get of { true_on : IntSet.t }
29+
| CompareAndSet of { old_value : int; new_value : int }
30+
| FetchAndAdd of { delta : int; true_on : IntSet.t }
2631

27-
let rec gen value_limit =
28-
let true_set =
29-
List.init value_limit (fun i -> if Random.bool () then Some i else None)
30-
|> List.filter_map Fun.id |> IntSet.of_list
32+
let gen value_limit =
33+
let rec set_f () =
34+
let set =
35+
List.init value_limit (fun i -> if Random.bool () then Some i else None)
36+
|> List.filter_map Fun.id |> IntSet.of_list
37+
in
38+
let size = IntSet.cardinal set in
39+
if 0 < size && size < value_limit then set else set_f ()
3140
in
32-
let size = IntSet.cardinal true_set in
33-
if 0 < size && size < value_limit then true_set else gen value_limit
41+
match Random.int 6 with
42+
| 0 | 1 | 2 -> Get { true_on = set_f () }
43+
| 3 | 4 ->
44+
let old_value = Random.int value_limit in
45+
let new_value = Random.int value_limit in
46+
CompareAndSet { old_value; new_value }
47+
| 5 ->
48+
let delta = Random.int value_limit in
49+
FetchAndAdd { delta; true_on = set_f () }
50+
| _ -> assert false
3451

35-
let eval t input = IntSet.mem input t
52+
let eval variable = function
53+
| Get { true_on } -> IntSet.mem (Atomic.get variable) true_on
54+
| FetchAndAdd { delta; true_on } ->
55+
IntSet.mem (Atomic.fetch_and_add variable delta) true_on
56+
| CompareAndSet { old_value; new_value } ->
57+
Atomic.compare_and_set variable old_value new_value
3658

37-
let to_string t var_id =
38-
Printf.sprintf "IntSet.mem (Atomic.get %c) (IntSet.of_list [%s])"
39-
(var_name var_id)
40-
(IntSet.to_seq t |> List.of_seq |> List.map Int.to_string
41-
|> String.concat "; ")
59+
let to_string var_id = function
60+
| Get { true_on } ->
61+
Printf.sprintf "IntSet.mem (Atomic.get %c) (IntSet.of_list [%s])"
62+
(var_name var_id)
63+
(IntSet.to_seq true_on |> List.of_seq |> List.map Int.to_string
64+
|> String.concat "; ")
65+
| FetchAndAdd { delta; true_on } ->
66+
Printf.sprintf
67+
"IntSet.mem (Atomic.fetch_and_add %c %d) (IntSet.of_list [%s])"
68+
(var_name var_id) delta
69+
(IntSet.to_seq true_on |> List.of_seq |> List.map Int.to_string
70+
|> String.concat "; ")
71+
| CompareAndSet { old_value; new_value } ->
72+
Printf.sprintf "Atomic.compare_and_set %c %d %d" (var_name var_id)
73+
old_value new_value
4274
end
4375

4476
module Conditional = struct
@@ -57,8 +89,7 @@ module Conditional = struct
5789
match (vars, funcs) with
5890
| [], [] -> ( match operator with `And -> true | `Or -> false)
5991
| var :: vars_tl, func :: funcs_tl -> (
60-
let input = Atomic.get var in
61-
let output = Function.eval func input in
92+
let output = Function.eval var func in
6293
match (operator, output) with
6394
| `Or, true -> true
6495
| `And, false -> false
@@ -73,14 +104,21 @@ module Conditional = struct
73104
let to_string t ~var_ids =
74105
let operator_str = match t.operator with `Or -> " || " | `And -> " && " in
75106
List.combine t.functions var_ids
76-
|> List.map (fun (func, var_id) -> Function.to_string func var_id)
107+
|> List.map (fun (func, var_id) -> Function.to_string var_id func)
77108
|> String.concat operator_str
78109
end
79110

80111
module Step = struct
81112
type t =
82113
| Write of { var_id : int; new_value : int; next : t }
83114
| Read of { var_id : int; next : t }
115+
| CompareAndSet of {
116+
var_id : int;
117+
old_value : int;
118+
new_value : int;
119+
next : t;
120+
}
121+
| FetchAndAdd of { var_id : int; delta : int; next : t }
84122
| Conditional of {
85123
var_ids : int list;
86124
conditional : Conditional.t;
@@ -96,6 +134,15 @@ module Step = struct
96134
| Read { var_id; next } ->
97135
ignore (Atomic.get (CCVector.get globals var_id));
98136
run ~globals next
137+
| CompareAndSet { var_id; old_value; new_value; next } ->
138+
ignore
139+
(Atomic.compare_and_set
140+
(CCVector.get globals var_id)
141+
old_value new_value);
142+
run ~globals next
143+
| FetchAndAdd { var_id; delta; next } ->
144+
ignore (Atomic.fetch_and_add (CCVector.get globals var_id) delta);
145+
run ~globals next
99146
| Conditional { var_ids; conditional; on_true; next } ->
100147
let variables =
101148
List.map (fun var_id -> CCVector.get globals var_id) var_ids
@@ -113,6 +160,14 @@ module Step = struct
113160
| Read { var_id; next } ->
114161
Printf.printf "%sAtomic.get %c |> ignore;\n" indent (var_name var_id);
115162
print ~depth next
163+
| CompareAndSet { var_id; old_value; new_value; next } ->
164+
Printf.printf "%sAtomic.compare_and_set %c %d %d |> ignore;\n" indent
165+
(var_name var_id) old_value new_value;
166+
print ~depth next
167+
| FetchAndAdd { var_id; delta; next } ->
168+
Printf.printf "%sAtomic.fetch_and_add %c %d |> ignore;\n" indent
169+
(var_name var_id) delta;
170+
print ~depth next
116171
| Conditional { var_ids; conditional; on_true; next } ->
117172
let s = Conditional.to_string conditional ~var_ids in
118173
Printf.printf "%sif (%s) then (\n" indent s;
@@ -127,12 +182,19 @@ module Step = struct
127182
if fuel > 1 then gen ~config ~fuel:(fuel - 1) () else Noop
128183
in
129184
let maybe_conditionals = if config.generate_conditionals then 1 else 0 in
130-
match Random.int (2 + maybe_conditionals) with
131-
| 0 ->
185+
match Random.int (6 + maybe_conditionals) with
186+
| 0 | 1 ->
132187
let new_value = Random.int config.value_limit in
133188
Write { var_id; new_value; next = next fuel }
134-
| 1 -> Read { var_id; next = next fuel }
135-
| 2 ->
189+
| 2 | 3 -> Read { var_id; next = next fuel }
190+
| 4 ->
191+
let old_value = Random.int config.value_limit in
192+
let new_value = Random.int config.value_limit in
193+
CompareAndSet { var_id; old_value; new_value; next = next fuel }
194+
| 5 ->
195+
let delta = Random.int config.value_limit - (config.value_limit / 2) in
196+
FetchAndAdd { var_id; delta; next = next fuel }
197+
| 6 ->
136198
let func_count =
137199
min (max 1 fuel) (min config.globals_count (1 + Random.int 2))
138200
in
@@ -144,7 +206,7 @@ module Step = struct
144206
in
145207
let fuel_a, fuel_b =
146208
let tmp = Random.int (max (fuel - func_count) 1) in
147-
(tmp/2, tmp/2)
209+
(tmp / 2, tmp / 2)
148210
in
149211

150212
let on_true = gen ~config ~fuel:fuel_a () in
@@ -179,13 +241,14 @@ module Program = struct
179241
end
180242

181243
let run_random config () =
182-
Random.self_init ();
244+
(match config.seed with
245+
| None -> Random.self_init ()
246+
| Some seed -> Random.init seed);
183247
let globals = CCVector.of_list (List.init config.globals_count Fun.id) in
184248
let thread_f = Step.gen ~config ~fuel:config.operations_count in
185249
let threads = List.init config.thread_count (fun _ -> thread_f ()) in
186250
let program = ({ globals; threads } : Program.t) in
187251
if config.print_tests then Program.print program;
188-
189252
let random = Program.run ~impl:(`Random 100) program in
190253
let dpor = Program.run ~impl:`Dpor program in
191254
if not (Dscheck.Trace_tracker.subset random dpor) then (
@@ -212,6 +275,7 @@ let _ =
212275
let thread_count = ref 3 in
213276
let generate_conditionals = ref true in
214277
let print_tests = ref false in
278+
let seed = ref 0 in
215279
let speclist =
216280
[
217281
( "-test-count",
@@ -232,6 +296,7 @@ let _ =
232296
( "-generate-conditionals",
233297
Arg.Set generate_conditionals,
234298
"enable/disable generation of conditional statements" );
299+
("-seed", Arg.Set_int seed, "random seed for generation");
235300
]
236301
in
237302
Arg.parse speclist
@@ -247,6 +312,7 @@ let _ =
247312
thread_count = !thread_count;
248313
generate_conditionals = !generate_conditionals;
249314
print_tests = !print_tests;
315+
seed = (if !seed > 0 then Some !seed else None);
250316
}
251317
: config)
252318
in

0 commit comments

Comments
 (0)