Upload
trina
View
28
Download
0
Embed Size (px)
DESCRIPTION
Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach. http ://qed.codeplex.com [POPL ’ 09, TACAS ‘ 10, PADTAD ‘ 10, VSTTE ‘ 10]. Shaz Qadeer Microsoft Research Redmond, WA. Serdar Taşıran , Tayfun Elmas , Ali Sezgin - PowerPoint PPT Presentation
Citation preview
Generalizing Reduction and Abstraction to
Simplify Concurrent Programs:The QED Approach
Shaz QadeerMicrosoft Research
Redmond, WA
Serdar Taşıran, Tayfun Elmas, Ali SezginKoç University Istanbul, Turkey
http://qed.codeplex.com[POPL ’09, TACAS ‘10, PADTAD ‘10, VSTTE ‘10]
QED: Simplify (coarsen), then verify
2
. . .
check
P1 PnP2
Correct
Coarser Atomic Actions
3
. . .
check
P1 PnP2
Correct
Difficult to prove• Fine-grain
concurrency• Annotations at every
interleaving point
Easy to prove• Larger atomic blocks• Local, sequential
analysis within atomic blocks
Example: Concurrent increment
4
acquire(lock);
t := x;
t := t + 1;
x := t;
release(lock);
acquire(lock);
k := x;
k := k + 1;
x := k;
release(lock);
x := 0;
assert x == 2;
Thread A Thread B
||
Main thread
Owicki-Gries proof, fine-grain actions
5
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
x := 0;
assert 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 }
{ 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 }
Thread A Thread B
6
Reduction
inc (): acquire (lock);
t := x;
t := t + 1;
x := t;
release(lock);
Right mover
Both mover
B
B
Left mover
inc (): acquire (lock);
t := x;
t := t + 1;
x := t;
release(lock);
inc (): x := x + 1;
REDUCE-SEQUENTIAL
6
Soundness
7
Soundness theorem:If Pn is correct (satisfies all assertions) then
1. all P1 ≤ i ≤ n are correct. 2. Pn preserves behaviors of all P1 ≤ i ≤ n .
Completeness: Subsumes Owicki-Gries [Nieto, 2007]
. . .
check
P1 PnP2
Correct
QED: Simplifier; complements other methods
8
acquire(lock);
t := x;
t := t + 1;
x := t;
release(lock);
acquire(lock);
k := x;
k := k + 1;
x := k;
release(lock);
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);
}
x := 0;
assert x == 2;
||
x := 0;
x := x + 1;
x := x + 1;
assert x == 2;
Simpler Owicki-Gries(4 location invariants)
Correct
Sequential analysis
Correct
Owicki-Gries(12 location invariants)
Correct
QED-verifier
reduceabstract
.....reducecheck
http://qed.codeplex.com
Correct
9
...P1 PnP2
P1
Pn
Proof script Boogie 2, Z3
QEDPLprogram
Automation using SMT solver
VC Valid
10
reduce abstract reduce
check
P1 PnP2
VC Valid VC Valid
CorrectVCValid
. . .
ActionPL11
Program:
Procedure bodies
Program’s main body
Global variables
Syntax:
Gated actions12
x = x + 1;
assert (x != 0);y = y / x;
x = x + 1;assert (x != 0);y = y / x;
Transition:Two-store relation
Gate:Assertion on pre-state
Semantics of ActionPL13
Pre-storeviolates assertion
Pre-store satisfies assertion
Pre- and post-store satisfies transition
Current dynamic statement
Current store
Execution:
Atomic transitions:
Operational semantics14
Proof method15
Current program
Program invariant (proof ensures this) Each execution starts from invariant Each transition preserves invariant
Proof context
Proof step: Governed by a proof rule May strengthen invariant May rewrite program
QED Program Transformations16
QED: Deciding Mover Types17
QED Transformations: Abstraction
I,P I,P’
• P’ : Atomic statement [ S ] in P replaced with [ S’ ]
• When?
• When atomic statement [S’] abstracts statement [S]
18
19
QED’s Idea of Abstraction
If for all :
errors1 errors11. If then
s12. If thens2 s1 s2
or errors1
s1
– Going wrong more often is sound for assertion checking
abstracted by
19
20
Flavors of Abstraction
if (x == 1) y := y + 1;
if (*) y := y + 1;
Adding non-determinism
Adding assertions (more “wrong” behaviors)
t := x; havoc t;
assume x != t; skip;
assert (lock_owner == tid);x := t + 1;x := t + 1;
20
“Read abstraction”
QED Transformations: Reduction
[ S1; S2]
[ S1 ; S2 ]
[ S1 ] ; [ S2 ]
[ S1 ] || [ S2 ]
I,P I,P’
21
If [S1] and [S2] are actions of correct mover types
P
P
P’
P’
22
Reduction ;
... 1 2 ... n ; ...
right-mover:
For each execution:
Exist equivalent executions:
... 1 2 ... n ...
... 1 2 ... n ... ...........
... 1 2 ... n ...
;
22
Use of movers in reduction
23
reduce
acquire(lock);
k := x;
k := k + 1;
x := k;
release(lock);
atomic { acquire(lock); t := x; t := t + 1; x := t; release(lock);}
acquire(lock) t := x t := t + 1; release(lock)... ... ......
acquire(lock) t := x t := t + 1 release(lock)... ... ... ......
R B
E1:
E2:
x := t...
x := t
E1 ≈ E2 Reason about only E2
B B L
Right-mover
Both-mover
Both-mover
Both-mover
Left-mover
Mover check in QED: Static, local, semantic
24
...
...
First-order verification condition
For each
;
...
Right-mover ?A
A B ;B A
B :
S1 S2 S3
S1 T2 S3
A B
B A
All actions in programrun by different thread
Traditional use of reduction [Lipton, 1975]
25
S1 S2 S3acquire y
S1 T2 S3acquirey
S1 T2 S3release x
S1 S2 S3releasex
Right-mover Left-mover
S1 S2 S3locked access y
S1 T2 S3locked-accessy
S1 T2 S3locked access x
S1 S2 S3locked accessx
Both-mover Both-mover
26
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
26
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 about
acq(L) acq(L) acq(L) acq(L)
• Both LHS and RHS block• No execution has
two consecutive acq(L)’s
S1 S2 S3acquire y
S1 T2 S3acquirey
S1 T2 S3release x
S1 S2 S3releasex
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?
29
Static mover check fails: Apparent conflict
acquire (lock);
t1 := x;
t1 := t1 + 1;
x := t1;
release(lock);
acquire (lock);
t2 := x;
t2 := t2 + 1;
x := t2;
release(lock);
• 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
29
30
Auxiliary variable: Which thread holds the lock?
inc (): acquire (lock);
t1 = x;
t1 = t1 + 1
x = t1;
release(lock);
inc (): acquire (lock); a := tid;
t2 = x;
t2 = t2 + 1
x = t2;
release(lock); a := 0;
AUX-ANNOTATE
New invariant: (lock == true) (a != 0)
• Auxiliary variable a is a history variable• Summarizes relevant part of execution history
30
31
Annotating Actions with Assertions
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
Invariant: (lock == true) (a != 0)
• Assertions indicate belief about non interference• Annotate actions locally with global information about execution
31
History Variable Annotations Make Static Mover Check Pass
32
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;
R
B
B
B
L
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;
• assert a == tid1; x := t1; and assert a == tid2; x := t2; commute
• α β β α • Because both α β and β α result in assertion violations.
32
33
Borrowing and paying back 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;
REDUCE-SEQUENTIAL, DISCHARGE ASSERTIONS
R
B
B
B
L
Dischargesthe assertions
Invariant: (lock == true) (a != 0)
33
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
with actions already in the data structure• Currently thread local access with all actions
• Assertions annotate action with reason for non-interference
35
Semantic Reduction: Ruling out Apparent Interference
assert !possiblyInList[t1];t1.next := n1;
assert possiblyInList[p2];n2 := p2.next;
• 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;
• If p2 and t1 refer to the same node:
• LHS and RHS lead to assertion violations (i.e., not possible)
• Otherwise, no conflict.
35
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 int db) { int va, 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; } }}
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 int db) { int va, 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; } }}
Left Mover
Right MoverRight Mover
Left Mover
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 int db) { int va, 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; } }}
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 int db) { int va, 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; } }}
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 int db) { atomic { havoc da, db, s; if (s) { da := m[a].d; db := m[b].d; } }}
Hide va, vb
Abstraction + Reduction: Increment with CAS
42
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; } ]
42
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 [Treiber 86]• 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]
43
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);
44
tressa : Temporal Dual of assert
• Example: y := y+1; // x == 0 or execution blocks z := 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!
45
tressa : Temporal Dual of assert
• Example: y := y+1; // x == 0 or execution blocks z := 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 φ
46
47
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;
REDUCE & RELAX
R
B
B
B
L
Pair Snapshot Example: Write
public void Write(int a, int d)
{
atomic{
m[a].d = d; // Write data
m[a].v++; // Increment version number
}
}
48
if TrySnapshot ends with s == true
TrySnapshot(int a, 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; }
}
49
a not written to b not
written to
(da,db) isa consistentsnapshot
Other Work on QED
• Variable hiding
• Linearizability-preserving soundness theorem
• Annotation assistance: • Automating proofs for simple programs• Common synchronization idioms
• Handling relaxed memory models [Ongoing]
50