proving data race freedom in relaxed memory models

59
Proving Data Race Freedom in Relaxed Memory Models Beverly Sanders Computer & Information Science & Engineering

Upload: byron-harper

Post on 01-Jan-2016

19 views

Category:

Documents


2 download

DESCRIPTION

Proving Data Race Freedom in Relaxed Memory Models. Beverly Sanders. Computer & Information Science & Engineering. Overview. Motivation Memory models and data races Simple multi-threaded programming language and logic Extensions to allow reasoning about data races Example - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Proving Data Race Freedom in Relaxed Memory Models

Proving Data Race Freedom in Relaxed Memory Models

Beverly Sanders

Computer & Information Science & Engineering

Page 2: Proving Data Race Freedom in Relaxed Memory Models

2

Overview

• Motivation• Memory models and data races• Simple multi-threaded programming

language and logic• Extensions to allow reasoning about data

races• Example• Conclusions and future work

Page 3: Proving Data Race Freedom in Relaxed Memory Models

3

Concurrent programming is hard

• non-deterministic• non-reproducible• operational reasoning unreliable

• It is becoming more commonplace• It is getting harder—relaxed

memory models

Page 4: Proving Data Race Freedom in Relaxed Memory Models

4

Sequential consistency

• Virtually all approaches for reasoning about concurrent program, both formal and informal assume SC

• Lamport(1979)– All operations appear to execute in some

sequential order– All operations on a single thread appear to

execute in the order specified by the program

Page 5: Proving Data Race Freedom in Relaxed Memory Models

5

Modern systems are not SC

• Optimizations (both by compiler and hardware) that preserve semantics of sequential programs may violate SC– reorder statements– buffered writes– …

Page 6: Proving Data Race Freedom in Relaxed Memory Models

6

ExampleInitially:

int x = 0;

boolean done = false

Thread 0:

x := ….

done := true;

Thread 1:

int r;

while (!done){/*busywait*/}

r := x;

Page 7: Proving Data Race Freedom in Relaxed Memory Models

7

ExampleInitially:

int x = 0;

boolean done = false

Thread 0:

done := true;

x := ….

Thread 1:

int r;

while (!done){/*busywait*/}

r := x;

Statements reordered. OK in sequential program but not in this one

Page 8: Proving Data Race Freedom in Relaxed Memory Models

8

ExampleInitially:

int x = 0;

boolean done = false

Thread 0:

x := ….

done := true;

Thread 1:

r0 = done;

while (!r0){/*busywait*/}

r := x;

Loop optimized by compiler. Ok in sequential program but not this one

Page 9: Proving Data Race Freedom in Relaxed Memory Models

9

Solutions?

• Bad solution: require system to implement SC– unacceptable loss of performance

• Better: provide mechanisms for the programmer to constrain non-SC behavior– explicit “fence” or “memory barrier” instructions– intrinsic

• lock and unlock instructions• volatile variables

– But then we should be able to verify that program is sufficiently constrained

Page 10: Proving Data Race Freedom in Relaxed Memory Models

10

Memory model

• Specification of how threads interact with the memory

• Traditionally, memory models have been specified for architectures

• Recently, memory models have become part of the programming language semantics.– Java is the most ambitious attempt to date

– Seems simple at first glance, but experience has shown it is hard to understand

Page 11: Proving Data Race Freedom in Relaxed Memory Models

11

Simple memory model

• Based on the happened-before relation (Lamport)• Inspired by the Java Memory Model

– an event happens-before another event on the same thread if it occurs earlier in the program order.

– writing a volatile variable happens-before subsequent reads of the variable

– unlocking a lock happens-before subsequent locks on the same lock

– happened-before is transitive

Page 12: Proving Data Race Freedom in Relaxed Memory Models

12

Thread 0 Thread 1

write x

write doneread done

read x

happened before edge

Page 13: Proving Data Race Freedom in Relaxed Memory Models

13

Thread 0 Thread 1

write x

write doneread done

read x

happened before edge

done is volatile

Page 14: Proving Data Race Freedom in Relaxed Memory Models

14

Thread 0 Thread 1

write x

write doneread done

read x

happened before edge

done is volatile

Page 15: Proving Data Race Freedom in Relaxed Memory Models

15

Definition of data race

• Conflicting accesses to the same variable that are not ordered by happens-before – Accesses to a variable conflict if they are performed by

different threads and at least one is a write

– Remark: term “race” is overloaded.– Sometimes it means any undesirable concurrency caused

nondeterminism (which often comes from not using locks properly to enforce atomicity)

– A program with no data races may still exhibit undesirable non-determinism.

Page 16: Proving Data Race Freedom in Relaxed Memory Models

16

Thread 0 Thread 1

write x

write doneread done

read x

happened before edgedata race

Page 17: Proving Data Race Freedom in Relaxed Memory Models

17

Thread 0 Thread 1

write x

write doneread done

read x

happened before edge

done is volatile

Page 18: Proving Data Race Freedom in Relaxed Memory Models

18

Fundamental property

• If there are no data races in any sequentially consistent execution, then the program will behave as if it is sequentially consistent.

Page 19: Proving Data Race Freedom in Relaxed Memory Models

19

• What about programs with data races?– Some systems leave behavior undefined– The Java memory model also constrains the

behavior of programs with data races• includes a notion of causality

• no "out of thin air" values

• safety

• Our goal is to prove the absence of data races, so we are not concerned with the behavior of programs with data races

Page 20: Proving Data Race Freedom in Relaxed Memory Models

20

Difficulties• It is difficult to reason about partial orders imposed

on execution paths• Need data race freedom on all paths• In most work, one settles for satisfying sufficient

constraints• all accesses to a particular shared variable are protected by a

common lock

• variable is volatile

– Even "simple" rules are difficult to get right

– Rules out important programming idioms

Page 21: Proving Data Race Freedom in Relaxed Memory Models

21

Proving data race freedom

• Extend known assertional methods – Start with very simple multithreaded

programming language (similar to Plato and BoogiePL)

– Extend the state space with a "happened-before" function that tracks information about happened-before edges

– Race-free access can be expressed as assertion– Prove in the usual way

Page 22: Proving Data Race Freedom in Relaxed Memory Models

22

Simple multithreaded programming language

Program ::= Global* Volatile* Thread+

Thread ::= ThreadID Local* Stmt

Stmt ::= …

(no procedures or objects)

Page 23: Proving Data Race Freedom in Relaxed Memory Models

23

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

Page 24: Proving Data Race Freedom in Relaxed Memory Models

24

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

If E's value is true, continue, otherwise computation gets stuck.

Getting stuck is OK

Page 25: Proving Data Race Freedom in Relaxed Memory Models

25

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

If E's value is true, continue, otherwise computation "goes wrong".

Going wrong is NOT OK

Page 26: Proving Data Race Freedom in Relaxed Memory Models

26

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

Set the values of the given Vars to arbitrary values of their types

Page 27: Proving Data Race Freedom in Relaxed Memory Models

27

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

Nondeterministic choice

Page 28: Proving Data Race Freedom in Relaxed Memory Models

28

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

Sequential composition

Page 29: Proving Data Race Freedom in Relaxed Memory Models

29

Stmt ::=

Var ::= E

| assume E

| assert E

| havoc Var+

| skip

| Stmt [] Stmt

| Stmt ; Stmt

| < Stmt >

Statement is executed atomically

Page 30: Proving Data Race Freedom in Relaxed Memory Models

30

• This language is more expressive than it appears at first glance

if E then S0 else S1

can be represented as

assume E ; S0 [] assume ~E ; S1

Page 31: Proving Data Race Freedom in Relaxed Memory Models

31

while E do Swith invariant I, where S modifies only

variables in M

assert I; havoc M; assume I; assume E ; S0; assert I; assume false; [] assume ~E;

Page 32: Proving Data Race Freedom in Relaxed Memory Models

32

Weakest preconditions

wp.v := e.Q ≡ [e\v]Q

wp.assume e.Q ≡

wp.assert e.Q ≡ e /\ Q

wp.havoc v.Q ≡

wp.skip.Q ≡ Q

wp.s0 [] s1.Q ≡ wp.s0.Q /\ sp.s1.Q

wp.s0 ; s1.Q ≡ wp.s0.(wp.s1.Q)

Qe

Q:v

Page 33: Proving Data Race Freedom in Relaxed Memory Models

33

• {P} S {Q} ≡

• wp.S.Q0 /\ Q1 = wp.S.Q0 /\ wp.S.Q1

Q.wp.SP

Page 34: Proving Data Race Freedom in Relaxed Memory Models

34

Atomic Statements

• Implicitly atomic statements– satisfy "at most once rule"

• statement accesses as most one non-local variable at most once

• Explicitly atomic statement< S >

Assumption that must be satisfied by the implementation

• Well formed program: all assign, assert, assume, and havoc commands are implicitly atomic or are contained in an explicit atomic statement

Page 35: Proving Data Race Freedom in Relaxed Memory Models

35

Locks

• Can be specified using explicit atomic statements

lck : ThreadId + free

lck.lock = <assume lcl=free; lck := curr>lck.unlock = <assert lck = curr; lck := free>

where curr = current thread

Page 36: Proving Data Race Freedom in Relaxed Memory Models

36

(SC) Multithreaded Correctness

Thread0

{Initial}<S0>{P1}<S1>..{Pn}<Sn>{true}

Thread1

{Initial}<T0>{Q1}<S1>..{Qm}<Sm>{true}

1. Show each thread's proof outline is valid

2. Show non-interference (Owicki-Gries)

Page 37: Proving Data Race Freedom in Relaxed Memory Models

37

(SC) Multithreaded Correctness

Thread0

{Initial}<S0>{P1}<S1>..{Pn}<Sn>{true}

Thread1

{Initial}<T0>{Q1}<S1>..{Qm}<Sm>{true}

• Non-interference: no assertion in one thread is violated by an action in another.

• Need to check all assertions between atomic actions

Page 38: Proving Data Race Freedom in Relaxed Memory Models

38

(SC) Multithreaded Correctness

Thread0

{Initial}<S0>{P1}<S1>..{Pn}<Sn>{true}

Thread1

{Initial}<T0>{Q1}<S1>..{Qm}<Sm>{true}

Example: To show that S1 in Thread0 does not falsify Qm in the proof outline of Thread1

{P1 /\Qm}S1{Qm}

Page 39: Proving Data Race Freedom in Relaxed Memory Models

39

Extensions for memory-synchronization state

let h: globals+volatile+thread → {globals+volatile+thread}

where

)th'h('v''

means that thread th can access v without causing a data race

norace('th','v')

Page 40: Proving Data Race Freedom in Relaxed Memory Models

40

Updates to h

)t'h('else)v'h(')t'h('thenz''t''ifz'.λ'

h)v'',t'('acquire

)v'h('else)v'h(')t'h('thenz''v''ifz'.λ'

h)v'',t'('release

}v'{'\)z''h(else)z''h(thenz''v''z''t''ifz'.λ'

h)v'',t'('invalidate

Page 41: Proving Data Race Freedom in Relaxed Memory Models

41

Updates to h

)t'h('else)v'h(')t'h('thenz''t''ifz'.λ'

h)v'',t'('acquire

)v'h('else)v'h(')t'h('thenz''v''ifz'.λ'

h)v'',t'('release

}v'{'\)z''h(else)z''h(thenz''v''z''t''ifz'.λ'

h)v'',t'('invalidate

h('v') := h('v') U h('t')

h('t') := h('v') U h('v')

})''{\)''h( :)''h(:'''','''':''( vzztzvzz

Page 42: Proving Data Race Freedom in Relaxed Memory Models

42

Modify programming language

• add (function valued) ghost variable h

• statements replaced with new statements that also read and/or update h

• if the modified program does not "go wrong", it is free of data races

Page 43: Proving Data Race Freedom in Relaxed Memory Models

43

Volatile variables

• reading a volatile variable

<acquire (curr,'x‘); r := x;>

• writing a volatile variable x

<x := e; release(curr,'x')>

Page 44: Proving Data Race Freedom in Relaxed Memory Models

44

Global (non-volatile) variables

• reading global n

< assert norace(curr, 'n'); r := n; >

• writing global n

< assert norace(curr,'n'); n := r; invalidate(curr,'n')>

Page 45: Proving Data Race Freedom in Relaxed Memory Models

45

Locks

• Lock the lock variable lck

<acquire(curr,'lck'); lck.lock;>

• Unlock lck

<lck.unlock; release(curr,'lck')>

Page 46: Proving Data Race Freedom in Relaxed Memory Models

46

Proof rules

{norace('t1','y') \/ ('t0'='t1' /\ norace('x','y'))}

acquire('t0','x');

{norace('t1','y')}

{norace('t1','y') \/ ('x'='t1' /\ norace('t0','y'))}

release('t0','x');

{norace('t1','y')}

Page 47: Proving Data Race Freedom in Relaxed Memory Models

47

Proof rules

{norace('t1','y') /\ ('t0' = 't1' \/ 'x' ≠ 'y')}

invalidat('t0','x')

{norace('t1','y')}

Page 48: Proving Data Race Freedom in Relaxed Memory Models

48

Recall exampleInitially:

int x = 0;

boolean done = false

Thread 0:

x := ….

done := true;

Thread 1:

int r;

while (!done){/*busywait*/}

r := x;

Page 49: Proving Data Race Freedom in Relaxed Memory Models

49

Thread 0:{norace('Thread0','done') /\ norace('Thread0','x')<assert norace(Thread0’,'x');

x := 1; invalidate(Thread0’,'x') > {norace(Thread0,done)}

<assert norace(‘Thread0’,'done'); done := true; invalidate(‘Thread0’,'done'); >

{true}

done not volatile

Page 50: Proving Data Race Freedom in Relaxed Memory Models

50

Thread 1:

int r;

…while (!done){}

r := x;

Thread 1:

r0 := done;

assume !r0;

assume false;

[]

assume r0;

r := x

Page 51: Proving Data Race Freedom in Relaxed Memory Models

51

Thread 1:{norace(Thread1,done) /\

done => norace(Thread1,’x’)}

<assert norace(Thread1,done); r0 := done;>

{r0 => norace(Thread1,x)}

assume !r0; assume false;

[]

{r0 => norace(Thread1,x)}

assume r0;

{norace(Thread1,x)}

< assert norace(Thread1,x); r := x >

Page 52: Proving Data Race Freedom in Relaxed Memory Models

52

• Both proof outlines are valid in isolation, but not interference-free

• For example, this proof obligation does not hold

{norace(‘Thread0’,’done’) /\ norace(‘Thread1’,’done’) /\

done => norace(‘Thread1’,’x’)} <…..invalidate(curr,'done'); >{norace(‘Thread1’,’done’) /\

done => norace(‘Thread1’,’x’)}

Page 53: Proving Data Race Freedom in Relaxed Memory Models

53

Thread 0:{!done /\ norace('Thread0','x')<assert norace(Thread0’,'x');

x := 1; invalidate(‘Thread0’,'x') > {!done /\ norace(Thread0,done)} < done := true; release(‘Thread0’,'done'); >

{done /\ norace(‘done’,’x’} => {true}

done isvolatile

Page 54: Proving Data Race Freedom in Relaxed Memory Models

54

Thread 1:{done => norace(‘done’,’x’)}

<acquire(Thread1,’done’); r0 := done;>

{r0 => done /\ r0 => norace(Thread1,x)}

assume !r0; assume false;

[]

{r0 => done /\ r0 => norace(Thread1,x)}

assume r0;

{r0 /\ r0 => done /\ norace(Thread1,x)}

< assert norace(Thread1,x); r := x >

Page 55: Proving Data Race Freedom in Relaxed Memory Models

55

• Both proof outlines are valid in isolation• They are also interference-free• Example

{!done /\ norace('Thread0','x') /\ r0 /\ r0 => done /\ r0 =>norace(Thread1,x)}

<assert norace(Thread0’,'x'); x := 1; invalidate(‘Thread0’,'x') >

{r0 /\ r0 => done /\ r0 => norace(Thread1,x)}

Precondition is false, triple

holds trivially

Page 56: Proving Data Race Freedom in Relaxed Memory Models

56

Remarks• Other approaches to data race detection

cannot handle this example

• They try to show– locking protocol followed– shared variables are volatile

• This framework allows other information (invariants) to be incorporated into the analysis by strengthening assertions

Page 57: Proving Data Race Freedom in Relaxed Memory Models

57

• How can we find the strengthened assertions?– Just calculating wp from postcondition of true may not

be sufficient.

– Let the programmer provide it (like is sometimes done for loop invariants)

– Heuristics• track values (done)

• conjoined assumed value (r0)

• using the important invariants of program – (r0 => done)

– done => norace(‘done’,’x’)

– Identify common patterns• “effectively immutable x signaled by done”

Page 58: Proving Data Race Freedom in Relaxed Memory Models

58

Conclusions and future work

• More complete language model– Procedures – Objects

• h:location -> {location}– Byte code logic– Java memory model mentions

• static initialization• final fields• dynamic thread creation, join,…

• Reduce interference• Tool support

Page 59: Proving Data Race Freedom in Relaxed Memory Models

59

The end

Thanks for attending