1 / 46

Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach

Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach. http://qed.codeplex.com. Shaz Qadeer Microsoft Research Redmond, WA. Serdar Taşıran , Tayfun Elmas , Ali Sezgin Koç University Istanbul, Turkey. QED: What is it good for?.

redford
Download Presentation

Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Generalizing Reduction and Abstraction to Simplify Concurrent Programs:The QED Approach http://qed.codeplex.com ShazQadeer Microsoft ResearchRedmond, WA Serdar Taşıran, TayfunElmas, Ali Sezgin Koç UniversityIstanbul, Turkey

  2. QED: What is it good for? Read(X) Write(X) Write(Y) Undo(Y) Want to verify:- Aborted transactions do not modify their write-set - Y is not modified here. - Straightforward if code were sequential

  3. QED: What is it good for? t = X havoc(t) Write(X) Write(Y) Undo(Y) Read(X) Want to verify:- Aborted transactions do not modify their write-set - Y is not modified here. - Straightforward if code were sequential

  4. QED-verified examples • Fine-grained locking • Linked-list with hand-over-hand locking [Herlihy-Shavit 08] • Two-lock queue [Michael-Scott 96] • Non-blocking algorithms • Bakery [Lamport 74] • Non-blocking stack [Treiber86] • Obstruction-free deque [Herlihy et al. 03] • Non-blocking stack [Michael 04] • Writer mode of non-blocking readers/writer lock [Krieger et al. 93] • Non-blocking queue [Michael-Scott 96] • Synchronous queue [Scherer-Lea-Scott 06]

  5. QED: Simplify (coarsen), then verify P1 P2 Pn . . . check Correct

  6. Coarser Atomic Actions • Difficult to prove • Fine-grain concurrency • Annotations at every • interleaving point • Easy to prove • Larger atomic blocks • Local, sequential analysis • within atomic blocks P1 P2 Pn . . . check Correct

  7. Example: Concurrent increment Main thread x := 0; assert x == 2; Thread A Thread B acquire(lock); t := x; t := t + 1; x := t; release(lock); acquire(lock); k := x; k := k + 1; x := k; release(lock); ||

  8. Owicki-Gries proof, fine-grain actions Thread A Thread B x := 0; assert x == 2; { A@L0=>x=0, A@L5=>x=1 } { A@L0=>x=0, A@L5=>x=1, held(l,B) } { A@L0=>x=0, A@L5=>x=1, held(l,B), k=x } { A@L0=>x=0, A@L5=>x=1, held(l,B), k=x+1 } { A@L0=>x=1, A@L5=>x=2, held(l,B) } { A@L0=>x=1, A@L5=>x=2 } { B@L0=>x=0, B@L5=>x=1 } { B@L0=>x=0, B@L5=>x=1, held(l,A) } { B@L0=>x=0, B@L5=>x=1, held(l,A), t=x } { B@L0=>x=0, B@L5=>x=1, held(l,A), t=x+1 } { B@L0=>x=1, B@L5=>x=2, held(l,A) } { B@L0=>x=1, B@L5=>x=2 } L0: acquire(lock); L1: t := x; L2: t := t + 1; L3: x := t; L4: release(lock); L5:// end of thread L0: acquire(lock); L1: k := x; L2: k := k + 1; L3: x := k; L4: release(lock); L5:// end of thread ||

  9. Reduction 9 inc (): acquire (lock); t := x; t := t + 1; x := t; release(lock); inc (): acquire (lock); t := x; t := t + 1; x := t; release(lock); Right mover Both mover B REDUCE-SEQUENTIAL B Left mover inc (): x := x + 1;

  10. Soundness P1 P2 Pn . . . check Soundness theorem: IfPn is correct (satisfies all assertions) then 1. all P1 ≤ i ≤n are correct. 2. Pnpreserves behaviors of all P1 ≤ i ≤n . Completeness: Subsumes Owicki-Gries [Nieto, 2007] Correct

  11. QED: Simplifier; complements other methods x := 0; assert x == 2; x := 0; assert x == 2; atomic { acquire(lock); t := x; t := t + 1; x := t; release(lock); } atomic { acquire(lock); k := x; k := k + 1; x := k; release(lock); } acquire(lock); t := x; t := t + 1; x := t; release(lock); acquire(lock); k := x; k := k + 1; x := k; release(lock); x := 0; x := x + 1; x := x + 1; assert x == 2; || || Owicki-Gries (12 location invariants) Simpler Owicki-Gries (4 location invariants) Sequential analysis Correct Correct Correct

  12. QED-verifier http://qed.codeplex.com P1 P2 Pn ... P1 QEDPL program Correct Pn reduce abstract ..... reduce check Boogie 2, Z3 Proof script

  13. Automation using SMT solver P1 P2 Pn . . . reduce abstract reduce VC VC VC Valid Valid Valid check Correct VC Valid

  14. QED Transformations: Abstraction I,P I,P’ • P’ : Atomic statement [ S ] in P replaced with [ S’ ] • When? • When atomic statement [S’] abstracts statement [S]

  15. QED’s Idea of Abstraction 15 abstracted by   s1 If for all :   s1 s1 1. If error error then   s1 s2 s1 s2 2. If then  s1 or error • Going wrong more often is sound for assertion checking

  16. Flavors of Abstraction 16 Adding non-determinism if (x == 1) y := y + 1; if (*) y := y + 1; t := x; havoc t; “Read abstraction” assume x != t; skip; Addingassertions (more “wrong” behaviors) assert (lock_owner == tid); x := t + 1; x := t + 1;

  17. QED Transformations: Reduction I,P I,P’ If [S1] and [S2] are actions of correct mover types P’ [ S1 ]; [ S2 ] [ S1 ] || [ S2 ] P [ S1; S2] [ S1 ; S2 ] P’ P

  18. Reduction  ;  ;  right-mover: ... 12  ... n  ... For each execution: Exist equivalent executions: ... 1 2  ... n  ... ........... ... 1 2  ...   n  ... ... 12  ...  n  ;  ...

  19. Use of movers in reduction atomic { acquire(lock); t := x; t := t + 1; x := t; release(lock); } acquire(lock); k := x; k := k + 1; x := k; release(lock); Right-mover Both-mover Both-mover Both-mover Left-mover reduce R B B B L E1: E2: acquire(lock) ... t := x ... ... t := t + 1; ... x := t ... release(lock) ... ... ... acquire(lock) t := x t := t + 1 release(lock) ... ... x := t E1 ≈ E2 Reason about only E2

  20. Mover check in QED: Static, local, semantic A B S1 S2 S3 A Right-mover ? All actions in program run by different thread B A S1 T2 S3 ... For each : ... B ... ; ; A B B A First-order verification condition

  21. Traditional use of reduction [Lipton, 1975] locked access release x x S1 S1 S2 S2 S3 S3 locked access release x x S1 S1 T2 T2 S3 S3 locked access acquire y y S1 S1 S2 S2 S3 S3 y y locked-access acquire S1 S1 T2 T2 S3 S3 Left-mover Right-mover Both-mover Both-mover

  22. Static mover check   • Static right-mover check between and : • Simple cases • Mover check passes: •  and  access different variables •  and  disable each other • Fails: •  writes to a variable and  reads it •  and  both write to a variable, writes do not commute

  23. x release S1 S2 S3 release x S1 T2 S3 acquire y S1 S2 S3 y acquire S1 T2 S3 Reduction: Syntactic to Semantic Notions of Commuting • Accesses to independent variables • y := 2 and x := z + t; • Increment and increment • x := x + 1 and x := x + 2 • Acquire: Right mover • Commutes to the right of any action • But what aboutacq(L) acq(L) acq(L) acq(L) • Both LHS and RHS block • No execution has two consecutive acq(L)’s

  24. Reduction: Normal to Weird Notions of Commuting • Lock protected accesses by two different threads • p q < q p • Why do they commute? • q is never followed by p • How is this captured in QED?

  25. Static mover check fails: Apparent conflict 25 • Static mover check is local, fails! • Individual actions do not locally contain the information: • “Whenever this action executes, this thread holds the lock” • Annotate action with local assertion: • Express belief about non-interference acquire (lock); t1 := x; t1 := t1 + 1; x := t1; release(lock); acquire (lock); t2 := x; t2 := t2 + 1; x := t2; release(lock);

  26. Auxiliary variable: Which thread holds the lock? 26 • Auxiliary variable a is a history variable • Summarizes relevant part of execution history New invariant: (lock == true) (a != 0) inc (): acquire (lock); a := tid; t2= x; t2= t2+ 1 x = t2; release(lock); a := 0; inc (): acquire (lock); t1= x; t1= t1+ 1 x = t1; release(lock); AUX-ANNOTATE

  27. Annotating Actions with Assertions 27 Invariant: (lock == true) (a != 0) acquire (lock); a := tid; assert a == tid; t1= x; t1= t1+ 1 assert a == tid; x = t1; assert a == tid;release(lock); a := 0; acquire (lock); a := tid; t1= x; t1= t1+ 1 x = t1; release(lock); a := 0; ABSTRACT • Assertions indicate belief about non interference • Annotate actions locally with global information about execution

  28. 28 History Variable Annotations Make Static Mover Check Pass Thread 1 acquire (lock); a := tid1; assert a == tid1; t1 := x; t1 := t1 + 1 assert a == tid1; x := t1; assert a == tid1;release(lock); a := 0; Thread 2 acquire (lock); a := tid2; assert a == tid2; t2 := x; t2 := t2 + 1 assert a == tid2; x := t2; assert a == tid2;release(lock); a := 0; R B B B L • assert a == tid1; x := t1; andassert a == tid2; x := t2; commute • α  β β α • Because both α  β and β  α result in assertion violations.

  29. Borrowing and paying back assertions 29 Invariant: (lock == true) (a != 0) Discharges the assertions inc (): acquire (lock); a := tid; assert a == tid; t1= x; t1= t1+ 1 assert a == tid; x = t1; assert a == tid;release(lock); a := 0; inc (): acquire (lock); a := tid; assert a == tid;t1= x; t1= t1+ 1 assert a == tid;x = t1; assert a == tid;release(lock); a := 0; R B B B L REDUCE-SEQUENTIAL, DISCHARGE ASSERTIONS

  30. Reduction: Syntactic to Semantic Notions of Commuting • What else commutes? • Actions that operate on different parts of memory • Different entries of a linked list • Actions on nodes not yet inserted into a data structure withactions already in the data structure • Currently thread local access with all actions • Assertions annotate action with reason for non-interference

  31. 31 Semantic Reduction: Ruling out Apparent Interference • possiblyInList[t] : • False when a newly created node assigned to t. • Set to true when p.next := t for some p. Remains true afterwards. assert possiblyInList[p2]; n2:= p2.next; assert !possiblyInList[t1]; t1.next := n1;  assert !possiblyInList[t1]; t1.next := n1; assert possiblyInList[p2]; n2:= p2.next;  • If p2 and t1 refer to the same node: • LHS and RHS lead to assertion violations (i.e., not possible) • Otherwise, no conflict.

  32. Atomic Snapshot

  33. class VersionedInteger { int v; int d; } VersionedInteger[] m; procedure Write(int a, int d) { atomic { m[a].d := d; m[a].v := m[a].v+1; } } procedure Snapshot(int a, int b, out bool s, out int da, out intdb) { intva, vb; atomic { va := m[a].v; da := m[a].d; } atomic { vb := m[b].v; db := m[b].d; } s := true; atomic { if (va < m[a].v) { s := false; } } atomic { if (vb < m[b].v) { s := false; } } }

  34. class VersionedInteger { int v; int d; } VersionedInteger[] m; procedure Write(int a, int d) { atomic { m[a].d := d; m[a].v := m[a].v+1; } } procedure Snapshot(int a, int b, out bool s, out int da, out intdb) { intva, vb; atomic { havoc va, da; assume va <= m[a].v; if (va == m[a].v) { da := m[a].d; } } atomic { havoc vb, db; assume vb <= m[b].v; if (vb == m[b].v) { db := m[b].d; } } s := true; atomic { if (va < m[a].v) { s := false; } if (s) { havoc s; } } atomic { if (vb < m[b].v) { s := false; } if (s) { havoc s; } } } Right Mover Right Mover Left Mover Left Mover

  35. class VersionedInteger { int v; int d; } VersionedInteger[] m; procedure Write(int a, int d) { atomic { m[a].d := d; m[a].v := m[a].v+1; } } procedure Snapshot(int a, int b, out bool s, out int da, out intdb) { intva, vb; atomic { havoc va, da; assume va <= m[a].v; if (va == m[a].v) { da := m[a].d; } havoc vb, db; assume vb <= m[b].v; if (vb == m[b].v) { db := m[b].d; } s := true; if (va < m[a].v) { s := false; } if (s) { havoc s; } if (vb < m[b].v) { s := false; } if (s) { havoc s; } } }

  36. class VersionedInteger { int v; int d; } VersionedInteger[] m; procedure Write(int a, int d) { atomic { m[a].d := d; m[a].v := m[a].v+1; } } procedure Snapshot(int a, int b, out bool s, out int da, out intdb) { intva, vb; atomic { havoc va, da, vb, db, s; if (s) { va := m[a].v; da := m[a].d; vb := m[b].v; db := m[b].d; s := true; } } }

  37. class VersionedInteger { int v; int d; } VersionedInteger[] m; procedure Write(int a, int d) { atomic { m[a].d := d; m[a].v := m[a].v+1; } } procedure Snapshot(int a, int b, out bool s, out int da, out intdb) { atomic { havoc da, db, s; if (s) { da := m[a].d; db := m[b].d; } } } Hide va, vb

  38. 38 Abstraction + Reduction: Increment with CAS t1 := x; s1 := CAS(x,t1,t1+1); t2 := x; s2 := CAS(x,t2,t2+1); || havoc t1; s1 := CAS(x,t1,t1+1); [ if (*) { s1:=false; } else { x:=x+1; s1:= true; } ]

  39. QED-verified examples • Fine-grained locking • Linked-list with hand-over-hand locking [Herlihy-Shavit 08] • Two-lock queue [Michael-Scott 96] • Non-blocking algorithms • Bakery [Lamport 74] • Non-blocking stack [Treiber86] • Obstruction-free deque [Herlihy et al. 03] • Non-blocking stack [Michael 04] • Writer mode of non-blocking readers/writer lock [Krieger et al. 93] • Non-blocking queue [Michael-Scott 96] • Synchronous queue [Scherer-Lea-Scott 06]

  40. QED and Optimistic Concurrency • tressa: Mechanism to annotate actions with assertions that can refer to prophecy variables (future) • assert: Discharged by reasoning about history of execution. • tressa: Temporal dual of assert • Example:y := y+1; z := z-1; assume (x == 0);

  41. tressa : Temporal Dual of assert • Example:y := y+1; // x == 0 or execution blocksz := z-1; // x == 0 or execution blocks assume (x == 0); • But • atomic{ assert x == 0; y := y+1;} atomic{ assert x == 0; z := z-1;} assume (x == 0);does not work! • Cannot discharge the assertions!

  42. tressa : Temporal Dual of assert • Example:y := y+1; // x == 0 or execution blocksz := z-1; // x == 0 or execution blocks assume (x == 0); • tressa φ: Either φ holds in the post state, or execution does not terminate (blocks). • atomic{ y := y+1; tressa x == 0;} atomic{ z := z-1; tressa x == 0;} assume (x == 0); • tressa annotations discharged by backwards reasoning within an atomic block. • Discharged tressaφ: You cannot come back from a final state of the program and violate φ

  43. Discharging tressa’s inc (): int t; acquire (lock); p =: 0 tressa a == tid; t = x; t = t + 1 tressa a == tid; x = t; release(lock); p =: tid; inc (): int t; acquire (lock); p =: 0; tressa p == tid;t = x; t = t + 1 tressa a == tid;x = t; release(lock); p =: tid; R B B B L REDUCE & RELAX

  44. Pair Snapshot Example: Write public void Write(int a, int d) { atomic{ m[a].d = d; // Write data m[a].v++; // Increment version number } }

  45. if TrySnapshot ends with s == true TrySnapshot(inta, int b) { atomic{ va = m[a].v; da = m[a].d; } atomic{ vb = m[b].v; db = m[b].d; } s = true; atomic{ if (va!=m[a].v) s = false; } atomic{ if (vb!=m[b].v) s = false; } } a not written to (da,db) isa consistentsnapshot b not written to

  46. Other Work on QED • Variable hiding • Linearizability-preserving soundness theorem • Annotation assistance: • Automating proofs for simple programs • Common synchronization idioms • Verifying parallelizing compilers

More Related