46
1 Eran Yahav Mooly Sagiv School of Computer Science Tel-Aviv University {yahave,msagiv}@post.tau.ac.il http://www.cs.tau.ac.il/~yahave Automatically Verifying Concurrent Queue Algorithms

Automatically Verifying Concurrent Queue Algorithms

  • Upload
    hayden

  • View
    43

  • Download
    0

Embed Size (px)

DESCRIPTION

Automatically Verifying Concurrent Queue Algorithms. Eran Yahav Mooly Sagiv School of Computer Science Tel-Aviv University {yahave,msagiv}@post.tau.ac.il http://www.cs.tau.ac.il/~yahave. Automatically Verifying Partial Correctness of Software using Abstract Interpretation. - PowerPoint PPT Presentation

Citation preview

Page 1: Automatically Verifying Concurrent Queue Algorithms

1

Eran Yahav Mooly SagivSchool of Computer Science

Tel-Aviv University

{yahave,msagiv}@post.tau.ac.ilhttp://www.cs.tau.ac.il/~yahave

Automatically Verifying Concurrent Queue Algorithms

Page 2: Automatically Verifying Concurrent Queue Algorithms

2

Automatically Verifying Partial Correctness of Softwareusing Abstract Interpretation

Operates on the program source Fully automatic Conservative results

No errors are reported partial correctness is guaranteed

But may produce “false alarms”Makes the results non-useful

The Challenge avoid false alarms

Page 3: Automatically Verifying Concurrent Queue Algorithms

3

Concurrent Queues

A common component of concurrent systems Operating systems

A large number of suggested algorithmsHard to get right

[Stone90] – races + items may be lost [Valois94] – items may be lost …

Mostly given without formal proof of correctness

Page 4: Automatically Verifying Concurrent Queue Algorithms

4

Automatically Verifying Concurrent Queue Algorithms?

Support the following Concurrency Dynamic allocation/deallocation of objects Destructive updates Heap references Unbounded storage (heap) Dynamic allocation/deallocation of threads

Handling references with sufficient precision for establishing correctness properties Preceding pointer-analysis phase usually

insufficient

Page 5: Automatically Verifying Concurrent Queue Algorithms

5

Example [Michael&Scott PODC96]

public void enqueue(Object value) { e_1 node = new QueueItem() // allocate queue nodee_2 node.val = value // copy enqueued value into nodee_3 node.next.ref = NULL e_4 while(true) { // Keep trying until done e_5 tail = this.Tail // get Tail.ptr and Tail.count e_6 next = tail.ref.next // get next ptr and count e_7 if (tail == this.Tail) { // are tails consistent?e_8 if (next.ref == NULL) { // was tail pointing to last node?e_9 if CAS(tail.ref.next,

next, <node, next.count+1>) { // try connecte_10 break // Enqueue is done. Exit loop e_11 }e_12 } else { // tail wasn’t pointing to last

nodee_13 CAS(this.Tail, tail,<next.ref, tail.count+1>) // try advance taile_14 } e_15 } e_16 } e_17 CAS(this.Tail, tail, <node, tail.count+1>) //enqueue done. try swing tail e_18 }

Page 6: Automatically Verifying Concurrent Queue Algorithms

6

Correctness

P1 The linked list is always connectedP2 Nodes are only inserted after the last

node of the linked listP3 Nodes are only deleted from the

beginning of the linked listP4 Head always points to the first node in

the linked listP5 Tail always points to a node in the linked

list

Page 7: Automatically Verifying Concurrent Queue Algorithms

7

Rich Problem Expressive Formalism

We use first-order logic with transitive closure

Naturally define behavior of heap-manipulating programs Heap references Heap Reachability Threads as heap-allocated objects (and

scheduling)

Can also model integers

Page 8: Automatically Verifying Concurrent Queue Algorithms

8

Plan

Vanilla verification attempt Program configurations Expressing safety properties Abstraction

Refining the vanilla solution Instrumentation predicates

Prototype implementation (TVLA/3VMC)

Page 9: Automatically Verifying Concurrent Queue Algorithms

9

Configurations

A program configuration encodes global store program-location of every thread status of locks and threads

First-order logical structures used to represent program configurations

Page 10: Automatically Verifying Concurrent Queue Algorithms

10

Configurations as First-order Logical Structures

First-order structure Objects - Individuals properties of objects – unary predicates relationship between objects – binary predicates Additional integrity constraints FO formulas

Object Type – unary predicates References between objects – binary predicates

Thread Program location – unary predicates

Integers Distinguished zero individual – unary predicate Successor relationship – binary predicate With integrity constraints corresponding to Peano axioms

Page 11: Automatically Verifying Concurrent Queue Algorithms

11

at[e_2]

at[e_2]

zerosuccsucc succ

rv[node]

rv[node]

rv[this]

rv[this]

rv[Head] rv[next] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]

iv[next]iv[next]

Concrete Configuration

rv[value]

rv[value]

Page 12: Automatically Verifying Concurrent Queue Algorithms

12

Configurations

Predicates model properties of interest eq(v1,v2) is_T(v) { at[lab](t) : lab Labels } { rv[fld](o1,o2) : fld Fields }

{ iv[fld](o1,o2) : fld Fields } heldBy(l,t), blocked(t,l), waiting(t,l) zero(v), succ(v1,v2)

Can use the framework with different predicates

Page 13: Automatically Verifying Concurrent Queue Algorithms

13

Safety PropertiesProperty Property Formula

P1 Tail reachable from Head

q:nbq,vt. rv[Tail](q,vt)

vh. rv[Head](q,vh) rv[next]*(vh, vt)

P2 Insert after last

q:nbq,ti:thread,vi,vt. at[e_18](ti) rv[node](ti,vi) rv[tail](ti,vt)

rv[this](ti,q) rv[next](vt,vi) rv[Tail](q,vi)

P3 Delete first

q:nbq,td:thread,vd,vh. at[d_19](td) rv[head](td,vd)

rv[this](td,q) rv[Head](q,vh) rv[next](vd,vh)

P4 Head first q:nbq,v,u. rv[Head](q,v) rv[next](u,v)

P5 Tail exists

q:nbq. v. rv[Tail](q,v)

Page 14: Automatically Verifying Concurrent Queue Algorithms

14

at[e_2]

at[e_2]

zerosuccsucc succ

rv[node]

rv[node]

rv[this]

rv[this]

rv[Head] rv[next] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]

iv[next]iv[next]

Tail Reachable from Head

Vh Vt

q:nbq,vt. rv[Tail](q,vt)

vh. rv[Head](q,vh) rv[next]*(vh, vt)

rv[value]

rv[value]

Page 15: Automatically Verifying Concurrent Queue Algorithms

15

Abstract Program Model

Conservative representation of the concrete model

Use 3-valued logical structures to conservatively represent multiple 2-valued structures 1 = true 0 = false 1/2 = unknown A join semi-lattice, 0 1 = 1/2

Conservatively apply actions on abstract configurations

Page 16: Automatically Verifying Concurrent Queue Algorithms

16

at[e_2]

at[e_2]

zerosuccsucc succ

rv[node]

rv[node]

rv[this]

rv[this]

rv[Head] rv[next] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]

iv[next]iv[next]

Concrete Configurationrv[value]

rv[value]

Page 17: Automatically Verifying Concurrent Queue Algorithms

17

zerosucc

rv[Head]

iv[Tail]

iv[Head]

Abstract Configuration

at[e_2]

rv[this]

iv[next]

rv[node]

rv[this]

rv[next]

succ

rv[Tail]

rv[value]

Page 18: Automatically Verifying Concurrent Queue Algorithms

18

canonical Abstraction

Merge all nodes with the same unary predicate values into a single summary node

Join predicate valuesConverts a configuration of infinite size

into a 3-valued abstract configuration of bounded size

Page 19: Automatically Verifying Concurrent Queue Algorithms

19

at[e_2]

at[e_2]

zerosuccsucc succ

rv[node]

rv[node]

rv[this]

rv[this]

rv[Head] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]

iv[next]

Concrete Bad Configuration

q:nbq,vt. rv[Tail](q,vt) vh. rv[Head](q,vh) rv[next]*(vh, vt)

rv[value]

rv[value]

Page 20: Automatically Verifying Concurrent Queue Algorithms

20

at[e_2]

zerosucc

rv[Head]

iv[Tail]

iv[Head]

Abstract Configuration

at[e_2]

rv[this]

iv[next]

rv[this]

rv[next]

succ

rv[Tail]

q:nbq,vt. rv[Tail](q,vt) vh. rv[Head](q,vh) rv[next]*(vh, vt)

rv[node]

rv[value]

Page 21: Automatically Verifying Concurrent Queue Algorithms

21

Instrumentation

Refine the abstraction by recording additional information

Natural idea – record which property-formulae hold via nullary predicates Corresponds to predicate abstraction

More generally – record subformulae that hold for an individual via unary predicates Obtain (some) useful results without changing

set of predicates per program/property

Page 22: Automatically Verifying Concurrent Queue Algorithms

22

Instrumentation Predicates

Predicate Intended Meaning Defining Formula

is[fld](o) o is shared by fld of at least two different objects

v1,v2.eq(v1,v2) rv[fld](v1,o) rv[fld](v2,o)

exists[fld](o)

There exists an object referenced by fld of o

v.rv[fld](o,v)

is_acquired(l)

l is acquired by some thread t.heldBy(l,t)

rt[fld,n](o) o is reachable from object referenced by fld using a path of next fields

t,ot.rv[fld](t,ot) rv[next]*(ot,o)

r_by[fld](o) o is referenced by fld of some object

v.rv[fld](v,o)

i_by[fld](o) o is int value of fld of some object

v.iv[fld](v,o)

Page 23: Automatically Verifying Concurrent Queue Algorithms

23

r_by[node]rt[node,n]

is[this]r_by[this]rt[this,n]

r_by[node]rt[node,n]

r_by[head]rt[head,n]

r_by[next]rt[Head,n]

r_by[next]rt[Head,n]

r_by[next]r_by[Tail]rt[Head,n]rt[Tail,n]

at[e_2]

at[e_2]

zeroi_by[…]

succsucc succ

rv[node]

rv[node]

rv[this]

rv[this]

rv[Head] rv[next] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]

iv[next]iv[next]

Instrumented Concrete Configuration

r_by[value]rt[value,n]

r_by[value]rt[value,n]

rv[value]

rv[value]

Page 24: Automatically Verifying Concurrent Queue Algorithms

24

r_by[node]rt[node,n]

is[this]r_by[this]rt[this,n]

r_by[Head]rt[Head,n]

r_by[next]rt[Head,n]

r_by[next]r_by[Tail]rt[Head,n]rt[Tail,n]

at[e_2]

rv[node]

rv[this]

rv[Head] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]iv[next]rv[next]

succ

succ

Instrumented Abstract Configuration

zeroi_by[…]

q:nbq,vt. rv[Tail](q,vt)

vh. rv[Head](q,vh) rv[next]*(vh, vt)q:nbq,v. rv[Tail](q,v) rt[Head,n](v)

r_by[value]rt[value,n]rv[value]

Page 25: Automatically Verifying Concurrent Queue Algorithms

26

Best Conservative Interpretation

Concrete Representati

on

Concrete Representati

on

Concretization Abstraction

Operational Semantics

[|S|]

Abstract Representati

on

Abstract Representati

onAbstract Semantics

[|S|]

Page 26: Automatically Verifying Concurrent Queue Algorithms

27

r_by[node]rt[node,n]

is[this]r_by[this]rt[this,n]

r_by[Head]rt[Head,n]

r_by[next]rt[Head,n]

r_by[next]r_by[Tail]rt[Head,n]rt[Tail,n]

at[e_2]

rv[node]

rv[this]

rv[Head] rv[next] rv[next]

rv[Tail]

iv[Tail]

iv[Head]

iv[next]iv[next]rv[next]

succ

succ

zeroi_by[…]

r_by[value]rt[value,n]rv[value]

Abstract Interpretation - Concretizatione_2 node.val = value

Page 27: Automatically Verifying Concurrent Queue Algorithms

28

r_by[node]rt[node,n]at[e_2]

rv[node]

Abstract Interpretation - Concretizationr_by[value]rt[value,n]rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

e_2 node.val = value

Page 28: Automatically Verifying Concurrent Queue Algorithms

29

Abstract Interpretation - update

r_by[node]rt[node,n]exists[val]

at[e_3]rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

rv[value]

r_by[node]rt[node,n]exists[val]

at[e_3]rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]exists[val]

at[e_3]rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

r_by[node]rt[node,n]at[e_2]

rv[node]

r_by[value]rt[value,n]

rv[value]

…rv[val]

rv[value] rv[value]

e_2 node.val = value

Page 29: Automatically Verifying Concurrent Queue Algorithms

30

r_by[node]rt[node,n]

at[e_2]

rv[node]

Abstract Interpretation - abstraction

r_by[value]rt[value,n]rv[value]

at[e_3]

rv[value]

rv[val]

rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

r_by[node]rt[node,n]exists[val]

at[e_3]

rv[value]

rv[val]

rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

r_by[node]rt[node,n]exists[val] r_by[node]

rt[node,n]

at[e_2]

rv[node]

r_by[value]rt[value,n]rv[value]

at[e_3]

rv[value]

rv[val]

rv[node]

r_by[value]rt[value,n]r_by[val]rt[val,n]

r_by[node]rt[node,n]exists[val]

Page 30: Automatically Verifying Concurrent Queue Algorithms

31

Prototype Implementation

TVLA/3VMCfocuscoerceLimitations

only intraprocedural no optimizations used

No partial-order reduction

Page 31: Automatically Verifying Concurrent Queue Algorithms

32

Experimental Results

Program Configs Space (MB)

Time (Sec)

Nbq_enqueue 1833 14.2 727

Nbq_dequeue 1098 5.3 309

Nbq_err1 36 0.1 11

Nbq_uni 17 0.1 3

Tlq_enqueue 982 10 6162

Tlq_dequeue 225 4.1 304

Twolockqn 975 7.5 577

Twolockq_err1 24 0.1 30

Page 32: Automatically Verifying Concurrent Queue Algorithms

33

Conclusions

Common challenges of model checking and abstract interpretation False alarms Cost Scalability

Size Language features

Page 33: Automatically Verifying Concurrent Queue Algorithms

34

Conclusions

Traditional MC Our Approachconcrete configuration

propositional FOTC

abstraction model extraction*abstract interpretation

control flowinternally represented

internally represented

materialization ? basic featureobject number a priori bounded unbounded

thread numberfixed or a priori bounded

unbounded

abstraction refinement

yes ?

Page 34: Automatically Verifying Concurrent Queue Algorithms

35

Summary

Verified interesting safety properties of concurrent queues

Unbounded number of objects and threads

Dynamic allocation of objects and threads

Page 35: Automatically Verifying Concurrent Queue Algorithms

36

http://www.cs.tau.ac.il/~yahave

Page 36: Automatically Verifying Concurrent Queue Algorithms

37

Integer Representation - Concrete

zerosuccsucc succ

iv[y]iv[x]

y++

x == y ?

yes

zerosuccsucc succ

iv[y]

iv[x]x == y ?

no

Page 37: Automatically Verifying Concurrent Queue Algorithms

38

Integer Representation – No Instrumentation

zerosuccsucc succ

iv[y]iv[x]

y++

x == y ?

yes

zerosuccsucc succ

iv[y]iv[x]

x == y ?

no

Page 38: Automatically Verifying Concurrent Queue Algorithms

39

Integer Representation – No Instrumentation

zerosucc

iv[y]iv[x]

y++

x == y ?

maybe

x == y ?

maybe

succ

zerosucc

iv[y]iv[x]

succ

Page 39: Automatically Verifying Concurrent Queue Algorithms

40

Integer Representation – With Instrumentation

zerosuccsucc succ

iv[y]iv[x]

y++

x == y ?

yes

zerosuccsucc succ

iv[y]iv[x]

x == y ?

no

i_by[x]i_by[y]

i_by[x] i_by[y]

Page 40: Automatically Verifying Concurrent Queue Algorithms

41

Integer Representation – With Instrumentation

zerosucc

iv[y]

iv[x]

y++

x == y ?

yes

x == y ?

no

succ

succ

zerosucc

iv[y]

iv[x]

succ

succ

succi_by[x] i_by[y]

i_by[x]i_by[y]

Page 41: Automatically Verifying Concurrent Queue Algorithms

42

Backup Slides

Page 42: Automatically Verifying Concurrent Queue Algorithms

43

References

[Stone90] J.M. Stone. A simple and Correct Shared-Queue

Algorithm using compare-and-swap. In Proceedings of Supercomputing ’90, November 1990.

[Valois94] J.D. Valois. Implementing Lock-Free Queues. In

Seventh international Conference on Parallel and Distributed Computing Systems, Las Vegas, NV, October 1994

Page 43: Automatically Verifying Concurrent Queue Algorithms

44

Structural Operational Semantics - actions

An action consists of: precondition formula update formulae

Precondition formula may use a free variable ts for “currently scheduled” thread

Semantics is non-deterministic

Page 44: Automatically Verifying Concurrent Queue Algorithms

45

Structural Operational Semantics - actions

lock(v)

tts: rval[v](ts,l) held_by(l,t)

held_by’(l1,t1) = held_by(l1,t1) (l1 = l t1 = ts)

blocked’ (t1,l1) = blocked(t1,l1) ((l1 l) (t1 ts))

precondition

predicateupdate

Page 45: Automatically Verifying Concurrent Queue Algorithms

46

Initialize(C0) {for each C C0

push(stack,C)}explore() { while stack is not empty { C = pop(stack) if not member(C,stateSpace) { verify(C) stateSpace = stateSpace {C} for each action ac for each C’ such that C ac C’ push(stack,C’) } }}

State Space Exploration

Page 46: Automatically Verifying Concurrent Queue Algorithms

47

Unbounded Number of Threads

Exploit state-space symmetryPrevious work defined symmetry between

process names (indices)Thread location = thread propertycanonical names = symmetry between

properties