A case for relaxed program logics Viktor Vafeiadis MPI-SWS 10 July - - PowerPoint PPT Presentation
A case for relaxed program logics Viktor Vafeiadis MPI-SWS 10 July - - PowerPoint PPT Presentation
A case for relaxed program logics Viktor Vafeiadis MPI-SWS 10 July 2014 Understanding weak memory consistency Read the architecture/language specs? Too informal, often wrong. Read the formalisations? Fairly complex. Run benchmarks /
Understanding weak memory consistency Read the architecture/language specs?
◮ Too informal, often wrong.
Read the formalisations?
◮ Fairly complex.
Run benchmarks / Litmus tests?
◮ Observe only subset of behaviours.
We need better tools. . . Relaxed program logics
Viktor Vafeiadis A case for relaxed program logics 2/17
Which memory model? Hardware or language models?
◮ Want to reason at “high level” ◮ TSO ❀ good robustness theorems
C/C++ or Java?
◮ JMM is broken [Sevcik et al.] ◮ So, only C/C++11 left
Goals:
◮ Understand the memory model ◮ Verify intricate concurrent programs
Viktor Vafeiadis A case for relaxed program logics 3/17
The C11 memory model Two types of locations: ordinary and atomic
◮ Races on ordinary accesses ❀ error
A spectrum of atomic accesses:
◮ Relaxed ❀ no fence ◮ Consume reads ❀ no fence, but preserve deps ◮ Release writes ❀ no fence (x86); lwsync (PPC) ◮ Acquire reads ❀ no fence (x86); isync (PPC) ◮ Seq. consistent ❀ full memory fence
Explicit primitives for fences
Viktor Vafeiadis A case for relaxed program logics 4/17
Release-acquire synchronization: message passing Initially a = x = 0. a = 5; x.store(release, 1); while (x.load(acq) == 0); print(a); This will always print 5. Justification:
Wna(a, 5)
- Racq(x, 1)
- Wrel(x, 1)
- Rna(x, 5)
Release-acquire synchronization
Viktor Vafeiadis A case for relaxed program logics 5/17
Rules for release/acquire accesses Ownership transfer by rel-acq synchronizations.
◮ Atomic allocation ❀ pick loc. invariant Q.
- Q(v)
- x = alloc(v);
- WQ(x) ∗ RQ(x)
- ◮ Release write ❀ give away permissions.
- Q(v) ∗ WQ(x)
- x.store(v, rel);
- WQ(x)
- ◮ Acquire read ❀ gain permissions.
- RQ(x)
- t = x.load(acq);
- Q(t) ∗ RQ[t:=emp](x)
- Viktor Vafeiadis
A case for relaxed program logics 6/17
Release-acquire synchronization: message passing Initially a = x = 0. Let J(v) def = v = 0 ∨ &a → 5.
- &a → 0 ∗ WJ(x)
- a = 5;
- &a → 5 ∗ WJ(x)
- x.store(release, 1);
- WJ(x)
- RJ(x)
- while (x.load(acq) == 0);
- &a → 5
- print(a);
- &a → 5
- PL consequences:
Ownership transfer works!
Viktor Vafeiadis A case for relaxed program logics 7/17
Relaxed accesses Basically, disallow ownership transfer.
◮ Relaxed reads:
- RQ(x)
- t := x.load(rlx)
- RQ(x)
- ◮ Relaxed writes:
Q(v) = emp
- WQ(x)
- x.store(v, rlx)
- WQ(x)
- Unsound because of dependency cycles!
Viktor Vafeiadis A case for relaxed program logics 8/17
Dependency cycles Initially x = y = 0. if (x.load(rlx) == 1) y.store(1, rlx); if (y.load(rlx) == 1) x.store(1, rlx); C11 allows the outcome x = y = 1. Justification:
Rrlx(x, 1)
- Rrlx(y, 1)
- Wrlx(y, 1)
- Wrlx(x, 1)
- Relaxed accesses
don’t synchronize
Viktor Vafeiadis A case for relaxed program logics 9/17
Dependency cycles Initially x = y = 0. if (x.load(rlx) == 1) y.store(1, rlx); if (y.load(rlx) == 1) x.store(1, rlx); C11 allows the outcome x = y = 1. What goes wrong: Non-relational invariants are unsound. x = 0 ∧ y = 0 The DRF-property does not hold.
Viktor Vafeiadis A case for relaxed program logics 9/17
Dependency cycles Initially x = y = 0. if (x.load(rlx) == 1) y.store(1, rlx); if (y.load(rlx) == 1) x.store(1, rlx); C11 allows the outcome x = y = 1. How to fix this: Don’t use relaxed writes ∨ Strengthen the model
Viktor Vafeiadis A case for relaxed program logics 9/17
Incorrect message passing int a; atomic_int x = 0;
a = 5;
if (x.load(rlx) = 0){ x.store(1, rlx); print(a); }
Wna(x, 0)
- Wna(a, 5)
- race
- Rrlx(x, 1)
- Wrlx(x, 1)
- Rna(a, 5)
- Viktor Vafeiadis
A case for relaxed program logics 10/17
Message passing with C11 memory fences int a; atomic_int x = 0;
a = 5; if (x.load(rlx) = 0){ fence(release); fence(acq); x.store(1, rlx); print(a); }
Wna(x, 0)
- Wna(a, 5)
- Rrlx(x, 1)
- Fencerel
- sw
Fenceacq
- Wrlx(x, 1)
- Rna(a, 5)
- Viktor Vafeiadis
A case for relaxed program logics 10/17
Reasoning about fences
◮ Introduce two ‘modalities’ in the logic
- P
- fence(release)
- △P
- ∇P
- fence(acq)
- P
- RQ(x)
- t := x.load(rlx)
- RQ[t:=emp](x) ∗ ∇Q(t)
- WQ(x) ∗ △Q(v)
- x.store(v, rlx)
- WQ(x)
- Viktor Vafeiadis
A case for relaxed program logics 11/17
Reasoning about fences Let Q(v) def = v = 0 ∨ &a → 5.
- &a → 0 ∗ WQ(x) ∗ RQ(x)
-
- &a → 0 ∗ WQ(x)
- a = 5;
- &a → 5 ∗ WQ(x)
- fence(release);
- △(&a → 5) ∗ WQ(x)
- x.store(1, rlx);
- true
- t = x.load(rlx);
- ∇(t = 0 ∨ &a → 5)
- if (t = 0)
fence(acq);
- &a → 5
- print(a); }
- true
-
Viktor Vafeiadis A case for relaxed program logics 12/17
Release-consume synchronization Initially a = x = 0. a = 5; x.store(release, &a); t = x.load(consume); if (t = 0) print(∗t); This program cannot crash nor print 0. Justification:
Wna(a, 5)
- Rcon(x, &a)
- Wrel(x, &a)
- Rna(a, 5)
Release-consume synchronization
Viktor Vafeiadis A case for relaxed program logics 13/17
Release-consume synchronization Initially a = x = 0. Let J(t) def = t = 0 ∨ t → 5.
- &a → 0 ∗ WJ(x)
- a = 5;
- &a → 5 ∗ WJ(x)
- x.store(release, &a);
- RJ(x)
- t = x.load(consume);
- ∇
t(t = 0 ∨ t → 5)
- if (t = 0) print(∗t);
This program cannot crash nor print 0. PL consequences: Needs funny modality, but otherwise OK.
Viktor Vafeiadis A case for relaxed program logics 13/17
Proposed rules for consume accesses
- RQ(x)
- t := x.load(cons)
- RQ[t:=emp](x) ∗ ∇
t Q(t)
- P
- C
- Q
- C is basic command mentioning t
- ∇
t P
- C
- ∇
t Q
- Viktor Vafeiadis
A case for relaxed program logics 14/17
Release-acquire too weak in the presence of consume Initially x = y = 0. a = 1; x.store(1, release); while (x.load(consume) = 1); y.store(1, release); (∗) while (y.load(acquire) = 1); (∗) a = 2; C11 deems this program racy.
◮ Only different thread rel-acq synchronize.
What goes wrong in PL: On ownership transfers, we must prove that we don’t read from the same thread.
Viktor Vafeiadis A case for relaxed program logics 15/17
Release-acquire too weak in the presence of consume Initially x = y = 0. a = 1; x.store(1, release); while (x.load(consume) = 1); y.store(1, release); (∗) while (y.load(acquire) = 1); (∗) a = 2; C11 deems this program racy. But, it is not racy:
◮ On x86-TSO, Power, ARM, and Itanium. ◮ Or if we move the (∗) lines to a new thread.
So, drop the “different thread” restriction.
Viktor Vafeiadis A case for relaxed program logics 15/17
Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x.store(1, release); x.store(3, relaxed); while(x.load(acquire) = 3); a = 2; This program is not racy. The acquire synchronizes with the release.
Viktor Vafeiadis A case for relaxed program logics 16/17
Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x.store(1, release); x.store(3, relaxed); x.store(2, relaxed); while(x.load(acquire) = 3); a = 2; But this one is racy according to C11. The acquire no longer synchronizes with the release.
Viktor Vafeiadis A case for relaxed program logics 16/17
Conclusion
Relaxed program logics are a tool for understanding weak memory models
Viktor Vafeiadis A case for relaxed program logics 17/17