Automatically proving linearizability Viktor Vafeiadis University - - PowerPoint PPT Presentation
Automatically proving linearizability Viktor Vafeiadis University - - PowerPoint PPT Presentation
Automatically proving linearizability Viktor Vafeiadis University of Cambridge CAV 2010 M&S non-blocking queue head tail null X 1 2 3 4 typedef struct Node_s *Node; struct Queue_s *Q; struct Node_s { init() { int val; n = new
M&S non-blocking queue
X 1 3 4
null
2 head tail
typedef struct Node_s *Node; struct Node_s { int val; Node next; } struct Queue_s { Node head; Node tail; } struct Queue_s *Q; init() { n = new Node(); n→next = null; Q = new Queue(); Q→head = node; Q→tail = node; }
Linearizability
Every method executes ‘atomically’ & obeys a functional correctness specification Shared variable: AQ
AQ := append(singleton(v), AQ); return 0; if (AQ == empty) { return EMPTY; } else { r := hd(AQ); AQ := tl(AQ); return r; } dequeue() spec enqueue(v) spec
Linearizability & forward simulation
Linearizability: The implementation (of every method) is a refinement
- f an atomic specification.
Standard proof technique: forward simulation Abstract (spec) Concrete (impl)
Sconc S’conc Sabs S’abs
Linearization points
The implementation is a refinement of an atomic specification.
abstract execution concrete execution
linearization point (LP)
Linearization point of enqueue
- Lin. Point
(provided CAS succeeds)
enqueue(v) { m := new Node(); m→val := v; m→next := null; while (true) { t := Q→tail; n := tail→next; if (Q→tail ≠ tail) continue; if (n == null) { if (CAS(&t→next,n,m)) break; } else { CAS(&Q→tail,t,n); } } CAS(&Q→tail,t,n); }
Proof search for the LP ?
- For each execution path of each method,
choose a candidate LP
- Check whether it is a valid LP
Does this work ?
Proof search for the LP ?
- For each execution path of each method,
choose a candidate LP
- Check whether it is a valid LP
Does this work ? Not quite.
- 1. LPs can be conditional
- 2. LPs can be in the code of another thread
LP of dequeue, when it returns EMPTY
LP provided
this test fails, and the h==t test succeeds the n==null test succeeds
Condition:
¬prophecy(Q→tail ≠ t)
∧ h == t ∧ n == null dequeue () { while (true) { h := Q→head; t := Q→tail; n := h→next; if (Q→tail ≠ t) continue; if (h == t) { if (n == null) return EMPTY; CAS(&Q→tail,t,n); } else { if (CAS(&Q→head,h,n)) return n→val; } } }
Key observation
- Method executions that logically modify the
state have a simple LP.
- Method executions that do not logically
modify the state often have a complex LP.
So: Treat these two cases differently.
- Search for LPs of executions that logically
modify the state;
- Do a non-constructive proof for executions
that do not logically modify the state.
Basic LP validation
Auxiliary variable: lres
- 1. At the entry to the function:
lres := UNDEF;
- 2. At the candidate efgectful LPs:
assert(lres==UNDEF); lres := method_spec();
- 3. At the return points, check
res == lres concrete result abstract result
Auxiliary variable: can_return
- 1. At the entry to the function:
∀i. can_return[i] := false;
- 2. At every point, add a pure ‘LP checker’:
if (abs_method() has no side-efgects) can_return[abs_method()] := true;
- 3. At the return points, check
can_return[res] == true
Validating pure executions
concrete result
For example...
if (AQ == empty) { return EMPTY; } else { r := hd(AQ); AQ := tl(AQ); return r; } if (AQ == empty) { can_return[EMPTY] := true; } dequeue spec pure lin. checker
Auxiliary variables: lres, can_return
- 1. At the entry to the function:
lres := UNDEF; ∀i. can_return[i] := false;
- 2. At the candidate efgectful LPs:
assert(lres==UNDEF); lres := abs_method()
- 3. Add pure checkers at every program point:
assign can_return[i] := true if method_spec returns i & has no side-efgects.
- 4. At the return points, check
(res==lres) ∨ (lres==UNDEF ∧ can_return[res])
Enhanced LP validation
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 +INF
null
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 5 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 5 3 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 5 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
LPs in other threads
add (e) { ... } remove (e) { ... } contains (e) { c := H; while (c→val < e) c := c→next; return (c→val == e); }
1 7 3 5 +INF
null
c
- INF
contains(5) || add(5); remove(3); remove(5)
Auxiliary variables: lres, can_return
- 1. At the entry to the function:
lres := UNDEF; ∀i. can_return[i] := false;
- 2. At the candidate efgectful LPs:
assert(lres==UNDEF); lres := abs_method()
- 3. Add pure checkers at every program point
(incl. program points in other threads)
- 4. At the return points, check
(res==lres) ∨ (lres==UNDEF ∧ can_return[res])
Enhanced LP validation
Experiments (linearizability)
Algorithm Lines Ops Efg Pure LpO Time (s) DCAS stack 100 8 4 5 0.3 Treiber stack 100 8 4 5 0.3 M&S two-lock queue 85 4 3 2 16.5 M&S non-blocking queue 127 4 3 2 4.9 DGLM non-blocking queue 126 4 3 2 7.6 Pessimistic set 100 3 2 3 247.8 V&Y DCAS-based set 101 3 2 3 51.0 ORVYY lazy set 94 3 2 3 1 521.5
Lines: lines of code: excluding comments & specs Ops: # methods Efg: # efgectful methods Pure: # methods with a pure execution path LpO: # linearization points in other threads
Summary & future work
- Observation:
Efgectful LPs are usually simple
- Technique:
Search for efgectful LPs Try all possible pure LPs at once
- Challenges ahead: