reasoning about the c c weak memory model
play

Reasoning about the C/C++ weak memory model Viktor Vafeiadis Max - PowerPoint PPT Presentation

Reasoning about the C/C++ weak memory model Viktor Vafeiadis Max Planck Institute for Software Systems (MPI-SWS) 17 July 2014 Understanding weak memory consistency Read the architecture/language specs? Too informal, often wrong. Read the


  1. Reasoning about the C/C++ weak memory model Viktor Vafeiadis Max Planck Institute for Software Systems (MPI-SWS) 17 July 2014

  2. 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 a better methodology. . . Viktor Vafeiadis Reasoning about the C/C++ weak memory model 2/34

  3. 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 Reasoning about the C/C++ weak memory model 3/34

  4. Relaxed behaviour: store buffering Initially x = y = 0. x . store(1 , rlx ); y . store(1 , rlx ); t 1 = y . load( rlx ); t 2 = x . load( rlx ); This can return t 1 = t 2 = 0. Justification: [ x = y = 0] Behaviour observed W rlx ( x , 1) W rlx ( y , 1) on x86/Power/ARM R rlx ( y , 0) R rlx ( x , 0) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 4/34

  5. Release-acquire synchronization: message passing Initially a = x = 0. a = 5; while ( x . load( acq ) == 0); x . store(1 , release ); print( a ); This will always print 5. Justification: W na ( a , 5) R acq ( x , 1) Release-acquire synchronization W rel ( x , 1) R na ( a , 5) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 5/34

  6. Relaxed accesses don’t synchronize Initially a = x = 0. a = 5; while ( x . load( rlx ) == 0); x . store(1 , rlx ); print( a ); The program is racy ❀ undefined semantics. Justification: W na ( a , 5) R rlx ( x , 1) Relaxed accesses race don’t synchronize W rlx ( x , 1) R na ( a , ?) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 6/34

  7. Dependency cycles Initially x = y = 0. if ( x . load ( rlx ) == 1) if ( y . load ( rlx ) == 1) y . store (1 , rlx ); x . store (1 , rlx ); C11 allows the outcome x = y = 1. Justification: R rlx ( x , 1) R rlx ( y , 1) Relaxed accesses don’t synchronize W rlx ( y , 1) W rlx ( x , 1) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 7/34

  8. Given a memory model definition 1. Check that the model is mathematically sane . ◮ For example, it is monotone. 2. Check that it is not too weak . ◮ Provides useful reasoning principles. 3. Check that it is not too strong . ◮ Can be implemented efficiently. 4. Check that it is actually useful . ◮ Admits the intended program optimisations. Viktor Vafeiadis Reasoning about the C/C++ weak memory model 8/34

  9. How does the C11 definition rate? (1/2) Let’s start with some good news. . . Verified compilation of atomic accesses to x86 and Power/ARM. [Batty et al., POPL’11] [Batty et al., POPL’12] [Sarkar et al., PLDI’12] = ⇒ The C11 model is not too strong . Viktor Vafeiadis Reasoning about the C/C++ weak memory model 9/34

  10. How does the C11 definition rate? (2/2) 1. Check that the model is mathematically sane . ✗ No, it is not monotone. 2. Check that it is not too weak . ✗ No, due to dependency cycles. 3. Check that the model is not too strong . ✓ OK, prior work. 4. Check that it is actually useful . ✗ No, it disallows intended program transformations. Viktor Vafeiadis Reasoning about the C/C++ weak memory model 10/34

  11. Part I. Mathematical sanity ◮ Monotonicity ◮ Prefix closure

  12. Monotonicity “Adding synchronisation should not introduce new behaviours” Examples: ◮ Adding a memory fence ◮ Strengthening the access mode of an operation ◮ Reducing parallelism, C 1 � C 2 ❀ C 1 ; C 2 ◮ Expression evaluation linearisation: x = a + b ; t 1 = a ; t 2 = b ; x = t 1 + t 2 ; ❀ ◮ (Roach motel reorderings) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 12/34

  13. Obstacles to monotonicity 1. The axiom for non-atomic reads rf( b ) = a ∧ (isNA( a ) ∨ isNA( b )) = ⇒ hb( a , b ) (in combination with dependency cycles) 2. The axiom for SC reads Viktor Vafeiadis Reasoning about the C/C++ weak memory model 13/34

  14. Sequentionalisation is invalid if ( x . load( rlx ) == 1) if ( y . load( rlx ) == 1) a = 1; if ( a == 1) x . store(1 , rlx ); y . store(1 , rlx ); [ a = x = y = 0] W na ( a , 1) R rlx ( x , 1) R rlx ( y , 1) R na ( a , 1) W rlx ( x , 1) W rlx ( y , 1) rf( b ) = a ∧ (isNA( a ) ∨ isNA( b )) = ⇒ hb( a , b ) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 14/34

  15. SC read restriction There shall be a single total order S on all seq_cst operations [. . . ] such that each seq_cst operation B that loads a value from an atomic object M observes one of the following values: ◮ the result of the last modification A of M that precedes B in S, if it exists, or ◮ if A exists, the result of some modification of M in the visible sequence of side effects with respect to B that is not seq_cst and that does not happen before A, or ◮ if A does not exist, [. . . ] [N1570, §7.17.3.6] rf( b ) = c ∧ isSC( b ) = ⇒ iscr( c , b ) ∨ ¬ isSC( c ) ∧ ∄ a . hb( c , a ) ∧ iscr( a , b ) where iscr( c , b ) def = scr( c , b ) ∧ ∄ d . scr( c , d ) ∧ scr( d , b ) scr( c , b ) def = iswrite locs( b ) ( c ) ∧ sc( c , b ) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 15/34

  16. Strengthening is invalid s 1 = x . load( rlx ); s 2 = x . load( rlx ); x . store(1 , rlx ); x . store(3 , rlx ); y . store(3 , sc ); s 3 = x . load( rlx ); x . store(2 , sc ); y . store(2 , sc ); r = x . load( sc ); t 1 = y . load( rlx ); y . store(1 , sc ); t 2 = y . load( rlx ); t 3 = y . load( rlx ); r = s 1 = t 1 = 1 ∧ s 2 = t 2 = 2 ∧ s 3 = t 3 = 3 — Disallowed W rlx ( x , 1) W rlx ( x , 3) W sc ( y , 3) sc sc W sc ( x , 2) W sc ( y , 2) R sc ( x , 1) sc sc W sc ( y , 1) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 16/34

  17. Strengthening is invalid s 1 = x . load( rlx ); s 2 = x . load( rlx ); x . store(1 , rlx ); x . store(3 , sc ); y . store(3 , sc ); s 3 = x . load( rlx ); x . store(2 , sc ); y . store(2 , sc ); r = x . load( sc ); t 1 = y . load( rlx ); y . store(1 , sc ); t 2 = y . load( rlx ); t 3 = y . load( rlx ); r = s 1 = t 1 = 1 ∧ s 2 = t 2 = 2 ∧ s 3 = t 3 = 3 — Allowed W rlx ( x , 1) W sc ( x , 3) W sc ( y , 3) sc sc sc sc W sc ( x , 2) W sc ( y , 2) R sc ( x , 1) sc sc W sc ( y , 1) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 16/34

  18. Prefix closure “Removing (hb ∪ rf)-maximal events should preserve consistency” ◮ Maximal events should not affect other events ◮ Does not hold because of release sequences Viktor Vafeiadis Reasoning about the C/C++ weak memory model 17/34

  19. Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x . store(1 , release ); while ( x . load( acq ) � = 3); x . store(3 , rlx ); a = 2; This program is not racy. The acquire synchronizes with the release. Viktor Vafeiadis Reasoning about the C/C++ weak memory model 18/34

  20. Release sequences too strong (relaxed writes) Initially x = y = 0. a = 1; x . store(2 , rlx ); ( ∗ ) x . store(1 , release ); while ( x . load( acq ) � = 3); x . store(3 , rlx ); a = 2; But this one is racy according to C11. The acquire no longer synchronizes with the release. Same if (*) is in a different thread. Viktor Vafeiadis Reasoning about the C/C++ weak memory model 18/34

  21. Part II. Not overly weak ◮ High-level reasoning principles

  22. Some basic high-level reasoning principles DRF: Race-free programs have SC semantics ≈ Ownership-based reasoning Coherence: SC for single-variable programs ≈ Non-relational invariants; e.g., x ≥ 0 ∧ y ≥ 0. Cumulativity: Transitive visibility for Rel-Acq ◮ Ownership tranfer possible Viktor Vafeiadis Reasoning about the C/C++ weak memory model 20/34

  23. � � � � Release-acquire synchronization: message passing Initially a = x = 0. a = 5; while ( x . load( acq ) == 0); x . store( release , 1); print( a ); This will always print 5. Justification: W na ( a , 5) R acq ( x , 1) Release-acquire synchronization W rel ( x , 1) R na ( x , 5) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 21/34

  24. Rules for release/acquire accesses Relaxed separation logic [OOPSLA’13] Ownership transfer by rel-acq synchronizations. ◮ Atomic allocation ❀ pick loc. invariant Q . � � � � Q ( v ) x = alloc( v ); W Q ( x ) ∗ R Q ( x ) ◮ Release write ❀ give away permissions. � � � � Q ( v ) ∗ W Q ( x ) x . store( v , rel ); W Q ( x ) ◮ Acquire read ❀ gain permissions. � � � � R Q ( x ) t = x . load( acq ); Q ( t ) ∗ R Q [ t :=emp] ( x ) Viktor Vafeiadis Reasoning about the C/C++ weak memory model 22/34

  25. Release-acquire synchronization: message passing Initially a = x = 0. Let J ( v ) def = v = 0 ∨ & a �→ 5. � � � � & a �→ 0 ∗ W J ( x ) R J ( x ) a = 5; while ( x . load( acq ) == 0); � � � � & a �→ 5 ∗ W J ( x ) & a �→ 5 x . store( release , 1); print( a ); � � � � W J ( x ) & a �→ 5 PL consequences: Ownership transfer works! Viktor Vafeiadis Reasoning about the C/C++ weak memory model 23/34

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend