1 / 42

QED: A Simplifier for Concurrent Programs

QED: A Simplifier for Concurrent Programs. Shaz Qadeer Microsoft Research. Joint work with Tayfun Elmas Ali Sezgin Serdar Tasiran. Reliable concurrent software?. Concurrency results in Heisenbugs non-deterministic, timing dependent data corruption, crashes

aric
Télécharger la présentation

QED: A Simplifier for Concurrent Programs

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. QED: A Simplifier for Concurrent Programs Shaz Qadeer Microsoft Research Joint work with Tayfun Elmas Ali Sezgin Serdar Tasiran

  2. Reliable concurrent software? • Concurrency results in Heisenbugs • non-deterministic, timing dependent • data corruption, crashes • difficult to detect, reproduce, eliminate • Correctness problem • does program behave correctly for allinputs and allinterleavings?

  3. Undecidable problem! P satisfies S

  4. Assertions: Provide contracts to decompose problem • into a collection of decidable problems • pre-condition and post-condition for each procedure • loop invariant for each loop P satisfies S

  5. Invariant problem • pre x=c; A B int t; L0: acquire(l); L1: t := x; L2: t := t + 1; L3: x := t; L4: release(l); L5: int t; M0: acquire(l); M1: t := x; M2: t := t + 1; M3: x := t; M4: release(l); M5: B@M0x=c,B@M5x=c+1 A@L0x=c, A@L5x=c+1 B@M0x=c,B@M5x=c+1, held(l, A) A@L0x=c, A@L5x=c+1, held(l, B) B@M0x=c,B@M5x=c+1, held(l, A), t=x A@L0x=c, A@L5x=c+1, held(l, B), t=x B@M0x=c,B@M5x=c+1, held(l, A), t=x+1 A@L0x=c, A@L5x=c+1, held(l, B), t=x+1 B@M0x=c+1,B@M5x=c+2, held(l, A) A@L0x=c+1, A@L5x=c+2, held(l, B) B@M0x=c+1,B@M5x=c+2 A@L0x=c+1, A@L5x=c+2 • post x=c+2;

  6. Abstraction problem int t; t := x; t := t + 1; x := t; x := x+1 int t; acquire(l); t := x; t := t + 1; x := t; release(l); ??

  7. Intuitive reasoning with atomic actions • pre x=c; int t; L0: acquire(l); L1: t := x; L2: t := t + 1; L3: x := t; L4: release(l); L5: int t; M0: acquire(l); M1: t := x; M2: t := t + 1; M3: x := t; M4: release(l); M5: • post x=c+2;

  8. Intuitive reasoning with atomic actions • pre x=c; int t; atomic { L0: acquire(l); L1: t := x; L2: t := t + 1; L3: x := t; L4: release(l); } L5: int t; atomic { M0: acquire(l); M1: t := x; M2: t := t + 1; M3: x := t; M4: release(l); } M5: B@M0x=c,B@M5x=c+1 A@L0x=c, A@L5x=c+1 B@M0x=c+1,B@M5x=c+2 A@L0x=c+1, A@L5x=c+2 • post x=c+2;

  9. Intuitive reasoning with atomic actions • pre x=c; atomic { x := x + 1; } atomic { x := x + 1; } • post x=c+2;

  10. Intuitive reasoning with atomic actions • pre x=c; atomic { x := x + 1; } atomic { x := x + 1; } • post x=c+2; Verify using sequential methods!

  11. QED • Do not verify the original program • Instead, simplify the program • Verify the program once it is simple enough I,P Invariant Program text I0,P0 I1,P1 I2,P2 I3,P3 • Simplified program has simpler invariants • Abstraction of a program is another program

  12. Atomic snapshot int[] m; procedure Write(int a, int d) { atomic { m[a] := d; } } procedure Snapshot(int a, int b, out int da, out intdb) { atomic { da := m[a]; db := m[b]; } }

  13. Atomic snapshot 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; } } }

  14. QED-simplified atomic snapshot 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, int b, out bool s, out int da, out intdb) { atomic { havoc s, da, db; if (s) { da := m[a].d; db := m[b].d; } } }

  15. QED transformations I,P I’,P’ Strengthen invariant Reduce program Abstract program

  16. Rule 1: Strengthen invariant I,P I’,P I’  I

  17. Rule 2: Reduce program I,P I,P’ atomic { A} ; atomic { B } atomic { A ; B }

  18. x release S1 S2 S3 release x S1 T2 S3 acquire y S1 S2 S3 y acquire S1 T2 S3 Right and left movers (Lipton 1975) Lock int owner; procedure acquire() { atomic { assume owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; } }

  19. R* . x . N . Y . L* S0 S5 R* . . . Y x . N L* S0 S5 Reduction theorem Sequence R*;(N+); L*is atomic

  20. Rule 3: Abstract program I,P I,P’ atomic { A } atomic { B } From each state x in I, if A can go to y then B can also go to y

  21. QED tool [http://qed.codeplex.com] P1 P2 Pn P1 ... QED Correct Pn reduce abstract ..... reduce check

  22. 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]

  23. QED transformations I,P I’,P’ • Strengthen invariant • Abstract program • Reduce program • The rules are symbiotic: • Abstraction enables reduction • Reduction enables abstraction • Program simplification enables simpler invariants Together these rules are surprisingly powerful!

  24. Two examples • Atomic snapshot • Abstraction enables reduction • Spin lock • Program simplification yields simpler invariants

  25. Atomic Snapshot

  26. 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; } } }

  27. 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

  28. 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; } } }

  29. 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; } } }

  30. 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

  31. Spin Lock

  32. bool held; procedure acquire() { while (true) { if (CAS(held, false, true)) { break; } } } procedure release() { held := false; } int owner; procedure acquire() { atomic { assume owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; } }

  33. bool held; int owner; procedure acquire() { while (true) { if (CAS(held, false, true)) { owner := tid; break; } } } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  34. bool held; int owner; procedure acquire() { while (*) { assume held != false; } atomic { assume held == false; held := true; } owner := tid; } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  35. bool held; int owner; procedure acquire() { while (*) { assume true; } atomic { assume held == false; held := true; } owner := tid; } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  36. bool held; int owner; procedure acquire() { atomic { assume held == false; held := true; } owner := tid; } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  37. bool held; int owner; procedure acquire() { atomic { assume held == false; held := true; } atomic { assert owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } } Left Mover (Not Quite) Invariant: owner == 0  held == false

  38. bool held; int owner; procedure acquire() { atomic { assume held == false; held := true; assert owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  39. bool held; int owner; procedure acquire() { atomic { assume held == false; held := true; assert owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } } Invariant: owner == 0  held == false

  40. bool held; int owner; procedure acquire() { atomic { assume held == false; held := true; assume owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; held := false; } }

  41. int owner; procedure acquire() { atomic { assume owner == 0; owner := tid; } } procedure release() { atomic { assert owner == tid; owner := 0; } } Hide held

  42. Conclusions • QED: A simplifier for concurrent programs • Do not verify the original program • Instead, simplify the program • Verify the program once it is simple enough • Other applications • Concurrency testing • Programmer-assisted parallelization

More Related