50
Generalizing Reduction and Abstraction to Simplify Concurrent Programs: The QED Approach Shaz Qadeer Microsoft Research Redmond, WA Serdar Taşıran, Tayfun Elmas, Ali Sezgin Koç University Istanbul, Turkey http ://qed.codeplex.com [POPL ’09, TACAS ‘10, PADTAD ‘10, VSTTE ‘10]

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

  • 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

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

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]

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

QED: Simplify (coarsen), then verify

2

. . .

check

P1 PnP2

Correct

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

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

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

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

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

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

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

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

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

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

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

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

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

QED-verifier

reduceabstract

.....reducecheck

http://qed.codeplex.com

Correct

9

...P1 PnP2

P1

Pn

Proof script Boogie 2, Z3

QEDPLprogram

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

Automation using SMT solver

VC Valid

10

reduce abstract reduce

check

P1 PnP2

VC Valid VC Valid

CorrectVCValid

. . .

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

ActionPL11

Program:

Procedure bodies

Program’s main body

Global variables

Syntax:

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

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

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

Semantics of ActionPL13

Pre-storeviolates assertion

Pre-store satisfies assertion

Pre- and post-store satisfies transition

Current dynamic statement

Current store

Execution:

Atomic transitions:

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

Operational semantics14

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

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

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

QED Program Transformations16

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

QED: Deciding Mover Types17

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

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

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

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

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

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”

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

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’

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

22

Reduction ;

... 1 2 ... n ; ...

right-mover:

For each execution:

Exist equivalent executions:

... 1 2 ... n ...

... 1 2 ... n ... ...........

... 1 2 ... n ...

;

22

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

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

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

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

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

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

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

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

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

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

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

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?

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Atomic Snapshot

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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