590 likes | 698 Views
Asserting and Checking Determinism for Parallel Programs. Jacob Burnim Koushik Sen * EECS, UC Berkeley. Motivation. Parallel programming is difficult Culprit: Non-determinism Interleaving of parallel threads But required to harness parallelism
E N D
Asserting and Checking Determinismfor Parallel Programs Jacob Burnim KoushikSen* EECS, UC Berkeley
Motivation • Parallel programming is difficult • Culprit: Non-determinism • Interleaving of parallel threads • But required to harness parallelism • Sequential programs produce deterministic results • To make parallel programming easy • We want determinism • Same input => semantically same output.
Determinism Efforts • Language design [DPJ, X10,Yada] • Deterministic by design: Types and annotations • Constrains programming • May need non-determinism for better performance • Deterministic runtime [DMP, Kendo] • Race detection • Absence of data races does not imply determinism • Data races could be benign and could help in improving performance • Determinism Checker [SingleTrack, Torrellas et al.] • Dynamic determinism checker. • Determinism with respect to abstraction [Rinard et al.]
Our Goal • Provide a framework that can express relevant determinism directly and easily • Separate from functional correctness specification • Allow data races and healthy non-determinism • Language independent • Useful for QA
Our Goal • How to specify correctness of parallelism? Implicit: No sourcesofnon-determinism(no data races) Explicit: Full functional correctness. • Determinism specification: A sweet spot? • Lightweight, but precise.
Outline • Motivation • Deterministic Specification [FSE’09] • Checking: Active Testing • Experimental Evaluation • Future Work + Conclusions
Deterministic Specification • Goal: Specify deterministic behavior. • Same initial parameters => same image. • Non-determinism is internal. // Parallel fractal render mandelbrot(params, img);
Deterministic Specification • Program: , Initial State: , Schedules: • Specifies: Two runs from same initial program state have same result state for any pair of schedules deterministic { // Parallel fractal render mandelbrot(params, img); }
Deterministic Specification • Too restrictive – different schedules may give slightly different floating-point results. double A[][], b[], x[]; ... deterministic { // Solve A*x = b in parallel lufact_solve(A, b, x); }
Deterministic Specification • Too restrictive – internal structure of set may differ depending on order of adds. set t = new RedBlackTreeSet(); deterministic { t.add(3) || t.add(5); }
Deterministic Specification • Too restrictive – search can correctly return any tree with optimal cost. deterministic { // Parallel branch-and-bound Tree t = min_phylo_tree(data); }
Semantic Determinism • Too strict to require every interleaving to give exact same program state: deterministic { P }
Semantic Determinism • Too strict to require every interleaving to give exact same program state: deterministic { P } Predicate! Should be user-defined.
Semantic Determinism • Too strict to require every interleaving to give exact same program state: • Specifies: Final states are equivalent. deterministic { P } assert Post(s1,s1’)
Semantic Determinism double A[][], b[], x[]; ... deterministic { // Solve A*x = b in parallel lufact_solve(A, b, x); } assert (|x – x’| < ε) “Bridge” predicate
Semantic Determinism • Resulting sets are semantically equal. set t = new RedBlackTreeSet(); deterministic { t.add(3) || t.add(5); } assert (t.equals(t’))
Semantic Determinism deterministic { // Parallel branch-and-bound Tree t = min_phylo_tree(data); } assert (t.cost == t’.cost())
Preconditions for Determinism set t = … deterministic { t.add(3) || t.add(5); } assert (t.equals(t’)) … deterministic { t.add(4) || t.add(6); } assert (t.equals(t’)) • Too strict – initial states must be identical • Not compositional.
Preconditions for Determinism • Too strict to require identical initial states: deterministic { P } assert Post(s1,s1’)
Preconditions for Determinism • Too strict to require identical initial states: deterministic assume (s0 = s0’) { P } assert Post(s1,s1’)
Preconditions for Determinism • Too strict to require identical initial states: deterministic assume (s0 = s0’) { P } assert Post(s1,s1’) Predicate! Should be user-defined.
Preconditions for Determinism • Too strict to require identical initial states: • Specifies: deterministic assume Pre(s0,s0’) { P } assert Post(s1,s1’)
Bridge predicates/assertions deterministic assume Pre(s0,s0’) { P } assert Post(s1,s1’) “Bridge”predicate “Bridge”assertion
Preconditions for Determinism • Specifies: Semantically equal sets yield semantically equal sets. set t = ... deterministic assume (t.equals(t’) { t.add(4) || t.add(6); } assert (t.equals(t’))
Advantage • Separately check parallelism and functional correctness. • Show parallelism is outwardly deterministic. • Reason about correctness sequentially. • Decompose correctness proof! • Example: • Write Cilk program and prove (or test) sequential correctness. • Add parallelism, answers should not change
Determinism vs. Atomicity • Internal vs. external parallelism/non-determinism • Complementary notions Deterministic Atomic “Closed program” “Open program”
Other Testing Use sequential program as spec deterministic Pre(s0,s0’) { if (*) { SequentialPgm; } else { ParallelPgm; } } assert Post(s,s’); Regression testing deterministic Pre(s0,s0’) { if (*) { PgmVersion1; } else { PgmVersion2; } } assert Post(s,s’);
Outline • Motivation • Deterministic Specification [FSE’09] • Checking: Active Testing [PLDI 08,09, FSE 08, CAV 09] • Experimental Evaluation • Future Work + Conclusions
Checking: Active Testing Predicting and Exploring “interesting” Schedules
Active Testing:Predict and Test Potential Bugs • Predict potential bugs: • Data races: Eraser or lockset based • Atomicity violations: cycle in transactions and happens-before relation • Deadlocks: cycle in resource acquisition graph • Memory model bugs: cycle in happens-before relation • Test schedules to create those bugs [ASE 07, PLDI 08, FSE 08, PLDI 09, FSE 09, CAV 09]
Active Testing Cartoon: Phase I Potential Collision 2 1 1 3 2
Active Testing Cartoon: Phase II 2 1 1 3 2
Outline • Motivation • Deterministic Specification • Checking: Active Testing • Experimental Evaluation • Future Work + Conclusions
Ease of Asserting Determinism • Implemented a deterministic assertion library for Java. • Manually added deterministic assertions to 13 Java benchmarks with 200 – 4k LoC • Typically 5-10 minutes per benchmark • Functional correctness very difficult.
Ease of Use: Example Deterministic.open(); Predicate eq = new Equals(); Deterministic.assume(width, eq); … (9 parameters total) … Deterministic.assume(gamma, eq); // Compute fractal in threads int matrix[][] = …; Deterministic.assert(matrix, eq); Deterministic.close();
Effectiveness in Finding Bugs • 13 Java benchmarks of 200 – 4k LoC • Ran benchmarks on ~100 schedules • Schedules with data races and other “interesting” interleavings (active testing) • For every pair of executions ofdeterministic Pre { P } Post:check that:
Experimental Evaluation • Across 13 benchmarks: • Found 40 data races. • 1 violates deterministic assertions.
Experimental Evaluation • Across 13 benchmarks: • Found 40 data races. • 1 violates deterministic assertions. • Found many interesting interleavings(non-atomic methods, lock races, etc.) • 1 violates deterministic assertions.
Determinism Violation deterministic { // N trials in parallel. foreach (n = 0; n < N; n++) { x = Random.nextDouble(); y = Random.nextDouble(); … } } assert (|pi - pi’| < 1e-10) • Pair of calls to nextDouble() mustbe atomic.
Outline • Motivation • Deterministic Specification • Checking: Active Testing • Experimental Evaluation • Future Work + Conclusions
How to verify: Essential Rule deterministic assume(Φ1) A11;A12;A13|| A21;A22;A23|| A31;A32;A33 } assert (Φ2)
How to verify: Essential Rule deterministic assume(Φ1) A11;A12;A13|| A21;A22;A23|| A31;A32;A33 } assert (Φ2) Find an invariant Φ and prove that for all i, j, l, m deterministic assume(Φ) Aij|| Alm } assert (Φ) and Φ1 → Φ and Φ → Φ2
Prove for the following deterministic assume(true) { parallel while (!wq.is_empty()) { [work = wq.get();] if (bound(work) >= best) continue; if (size(work) <= threshold) { s = find_best_solution(work); [best = min(best,cost(s));] } else { [wq.add_all(split(work));] } } } assert(best=best’)
Decompose the proof Let us prove that P ≈ S That is prove that deterministic assume(Pre(S0,S’0)) { if (*) P else S } assert (Post(S,S’))
Decompose the proof Let us prove that P ≈ S Create a non deterministic sequential program NS [Galois] P ≡ NS ≈ S
Decompose the proof Let us prove that P ≈ S Create a non deterministic sequential program NS P ≡ NS ≈ S deterministic assume(S0=S’0) { if (*) P else NS } assert (S=S’) deterministic assume(Pre(S0,S’0)) { if (*) NS else S } assert (Post(S,S’))
How to verify? deterministic assume(true) { parallel while (!wq.is_empty()) { [work = wq.get();] if (bound(work) >= best) continue; if (size(work) <= threshold) { s = find_best_solution(work); [best = min(best,cost(s));] } else { [wq.add_all(split(work));] } } } assert(best=best’) Not deterministic sequential program while (!wq.is_empty()) { [work = wq.nondet_get();] if (bound(work) >= best) continue; if (size(work) <= threshold) { s = find_best_solution(work); [best = min(best,cost(s));] } else { [wq.add_all(split(work));] } }
How to verify? Not deterministic sequential program while (!wq.is_empty()) { [work = wq.nondet_get();] if (bound(work) >= best) continue; if (size(work) <= threshold) { s = find_best_solution(work); [best = min(best,cost(s));] } else { [wq.add_all(split(work));] } } deterministic assume(true) { parallel while (!wq.is_empty()) { [work = wq.get();] if (bound(work) >= best) continue; if (size(work) <= threshold) { s = find_best_solution(work); [best = min(best,cost(s));] } else { [wq.add_all(split(work));] } } } assert(best=best’) Barrier()