Skip to content

Commit ba085b9

Browse files
better human-readable execution history output
1 parent 8a518dd commit ba085b9

File tree

5 files changed

+85
-22
lines changed

5 files changed

+85
-22
lines changed

.ocamlformat

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,2 @@
11
profile = default
2-
version = 0.24.1
2+
version = 0.25.1

src/tracedAtomic.ml

Lines changed: 56 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ type _ Effect.t +=
1212
| FetchAndAdd : (int t * int) -> int Effect.t
1313

1414
module IntSet = Set.Make (Int)
15-
1615
module IntMap = Map.Make (Int)
1716

1817
let _string_of_set s = IntSet.fold (fun y x -> string_of_int y ^ "," ^ x) s ""
@@ -193,11 +192,52 @@ type state_cell = {
193192
mutable backtrack : IntSet.t;
194193
}
195194

196-
let num_runs = ref 0
195+
let num_states = ref 0
196+
let num_interleavings = ref 0
197197

198198
(* we stash the current state in case a check fails and we need to log it *)
199199
let schedule_for_checks = ref []
200200

201+
let var_name i =
202+
match i with
203+
| None -> ""
204+
| Some i ->
205+
let c = Char.chr (i + 96) in
206+
Printf.sprintf "%c" c
207+
208+
let print_execution_sequence () =
209+
let highest_proc =
210+
List.fold_left
211+
(fun highest (curr_proc, _, _) ->
212+
if curr_proc > highest then curr_proc else highest)
213+
(-1) !schedule_for_checks
214+
in
215+
216+
let bar =
217+
List.init ((highest_proc * 20) + 20) (fun _ -> "-") |> String.concat ""
218+
in
219+
Printf.printf "\nsequence %d\n" !num_interleavings;
220+
Printf.printf "%s\n" bar;
221+
List.init (highest_proc + 1) (fun proc -> Printf.printf "P%d\t\t\t" proc)
222+
|> ignore;
223+
Printf.printf "\n%s\n" bar;
224+
225+
List.iter
226+
(fun s ->
227+
match s with
228+
| last_run_proc, last_run_op, last_run_ptr ->
229+
let last_run_ptr = var_name last_run_ptr in
230+
let tabs =
231+
List.init last_run_proc (fun _ -> "\t\t\t") |> String.concat ""
232+
in
233+
Printf.printf "%s%s %s\n" tabs
234+
(atomic_op_str last_run_op)
235+
last_run_ptr)
236+
!schedule_for_checks;
237+
Printf.printf "%s\n%!" bar
238+
239+
let print_max_exec_seq = ref false
240+
201241
let do_run init_func init_schedule =
202242
init_func ();
203243
(*set up run *)
@@ -214,6 +254,8 @@ let do_run init_func init_schedule =
214254
| [] ->
215255
if !finished_processes == num_processes then (
216256
tracing := false;
257+
num_interleavings := !num_interleavings + 1;
258+
if !print_max_exec_seq then print_execution_sequence ();
217259
!final_func ();
218260
tracing := true)
219261
| (process_id_to_run, next_op, next_ptr) :: schedule ->
@@ -231,8 +273,8 @@ let do_run init_func init_schedule =
231273
run_trace init_schedule ();
232274
finished_processes := 0;
233275
tracing := false;
234-
num_runs := !num_runs + 1;
235-
if !num_runs mod 1000 == 0 then Printf.printf "run: %d\n%!" !num_runs;
276+
num_states := !num_states + 1;
277+
if !num_states mod 1000 == 0 then Printf.printf "run: %d\n%!" !num_states;
236278
let procs =
237279
CCVector.mapi
238280
(fun i p -> { proc_id = i; op = p.next_op; obj_ptr = p.next_repr })
@@ -304,31 +346,26 @@ let check f =
304346
let tracing_at_start = !tracing in
305347
tracing := false;
306348
if not (f ()) then (
307-
Printf.printf "Found assertion violation at run %d:\n" !num_runs;
308-
List.iter
309-
(fun s ->
310-
match s with
311-
| last_run_proc, last_run_op, last_run_ptr ->
312-
let last_run_ptr =
313-
Option.map string_of_int last_run_ptr |> Option.value ~default:""
314-
in
315-
Printf.printf "Process %d: %s %s\n" last_run_proc
316-
(atomic_op_str last_run_op)
317-
last_run_ptr)
318-
!schedule_for_checks;
349+
Printf.printf "Found assertion violation at run %d:\n" !num_interleavings;
350+
print_execution_sequence ();
319351
assert false);
320352
tracing := tracing_at_start
321353

322354
let reset_state () =
323355
finished_processes := 0;
324356
atomics_counter := 1;
325-
num_runs := 0;
357+
num_states := 0;
358+
num_interleavings := 0;
326359
schedule_for_checks := [];
327360
CCVector.clear processes
328361

329-
let trace func =
362+
let trace ?(print_interleavings = false) func =
363+
print_max_exec_seq := print_interleavings;
330364
reset_state ();
331365
let empty_state = do_run func [ (0, Start, None) ] :: [] in
332366
let empty_clock = IntMap.empty in
333367
let empty_last_access = IntMap.empty in
334-
explore func empty_state empty_clock empty_last_access
368+
explore func empty_state empty_clock empty_last_access;
369+
if print_interleavings then
370+
Printf.printf "\nexplored %d maximal interleavings and %d states\n"
371+
!num_interleavings !num_states

src/tracedAtomic.mli

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,11 @@ val incr : int t -> unit
4646
val decr : int t -> unit
4747
(** [decr r] atomically decrements the value of [r] by [1]. *)
4848

49-
val trace : (unit -> unit) -> unit
50-
(** start the simulation trace *)
49+
val trace : ?print_interleavings:bool -> (unit -> unit) -> unit
50+
(** start the simulation trace
51+
52+
print_interleavings - print out explored interleavings
53+
*)
5154

5255
val spawn : (unit -> unit) -> unit
5356
(** spawn [f] as a new 'thread' *)

tests/dune

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,9 @@
1212
(name test_michael_scott_queue)
1313
(libraries dscheck alcotest)
1414
(modules test_michael_scott_queue michael_scott_queue))
15+
16+
17+
(test
18+
(name test_trace)
19+
(libraries dscheck alcotest)
20+
(modules test_trace))

tests/test_trace.ml

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
module Atomic = Dscheck.TracedAtomic
2+
3+
let counter incr () =
4+
let c1 = Atomic.make 0 in
5+
let c2 = Atomic.make 0 in
6+
Atomic.spawn (fun () -> incr c1);
7+
Atomic.spawn (fun () ->
8+
incr c1;
9+
incr c2);
10+
11+
Atomic.final (fun () ->
12+
Atomic.check (fun () -> Atomic.get c1 == 2 && Atomic.get c2 == 1))
13+
14+
let test_safe_counter () =
15+
Atomic.trace ~print_interleavings:true (counter Atomic.incr)
16+
17+
let _ = test_safe_counter ()

0 commit comments

Comments
 (0)