verifying concurrent programs with relaxed conflict detection tayfun elmas, ismail kuru, serdar...
TRANSCRIPT
Verifying Concurrent Programs with Relaxed Conflict Detection
Tayfun Elmas, Ismail Kuru, Serdar Taşıran, Omer SubasiKoç University Istanbul, Turkey
2
Relaxed Conflict Detection• Pattern
– Traverse/Take snapshot of (large portion of) global state– Do local computation– Update small portion of global state
• Very common– Concurrent data structures– Parallelized optimization algorithms– Cloud computing– Performance optimizations for transactional memory
• Ignore WAR conflicts (Titos et al., HiPEAC ‘12)• Early release/early discard (e.g., Kozyrakis et al., WTW ‘06)
• Performance problem: Most operations conflict• Solution: Program so that some conflicts can be ignored• Verification problem: How do you reason about correctness?
Motivating Example: Sorted Linked List
1 3 6 9 12 15 17Head
5
16
Insert 5
Insert 16
Motivating Example: Sorted Linked List
1 3 6 9 12 15 17Head
5
16
Insert 5
Insert 16
1 3 6 9 12 15 17Head
READ
1 3 6 9 12 15 17Head
5
WRITE
READ
Write-After-Read
conflict
1 3 6 9 12 15 17Head
16
WRITEREAD
5
WRITE
Write-After-Read
conflict
1 3 6 9 12 15 17Head
16
WRITEREAD
• Conventional TM conflict detection enforces conflict serializability– Does WriteSet(Tx1) intersect (ReadSet(Tx1) + WriteSet(Tx2)) ?– Any two concurrent insertions conflict!
5
WRITE
Linked List: Insertlist_insert(list_t *listPtr, node_t *node) {
atomic {
*curr = listPtr->head; do {
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; prev->next = node;
}}
9
Transactional memory:• Optimistic concurrency• Track read and write accesses a
transaction performs– ReadSet(Tx1)– WriteSet(Tx1)
• Enforce conflict serializability
• At commit time for Tx1for all concurrent transactions Tx2, check
WriteSet(Tx2) (ReadSet(Tx1) WriteSet(Tx1)) =
– Abort and retry Tx1 otherwise
1 3 6 9 12 15 17Head
5
16• But, allowing both insertions OK even if we ignore WAR conflict• Conflict serializability too strict• Options:
– Fine-grain, hand-crafted concurrency– Transactional memory + relaxed conflict detection
• Relaxed conflict detection• Programmer tells TM to ignore this kind of conflict• Need to reason that this still results in a correct program
Write-After-Read
conflict
1 3 6 9 12 15 17Head
16
WRITEREAD
5
WRITE
Linked List: Insertlist_insert(list_t *listPtr, node_t *node) {
atomic {
*curr = listPtr->head; Readdo { phase
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; Writeprev->next = node; phase
}}
12
13
Linked List: Insertlist_insert(list_t *listPtr, node_t *node) {
atomic {
*curr = listPtr->head; do {
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
Strict conflict detection:
Can reason about transaction code sequentially.
14
Linked List: Insertlist_insert(list_t *listPtr, node_t *node) {
atomic [!WAR]{
*curr = listPtr->head; do {
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
Ignore Write-After-Readconflicts:
• Writes by others interfere with transaction
• Cannot reasonsequentially
1 3 6
5READ 6; WRITE 5
15
Arguing that the !WAR block is atomiclist_insert(list_t *listPtr, node_t *node) {
atomic [!WAR]{
*curr = listPtr->head; do {
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
Would like these actions to be “right movers”
• Can commute to the right of any actionby another thread
Atomicity of this block guaranteed by TM
• Write-write conflictsnot ignored
16
Making !WAR block atomiclist_insert(list_t *listPtr, node_t *node) {
atomic [!WAR]{
*curr = listPtr->head; do {
prev = curr; currT1 = currT1->next;
} while (curr != NULL && curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
nodeT2->next = currT2;
1 3 6
5READ 6; WRITE 5
17
Making !WAR block atomiclist_insert(list_t *listPtr, node_t *node) {
atomic [!WAR]{
*curr = listPtr->head; do {
prev = curr; currT1 = currT1->next;
} while (curr != NULL && curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
nodeT2->next = currT2;
Ignored WAR conflict:
currT1 = currT1->next;
does not move to the right of
nodeT2->next = currT2;
18
Abstractionlist_insert(list_t *listPtr, node_t *node) {
atomic [!WAR]{
*curr = listPtr->head; do {
(currT1 = currT1->next)+; havoc prev;
assume prev->next = curr; assume prev->key < node->key;
} while (curr != NULL && curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
• Abstract action right mover• Now block is atomic.• Sequential verification
1 3 6
5WRITE 5; READ 5, 6;
19
1. Sequentially verify the original code
list_insert(list_t *listPtr, node_t *node) {
*curr = listPtr->head; do {
prev = curr; curr = curr->next; } while (curr != NULL &&
curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
20
2. Apply program transformation
list_insert(list_t *listPtr, node_t *node) {
*curr = listPtr->head; do {
(currT1 = currT1->next)+;
havoc prev; assume prev->next = curr; assume prev->key < node->key;
} while (curr != NULL && curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
Do global read abstractions Abstract transaction becomes
atomic.
21
3. Prove abstract code sequentially
list_insert(list_t *listPtr, node_t *node) {
*curr = listPtr->head; do {
(currT1 = currT1->next)+;
havoc prev; assume prev->next = curr; assume prev->key < node->key;
} while (curr != NULL && curr->key < node->key);
node->next = curr; prev->next = node;
assert(node is in the list && list is sorted); }
}
22
Relaxed Conflict Detection• Pattern
– Traverse/Take snapshot of (large portion of) global state– Do local computation– Update small portion of global state
• Concurrent data structures, optimization algorithms, cloud computing• Performance optimizations for transactional memory
– Ignore WAR conflicts (Titos et al., HiPEAC ‘12)– Early release/early discard (e.g., Kozyrakis et al., WTW ‘06)
• Issue: Snapshot may be stale– But programmer thinks this is OK (as long as there is no write-write conflict with another operation)
• Problem:– How to verify properties of code running under a
relaxed consistency model
23
WAR Conflict Pattern
read xread y
read x write xwrite y
24
WAR Conflict Pattern
read xread y
read x write xwrite y
WAR conflict OK
25
WAR Conflict Pattern
read xread y
read x write xwrite y
WAR conflict OK
as long as no
WAW conflict
26
WAR Conflict Pattern
read x read y
read x write xwrite y
WAR conflict OK
as long as no
WAW conflict
read x read y
read x write xwrite x
WAR conflict
WAW conflict
27
WAR Conflict Pattern
read x read y
read x write xwrite y
WAR conflict OK
as long as no
WAW conflict
read x read y
read x write xwrite x
WAR conflict
WAW conflict
A B O R T
28
Labyrinth: Grid Routing• FindRoute(p1,p2)
– Route a wire on the gridconnecting points p1 and p2
– Wires must not touch
• FindRoute operation– Take snapshot of grid– Find shortest path from p1 to p2– Write path to shared memory
if path does not overlap others• Overlap = write-write conflict
• Stale snapshot OK as long as computed path does not overlap others– Same path could have been computed
even with up-to-date snapshot
Write-After-Read
conflict
1 3 6 9 12 15 17Head
16
WRITEREAD
5
WRITE
snapshotGS := GlobStn;
(x, xVal) := localComp(snapshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; } 30
Non-problematic Interleaving
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn := GlobStn-1[w->wVal];
…
31
Actual Interleaving
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn := GlobStn-1[w->wVal];
…
snapshotGS := GlobSt0;
snapshotGS := GlobStn;
(x, xVal) := localComp(snapshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; }
This is OK because
localComp(GlobStn, args) and
localComp(GlobSt0,args)
would/might have produced
same result.
32
Correctness Argument
• Blue transaction’s snapshot is stale
• Blue and green accesses conflict
• But, end state consistent with
– green executed serially, then
– blue executed serially
1 3 6 9 12 15 17Head
16
WRITEREAD
5
WRITE
QED: A Proof System for Concurrent Programs
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]
Intuition for proof steps
• Abstract some actions• Prove non-interference• Commute• Prove larger blocks atomic
• Abstract some actions• Prove non-interference• Commute• Prove larger blocks atomic
Coarser Atomic Actions
35
. . .
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
36
QED’s Idea of Abstraction
If for all :
errors1 errors11. If then
s12. Else, if thens2 s1 s2
or errors1
s1
abstracted by
36
37
Flavors of Abstraction
if (x == 1) y := y + 1;
if (*) y := y + 1;
Adding non-determinism
Adding assertions (more behaviors that might go wrong)
t := x; havoc t;
assume x != t; skip;
assert (lock_owner == tid);x := t + 1;x := t + 1;
37
“Read abstraction”
QED Transformations: Reduction
[ S1; S2][ S1 ] ; [ S2 ]
I,P I,P’
38
If [S1] is a right mover or [S2] is a left mover
P P’
39
Reduction
;
... 1 2 ... n ; ...
right-mover:
For each execution:
Exist equivalent executions:
... 1 2 ... n ...
... 1 2 ... n ... ...........
... 1 2 ... n ...
;
39
Mover check in QED: Static, local, semantic
40
...
...
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
41
Atomicity Proof Idea
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn := GlobStn-1[w->wVal];
…
sshotGS := GlobSt0;
(x, xVal) := localComp(sshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; }
• Need this to be a “Right mover”• Must commute to the right of all other concurrent actions
Atomicity ensured bystrict conflict detection
42
Atomicity Proof Idea
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn := GlobStn-1[w->wVal];
…
sshotGS := GlobSt0;
(x, xVal) := localComp(sshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; }
• Need this to be a “Right mover”• Must commute to the right of all other concurrent actions
Atomicity ensured bystrict conflict detection
• Reasoning using Lipton’s reduction and abstraction• QED-like proof (“A Calculus of Atomic Actions”, POPL ’09)• Costly pairwise mover checks avoided
Atomicity Proof Idea
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn := GlobStn-1[w->wVal];
…
sshotGS := GlobSt0;
(x, xVal) := localComp(sshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; }
• Not a “Right mover”• Does not commute
to the right of global state updates
Reads and Updates do not Commute
1 3 6
5READ 6; WRITE 5
1 3 6
5WRITE 5; READ 5
Want to read 6 again!
Atomicity Proof Idea
GlobSt1 := GlobSt0[y->yVal];
…
GlobSt2 := GlobSt1[z->zVal];
…
GlobStn:= GlobStn-1[w->wVal];
…
sshotGS := GlobSt0;
(x, xVal) := localComp(sshotGS, args);
atomic { GlobSt := GlobSt [x->xVal]; }
• Not a “Right mover”• Does not commute
to the right of global state updates
• Idea: Abstract this read
• Add non-determinismso it can read GlobSt1, GlobSt2, …, GlobStn
Abstraction intuition
46
1 3 6
5ABSTRACT READ 6; WRITE 5
1 3 6
5WRITE 5; ABSTRACT READ 6
Need to jump over
5.
1 3 6
5READ 6; WRITE 5
1 3 6
5WRITE 5; READ 5
Want to read 6 again!
Abstraction intuition
47
1 3 6
5ABSTRACT READ 6; WRITE 5
1 3 6
5WRITE 5; ABSTRACT READ 6
Need to jump over
5.
1 3 6
5READ 6; WRITE 5
1 3 6
5WRITE 5; READ 5
Want to read 6 again!
curr = curr->next; abstracted bycurr = curr->next*; but don’t go past key.
48
Abstracting Read Accesses• Abstraction invariant AbsT,x:
A transition invariant for variable of type T at address x
• l := x.f becomes <obj = copy(x); havoc l; assume AbsT,x(state, state[obj.f l]) >
• “Read returns a non-deterministic value satisfying abstraction invariant”
• For the linked list insertion example
Absnode,x(old_st, new_st) = Reachold_st(list->head, x) ==>
Reachnew_st(list->head, x) ∧Reachnew_st (x, old(x->next))
∧Sortedold_st(list) ∧Sortednew_st(list)
Abstracting Accesses• Annotate write accesses:
– x.f := m becomes <assert AbsT,x(st, st[x.f m]); x := m >– Assertion: Proof obligation, ensures the abstraction invariant
• By construction, abstract reads commute to the right of annotated writes
• Assertions become proof obligations– Discharged using sequential reasoning– Abstraction invariant verified when operations are atomic
• Soundness guaranteed by theorem– Special case of QED soundness theorem– No pairwise mover check needed!
49
50
Ongoing Work: Obtaining the (Sequential) Specification
• When interpreted sequentially, the program may already have a specification– Spec already existed for Labyrinth and Genome
• Specifications (invariants) may be inferred mechanically• Done for the Genome benchmark using the Celia tool
– Invariant Synthesis for Programs Manipulating Lists with Unbounded Data A. Bouajjani, C. Dragoi, C. Enea, A. Rezine, and M. Sighireanu
CAV'10.
– On Inter-Procedural Analysis of Programs with Lists and Data A. Bouajjani, C. Dragoi, C. Enea, and M. Sighireanu PLDI'11.
51
Future Work: Obtaining the Abstraction Invariant
• Sometimes “true” is sufficient• Sometimes easy: Full cells never become empty (Labyrinth)
• Otherwise, need an over-approximation for
conflicting_updates* o read_access
• Can use annotation inference tool on the sequential code for
while (*) conflicting_updates; read_access;
52
Summary• Common pattern
– Traverse/Take snapshot of (large portion of) global state– Do local computation– Update small portion of global state
• Conflict serializability too costly– Fine-grain locking– Relaxed conflict detection
• Static proof approach for such programs– Read abstraction to capture effects of conflicting writes– Enables sequential proof on abstract program
• Ongoing work: Automation for inferring spec, abstraction invariant
53
Ongoing Work: Port Entire Proof Argument to VCC
• VCC: Verification tool for concurrent C programs (MS Aachen)– Used to verify Microsoft Hyper-V hypervisor– Uses Boogie, Z3
• Why VCC?– Can handle entire C– Larger agenda: Model and verify programs using novel concurrent
programming constructs• Programs with TM: race-freedom, static separation, assertions• Programs with relaxed consistency models, e.g. snapshot isolation
• Key ideas in VCC– Ownership, permissions expressed using ghost variables
• All annotations expressed using program logic– Objects have two-state invariants
• VCC checks that all actions preserve two-state invariants of all objects• Modular checks, converted to first-order logic queries for Z3.
54
Modeling Relaxed Conflict Detection in VCC
• Current proof argument– For each type, write an abstraction invariant– Relax read accesses using abstraction invariant
• Read accesses become right movers by construction– Relaxed code is atomic
• Discharge assertions used to justify right moverness– Verify desired properties on non-deterministic but sequential code
• Proof argument in VCC– Model TM and relaxed conflict detection using ownership, approval– Write two-state invariant about values returned by reads– Write two-state invariants about program objects– Verify that two-state invariants are admissible, preserved– Verify same specification as sequential version,
• Only rely on two-state invariant and atomicity within write block
Serdar Taşıran
Invited Speakers
Jim Larus Microsoft Research
Martin Rinard MIT
Giovanni Vigna UC Santa Barbara
Earlier Microsoft-Koç University Collaboration• Goldilocks: A Race Detection Tool
– Patented– Included in US and European
university curricula– Published in CACM Research
Highlights• One of 24 articles selected in
2010
• QED: A Verification Tool for Concurrent Programs– Winner: ACM Student Research
Competition– Best tool built using Microsoft
technology– Publicly available
reduceabstract
.....reducecheck
Correct
..
.
P1
Pn
P2
P1
Pn
Proof scriptBoogie 2, Z3
QEDPLprogram
Ongoing Research
• Tool support for new programming paradigms:– DesCloud: Cloud simulation on a desktop.– VCC verifier, relaxed conflict detection, relaxed consistency models
• Program Proof Tools– Handling relaxed hardware memory models in QED– Verifying TM implementations with QED
• Dynamic (Runtime) verification tools – Parallelizing race detection– Using TM to prevent and recover from races – Races in programs that use TM