Skip to content

Commit 4b458de

Browse files
committed
Parallelism: clean-up this commit
1 parent 7572497 commit 4b458de

File tree

5 files changed

+200
-184
lines changed

5 files changed

+200
-184
lines changed

src/common/util/cilfacade.ml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,8 @@ end
114114
let cleanCilPrinter = new cleanCilPrinterClass
115115

116116
let cleanDumpFile (pp: cilPrinter) (out : out_channel) (outfile: string) file =
117-
Domain.DLS.set Pretty.printDepth 99999;
118-
Domain.DLS.set Pretty.fastMode true;
117+
Pretty.printDepth := 99999;
118+
Pretty.fastMode := true;
119119
iterGlobals file (fun g -> dumpGlobal pp out g);
120120
flush out
121121

src/solver/parallelStats.ml

Lines changed: 66 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,15 @@ struct
2121
let instant_returns = Atomic.make 0
2222
let thread_starts = Atomic.make 0
2323
let thread_creates = Atomic.make 0
24+
let thread_start_times = Array.init maximal_number_of_threads (fun _ -> 0.0)
25+
let thread_end_times = Array.init maximal_number_of_threads (fun _ -> 0.0)
2426

2527
let active_threads = Atomic.make 0
2628
let first_thread_activation_time = Atomic.make 0.0
2729
let last_thread_activation_update_time = Atomic.make 0.0
2830
let total_thread_activation_time = Atomic.make 0.0
31+
32+
let iterations = Atomic.make 0
2933

3034
let updates = Atomic.make 0
3135
let updates_by_thread = Array.init maximal_number_of_threads (fun _ -> Atomic.make 0)
@@ -88,44 +92,46 @@ struct
8892
let rec thread_starts_solve_event thread_id =
8993
Atomic.incr thread_starts;
9094
let t = Unix.gettimeofday () in
91-
if (Atomic.get first_thread_activation_time) = 0.0 then
92-
begin
93-
let success = Atomic.compare_and_set first_thread_activation_time 0.0 t in
94-
if (not success) then thread_starts_solve_event thread_id
95-
else (
96-
Atomic.set last_thread_activation_update_time t;
97-
Atomic.incr active_threads;
98-
)
99-
end
100-
else (
101-
let last_thread_activation_update_time_f = Atomic.get last_thread_activation_update_time in
102-
let success = Atomic.compare_and_set last_thread_activation_update_time last_thread_activation_update_time_f t in
103-
if (not success) then thread_starts_solve_event thread_id
104-
else
105-
begin
106-
let time_diff = t -. last_thread_activation_update_time_f in
107-
let cpu_time_since_last_update = time_diff *. (float_of_int @@ Atomic.get active_threads) in
108-
let current_total_thread_activation_time = Atomic.get total_thread_activation_time in
109-
let new_total_thread_activation_time = current_total_thread_activation_time +. cpu_time_since_last_update in
110-
Atomic.set total_thread_activation_time new_total_thread_activation_time;
111-
Atomic.incr active_threads;
112-
end
113-
)
95+
thread_start_times.(thread_id) <- t
96+
(* if (Atomic.get first_thread_activation_time) = 0.0 then *)
97+
(* begin *)
98+
(* let success = Atomic.compare_and_set first_thread_activation_time 0.0 t in *)
99+
(* if (not success) then thread_starts_solve_event thread_id *)
100+
(* else ( *)
101+
(* Atomic.set last_thread_activation_update_time t; *)
102+
(* Atomic.incr active_threads; *)
103+
(* ) *)
104+
(* end *)
105+
(* else ( *)
106+
(* let last_thread_activation_update_time_f = Atomic.get last_thread_activation_update_time in *)
107+
(* let success = Atomic.compare_and_set last_thread_activation_update_time last_thread_activation_update_time_f t in *)
108+
(* if (not success) then thread_starts_solve_event thread_id *)
109+
(* else *)
110+
(* begin *)
111+
(* let time_diff = t -. last_thread_activation_update_time_f in *)
112+
(* let cpu_time_since_last_update = time_diff *. (float_of_int @@ Atomic.get active_threads) in *)
113+
(* let current_total_thread_activation_time = Atomic.get total_thread_activation_time in *)
114+
(* let new_total_thread_activation_time = current_total_thread_activation_time +. cpu_time_since_last_update in *)
115+
(* Atomic.set total_thread_activation_time new_total_thread_activation_time; *)
116+
(* Atomic.incr active_threads; *)
117+
(* end *)
118+
(* ) *)
114119

115120
let rec thread_ends_solve_event thread_id =
116121
let t = Unix.gettimeofday () in
117-
let last_thread_activation_update_time_f = Atomic.get last_thread_activation_update_time in
118-
let success = Atomic.compare_and_set last_thread_activation_update_time last_thread_activation_update_time_f t in
119-
if (not success) then thread_ends_solve_event thread_id
120-
else
121-
begin
122-
let time_diff = t -. last_thread_activation_update_time_f in
123-
let cpu_time_since_last_update = time_diff *. (float_of_int @@ Atomic.get active_threads) in
124-
let current_total_thread_activation_time = Atomic.get total_thread_activation_time in
125-
let new_total_thread_activation_time = current_total_thread_activation_time +. cpu_time_since_last_update in
126-
Atomic.set total_thread_activation_time new_total_thread_activation_time;
127-
Atomic.decr active_threads;
128-
end
122+
thread_end_times.(thread_id) <- t
123+
(* let last_thread_activation_update_time_f = Atomic.get last_thread_activation_update_time in *)
124+
(* let success = Atomic.compare_and_set last_thread_activation_update_time last_thread_activation_update_time_f t in *)
125+
(* if (not success) then thread_ends_solve_event thread_id *)
126+
(* else *)
127+
(* begin *)
128+
(* let time_diff = t -. last_thread_activation_update_time_f in *)
129+
(* let cpu_time_since_last_update = time_diff *. (float_of_int @@ Atomic.get active_threads) in *)
130+
(* let current_total_thread_activation_time = Atomic.get total_thread_activation_time in *)
131+
(* let new_total_thread_activation_time = current_total_thread_activation_time +. cpu_time_since_last_update in *)
132+
(* Atomic.set total_thread_activation_time new_total_thread_activation_time; *)
133+
(* Atomic.decr active_threads; *)
134+
(* end *)
129135

130136

131137
(* solvers can assign this to print solver specific statistics using their data structures *)
@@ -169,21 +175,38 @@ struct
169175
let threads_data = Seq.zip threads_data (Array.to_seq updates_by_thread) in
170176
let threads_with_update = ref 0 in
171177
let threads_with_anything = ref 0 in
172-
Seq.iteri (fun i ((vars, evals), updates) ->
173-
if (Atomic.get vars) <> 0 || (Atomic.get evals) > 0 || (Atomic.get updates) <> 0 then
174-
begin
175-
Logs.info "Thread %d: vars: %d, evals: %d, updates: %d" i (Atomic.get vars) (Atomic.get evals) (Atomic.get updates);
176-
threads_with_anything := !threads_with_anything + 1;
177-
end;
178-
if (Atomic.get updates) <> 0 then threads_with_update := !threads_with_update + 1
179-
) threads_data;
178+
(* The following is an important statistics, here left out for simplicity *)
179+
(* Seq.iteri (fun i ((vars, evals), updates) -> *)
180+
(* if (Atomic.get vars) <> 0 || (Atomic.get evals) > 0 || (Atomic.get updates) <> 0 then *)
181+
(* begin *)
182+
(* Logs.info "Thread %d: vars: %d, evals: %d, updates: %d" i (Atomic.get vars) (Atomic.get evals) (Atomic.get updates); *)
183+
(* threads_with_anything := !threads_with_anything + 1; *)
184+
(* end; *)
185+
(* if (Atomic.get updates) <> 0 then threads_with_update := !threads_with_update + 1 *)
186+
(* ) threads_data; *)
180187
Logs.info "Threads with updates: %d" !threads_with_update;
181188
Logs.info "Threads with anything: %d" !threads_with_anything;
182189
Logs.info "Threads returned instantly: %d" (Atomic.get instant_returns);
183190
Logs.info "Threads started: %d" (Atomic.get thread_starts);
184191
Logs.info "Threads created: %d" (Atomic.get thread_creates);
185192
Logs.info "Threads active: %d" (Atomic.get active_threads);
186193

194+
let non_zero_start_times = Array.filter (fun t -> t <> 0.0) thread_start_times in
195+
let first_thread_start = Array.fold_left min infinity non_zero_start_times in
196+
let current_time = Unix.gettimeofday () in
197+
let total_runtime = Seq.zip (Array.to_seq thread_start_times) (Array.to_seq thread_end_times)
198+
|> Seq.filter (fun (start, end_) -> start <> 0.0)
199+
|> Seq.map (fun (start, end_) -> if end_ = 0.0 then (start, current_time) else (start, end_))
200+
|> Seq.fold_left (fun acc (start, end_) -> acc +. (end_ -. start)) 0.0 in
201+
let walltime = current_time -. first_thread_start in
202+
Logs.info "Total runtime: %f" total_runtime;
203+
Logs.info "Walltime: %f" walltime;
204+
let average_active_threads = total_runtime /. walltime in
205+
Logs.info "Average active threads: %f" average_active_threads;
206+
207+
208+
209+
187210
(* Logs.info "vars: %d" (Atomic.get vars); *)
188211

189212
(* Array.iteri (fun i v -> if Atomic.get v <> 0 then Logs.info "vars (%d): %d" i (Atomic.get v)) vars_by_thread; *)

src/solver/td_parallel_base.ml

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ module CasWithStatAndException = struct
3030
if Atomic.compare_and_set key old new_ then
3131
Atomic.incr count_success
3232
else
33-
raise CasFailException
33+
begin
34+
Atomic.incr count_failure;
35+
raise CasFailException
36+
end
3437
end
3538

3639
module Base : GenericCreatingEqSolver =
@@ -54,14 +57,17 @@ module Base : GenericCreatingEqSolver =
5457
stable: bool;
5558
called: bool;
5659
root: bool; (** If this variable was the starting point of a solver thread *)
60+
id: int; (** Just for experimentation *)
5761
}
58-
let default () = {value = S.Dom.bot (); infl = VS.empty; called = false; stable = false; wpoint = false; root = false}
62+
let default () = {value = S.Dom.bot (); infl = VS.empty; called = false; stable = false; wpoint = false; root = false; id=0}
5963
let to_string s = S.Dom.show s.value
6064
end
6165

6266
(** Concurrency safe hashmap for the state of the unknowns. *)
6367
module CM = Data.SafeHashmap (S.Var) (DefaultState) (HM)
6468

69+
let var_count = Atomic.make 0
70+
6571
let create_empty_data () = CM.create ()
6672

6773
(* TODO this map should also be thread safe, or secured with a lock *)
@@ -77,9 +83,9 @@ module Base : GenericCreatingEqSolver =
7783
let cas = Data.CasWithStat.cas
7884

7985
let print_data data =
80-
Logs.debug "CAS success: %d" (Atomic.get Data.CasWithStat.count_success);
81-
Logs.debug "CAS failure: %d" (Atomic.get Data.CasWithStat.count_failure);
82-
Logs.debug "CAS success rate: %f" (float_of_int (Atomic.get Data.CasWithStat.count_success) /. (float_of_int (Atomic.get Data.CasWithStat.count_success + Atomic.get Data.CasWithStat.count_failure)))
86+
Logs.info "CAS success: %d" (Atomic.get CasWithStatAndException.count_success);
87+
Logs.info "CAS failure: %d" (Atomic.get CasWithStatAndException.count_failure);
88+
Logs.info "CAS success rate: %f" (float_of_int (Atomic.get CasWithStatAndException.count_success) /. (float_of_int (Atomic.get CasWithStatAndException.count_success + Atomic.get CasWithStatAndException.count_failure)))
8389

8490
let print_data_verbose data str =
8591
if Logs.Level.should_log Debug then (
@@ -108,6 +114,9 @@ module Base : GenericCreatingEqSolver =
108114
let init x thread_id =
109115
let value, was_created = CM.find_create data x in
110116
if (was_created) then new_var_event thread_id x;
117+
let var_id = Atomic.fetch_and_add var_count 1 in
118+
let s = Atomic.get value in
119+
Atomic.set value {s with id = var_id};
111120
value
112121
in
113122

@@ -176,7 +185,7 @@ module Base : GenericCreatingEqSolver =
176185
if tracing then trace "thread_pool" "starting task %d to iterate %a" job_id S.Var.pretty_trace y;
177186
thread_starts_solve_event job_id;
178187
let inner_prom = ref [] in
179-
iterate None inner_prom y job_id y_atom;
188+
iterate None inner_prom y [] job_id y_atom;
180189
HM.remove unknowns_with_running_jobs y;
181190
thread_ends_solve_event job_id;
182191
Thread_pool.await_all pool (!inner_prom);
@@ -199,13 +208,14 @@ module Base : GenericCreatingEqSolver =
199208
@param job_id The id of the thread that is solving for x.
200209
@param x_atom The atomic reference to the state of x, to prevent unnecessary lookups.
201210
*)
202-
and iterate orig prom x job_id x_atom = (* ~(inner) solve in td3*)
211+
and iterate orig prom x ichain job_id x_atom = (* ~(inner) solve in td3*)
203212

204213
(** Get the value for y, triggering an iteration if necessary, and performing a lookup otherwise.
205214
@param x The variable whose query led to the query for y, so that the infl of y can be updated.
206215
@param y The variable to get the value for.
207216
@return The value of y.
208217
*)
218+
209219
let rec query x y = (* ~eval in td3 *)
210220
(* Query with atomics: if anything is changed, query is repeated and the initial call *)
211221
(* has no side effects. Thus, imitating that the query just happend in a later point in time.*)
@@ -233,7 +243,8 @@ module Base : GenericCreatingEqSolver =
233243
) else (
234244
if tracing then trace "infl" "add_infl %a %a" S.Var.pretty_trace y S.Var.pretty_trace x;
235245
cas y_atom y_state {y_state_with_infl with stable = true; called=true};
236-
iterate (Some x) prom y job_id y_atom;
246+
let ichain = y_state.id :: ichain in
247+
iterate (Some x) prom y ichain job_id y_atom;
237248
(Atomic.get y_atom).value
238249
)
239250
) ) with CasFailException -> query x y
@@ -281,9 +292,19 @@ module Base : GenericCreatingEqSolver =
281292
in
282293

283294
(* begining of iteration to update the value for x *)
295+
(* let ichain_as_string = List.fold_left (fun acc x -> acc ^ (string_of_int x) ^ ".") "" in *)
296+
(* if tracing then trace "ichain" "%s" (ichain_as_string ichain); *)
284297
assert (not @@ is_global x);
285298
let cas = CasWithStatAndException.cas in
286299
let x_state = Atomic.get x_atom in
300+
301+
(match orig with
302+
Some orig -> begin
303+
let orig_atom = CM.find data orig in
304+
let orig_state = Atomic.get orig_atom in
305+
if tracing then trace "ilink" "%d,%d" orig_state.id x_state.id;
306+
end
307+
| None -> ());
287308
if tracing then trace "iter" "%d iterate %a, stable: %b, wpoint: %b" job_id S.Var.pretty_trace x x_state.stable x_state.wpoint;
288309
let x_is_widening_point = x_state.wpoint in (* if x becomes a wpoint during eq, checking this will delay widening until next iterate *)
289310
eval_rhs_event job_id x;
@@ -302,13 +323,13 @@ module Base : GenericCreatingEqSolver =
302323
| Some z -> (VS.add z x_state.infl)
303324
| None -> x_state.infl in
304325
let x_state_new = {x_state with infl = infl; called = false; wpoint = false} in
305-
try (cas x_atom x_state x_state_new ) with CasFailException -> (iterate[@tailcall]) orig prom x job_id x_atom;
326+
try (cas x_atom x_state x_state_new ) with CasFailException -> (iterate[@tailcall]) orig prom x ichain job_id x_atom;
306327
) else (
307328
let x_state_new = {x_state with stable = true} in
308329
(* No need to track cas success, as we will iterate again anyway. *)
309330
ignore @@ Atomic.compare_and_set x_atom x_state x_state_new;
310331
if tracing then trace "iter" "iterate still unstable %a" S.Var.pretty_trace x;
311-
(iterate[@tailcall]) orig prom x job_id x_atom
332+
(iterate[@tailcall]) orig prom x ichain job_id x_atom
312333
)
313334
) else (
314335
(* value has changed *)
@@ -336,11 +357,11 @@ module Base : GenericCreatingEqSolver =
336357
let success = Atomic.compare_and_set x_atom x_state new_s in
337358
if success then (
338359
if tracing then trace "iter" "iterate changed %a" S.Var.pretty_trace x;
339-
(iterate[@tailcall]) orig prom x job_id x_atom
360+
(iterate[@tailcall]) orig prom x ichain job_id x_atom
340361
) else (finalize[@tailcall]) ()
341362
) in
342363
finalize ();
343-
) with CasFailException -> (iterate[@tailcall]) orig prom x job_id x_atom;
364+
) with CasFailException -> (iterate[@tailcall]) orig prom x ichain job_id x_atom;
344365
) in
345366

346367
let set_start (x,d) =
@@ -350,6 +371,7 @@ module Base : GenericCreatingEqSolver =
350371
in
351372

352373
(* beginning of main solve *)
374+
353375
start_event ();
354376

355377
List.iter set_start st;
@@ -388,6 +410,7 @@ module Base : GenericCreatingEqSolver =
388410
(* After termination, only those variables are stable which are
389411
* - reachable from any of the queried variables vs, or
390412
* - effected by side-effects and have no constraints on their own (this should be the case for all of our analyses). *)
413+
print_data ();
391414
print_stats ();
392415
stop_event ();
393416

0 commit comments

Comments
 (0)