QED: A Simplifier for Concurrent Programs

1 / 42

# QED: A Simplifier for Concurrent Programs - PowerPoint PPT Presentation

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

I am the owner, or an agent authorized to act on behalf of the owner, of the copyrighted work described.

## PowerPoint Slideshow about ' QED: A Simplifier for Concurrent Programs' - aric

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.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.

- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -
Presentation Transcript

### QED: A Simplifier for Concurrent Programs

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
• difficult to detect, reproduce, eliminate
• Correctness problem
• does program behave correctly for allinputs and allinterleavings?

Undecidable problem!

P satisfies S

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

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:

[email protected]x=c,[email protected]x=c+1

[email protected]x=c, [email protected]x=c+1

[email protected]x=c,[email protected]x=c+1,

held(l, A)

[email protected]x=c, [email protected]x=c+1,

held(l, B)

[email protected]x=c,[email protected]x=c+1,

held(l, A), t=x

[email protected]x=c, [email protected]x=c+1,

held(l, B), t=x

[email protected]x=c,[email protected]x=c+1,

held(l, A), t=x+1

[email protected]x=c, [email protected]x=c+1,

held(l, B), t=x+1

[email protected]x=c+1,[email protected]x=c+2,

held(l, A)

[email protected]x=c+1, [email protected]x=c+2,

held(l, B)

[email protected]x=c+1,[email protected]x=c+2

[email protected]x=c+1, [email protected]x=c+2

• post x=c+2;
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);

??

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

[email protected]x=c,[email protected]x=c+1

[email protected]x=c, [email protected]x=c+1

[email protected]x=c+1,[email protected]x=c+2

[email protected]x=c+1, [email protected]x=c+2

• post x=c+2;
Intuitive reasoning with atomic actions
• pre x=c;

atomic { x := x + 1; }

atomic { x := x + 1; }

• post x=c+2;
Intuitive reasoning with atomic actions
• pre x=c;

atomic { x := x + 1; }

atomic { x := x + 1; }

• post x=c+2;

Verify using sequential methods!

QED
• Do not verify the original 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
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]; }

}

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

}

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

}

}

QED transformations

I,P

I’,P’

Strengthen invariant

Reduce program

Abstract program

Rule 1: Strengthen invariant

I,P

I’,P

I’  I

Rule 2: Reduce program

I,P

I,P’

atomic { A} ; atomic { B }

atomic { A ; B }

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;

}

}

R*

.

x

.

N

.

Y

.

L*

S0

S5

R*

.

.

.

Y

x

.

N

L*

S0

S5

Reduction theorem

Sequence R*;(N+); L*is atomic

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

QED tool

[http://qed.codeplex.com]

P1

P2

Pn

P1

...

QED

Correct

Pn

reduce

abstract

.....

reduce

check

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]
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!

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

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

}

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

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

}

}

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;

}

}

}

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

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;

}

}

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;

}

}

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;

}

}

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;

}

}

bool held;

int owner;

procedure acquire() {

atomic { assume held == false; held := true; }

owner := tid;

}

procedure release() {

atomic {

assert owner == tid; owner := 0;

held := false;

}

}

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

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;

}

}

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

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;

}

}

int owner;

procedure acquire() {

atomic { assume owner == 0; owner := tid; }

}

procedure release() {

atomic { assert owner == tid; owner := 0; }

}

Hide held

Conclusions
• QED: A simplifier for concurrent programs
• Do not verify the original program