Formal reasoning about the C11 weak memory model Invited talk @ CPP’15 Viktor Vafeiadis Max Planck Institute for Software Systems (MPI-SWS) 13 January 2015
What is a weak memory model? Viktor Vafeiadis Formal reasoning about the C11 weak memory model 2/32
What is a weak memory model? The WMM defines the semantics of concurrent memory accesses. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 2/32
Sequential consistency Sequential consistency (SC): ◮ The standard model for concurrency. ◮ Interleave each thread’s atomic accesses. ◮ Almost all verification work assumes it. Initially, X = Y = 0. X := 1; Y := 1; a := Y b := X In SC, this program cannot return a = b = 0. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 3/32
Store buffering in x86-TSO . . . cpu 1 cpu n write . . . read write-back Memory Initially, X = Y = 0. X := 1; Y := 1; a := Y b := X Allowed outcome: a = b = 0. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 4/32
IRIW: Not just store buffering Initially, X = Y = 0. a := X ; c := Y ; X := 1 Y := 1 b := Y d := X Allowed outcome: a = c = 1 and b = d = 0. X := 1 Y := 1 a := X c := Y b := Y d := X Viktor Vafeiadis Formal reasoning about the C11 weak memory model 5/32
A basic guarantee: coherence Coherence: “SC for a single variable” Initially, X = 0. a := X ; c := X ; X := 1 X := 2 b := X d := X Forbidden outcome: a = 1 , b = 2 , c = 2 , d = 1. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 6/32
The C11 memory model Two types of locations: ordinary and atomic ◮ Races on ordinary accesses ❀ error A spectrum of atomic accesses: ◮ Seq. consistent ❀ full memory fence ◮ Release writes ❀ no fence (x86); lwsync (PPC) ◮ Acquire reads ❀ no fence (x86); isync (PPC) ◮ Consume reads ❀ no fence, but preserve deps ◮ Relaxed ❀ no fence Explicit primitives for fences Viktor Vafeiadis Formal reasoning about the C11 weak memory model 7/32
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 Formal reasoning about the C11 weak memory model 8/32
Getting rid of the SB behaviour Initially x = y = 0. x . store(1 , sc ); y . store(1 , sc ); t 1 = y . load( sc ); t 2 = x . load( sc ); This cannot return t 1 = t 2 = 0. Justification: [ x = y = 0] [ x = y = 0] W sc ( x , 1) W sc ( y , 1) W sc ( x , 1) W sc ( y , 1) R sc ( y , 0) R sc ( x , 1) R sc ( y , 1) R sc ( x , 0) Viktor Vafeiadis Formal reasoning about the C11 weak memory model 9/32
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 Formal reasoning about the C11 weak memory model 10/32
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 Formal reasoning about the C11 weak memory model 11/32
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 Formal reasoning about the C11 weak memory model 12/32
The C11 weak memory model (simplified) def def def isread `,v ( a ) = 9 X, v 0 . lab ( a ) 2 { R X ( `, v ) , C X ( `, v, v 0 ) } isread ` ( a ) = 9 v. isread `,v ( a ) isread ( a ) = 9 `. isread ` ( a ) def def def iswrite `,v ( a ) = 9 X, v 0 . lab ( a ) 2 { W X ( `, v ) , C X ( `, v 0 , v ) } iswrite ` ( a ) = 9 v. iswrite `,v ( a ) iswrite ( a ) = 9 `. iswrite ` ( a ) def def def isfence ( a ) = lab ( a ) 2 { F ACQ , F REL } isaccess ( a ) = isread ( a ) _ iswrite ( a ) isNA ( a ) = mode ( a ) = NA def def def sameThread ( a, b ) = tid ( a ) = tid ( b ) isrmw ( a ) = isread ( a ) ^ iswrite ( a ) isSC ( a ) = mode ( a ) = SC def def def rsElem ( a, b ) = sameThread ( a, b ) _ isrmw ( b ) isAcq ( a ) = mode ( a ) w ACQ isRel ( a ) = mode ( a ) w REL def rseq ( a, b ) = a = b _ rsElem ( a, b ) ^ mo ( a, b ) ^ ( 8 c. mo ( a, c ) ^ mo ( c, b ) ) rsElem ( a, c )) = 9 c, d. ¬ sameThread ( a, b ) ^ isRel ( a ) ^ isAcq ( b ) ^ rseq ( c, rf ( d )) def sw ( a, b ) ^ ( a = c _ isfence ( a ) ^ sb + ( a, c )) ^ ( d = b _ isfence ( d ) ^ sb + ( d, b )) def = ( sb [ sw [ asw ) + hb = 9 a, b. isaccess ( a ) ^ isaccess ( b ) ^ loc ( a ) = loc ( b ) ^ a 6 = b def Racy ^ ( iswrite ( a ) _ iswrite ( b )) ^ ( isNA ( a ) _ isNA ( b )) ^ ¬ ( hb ( a, b ) _ hb ( b, a )) def Observation = { ( a, b ) | mo ( a, b ) ^ loc ( a ) = loc ( b ) = world } 8 a, b. sb ( a, b ) = ) tid ( a ) = tid ( b ) ( ConsSB ) @ a. hb ( a, a ) ( IrrHB ) order ( iswrite , mo ) ^ 8 `. total ( iswrite ` , mo ) ( ConsMO ) @ a, b. rf ( b ) = a ^ hb ( b, a ) ( ConsRFhb ) order ( isSC , sc ) ^ total ( isSC , sc ) @ a, b. hb ( a, b ) ^ mo ( b, a ) ( CohWW ) ( ConsSC ) ^ ( hb [ mo ) \ ( isSC × isSC ) ⊆ sc @ a, b. hb ( a, b ) ^ mo ( rf ( b ) , rf ( a )) ( CohRR ) 8 b. ( 9 c. rf ( b ) = c ) ( ) ( ConsRFdom ) @ a, b. hb ( a, b ) ^ mo ( rf ( b ) , a ) ( CohWR ) 9 `, a. iswrite ` ( a ) ^ isread ` ( b ) ^ hb ( a, b ) @ a, b. hb ( a, b ) ^ mo ( b, rf ( a )) ( CohRW ) 8 a, b. rf ( b ) = a = ) 9 `, v. iswrite `,v ( a ) ^ isread `,v ( b ) ( ConsRF ) 8 a, b. isrmw ( a ) ^ rf ( a ) = b = 8 a, b. rf ( b ) = a ^ ( isNA ( a ) _ isNA ( b )) = ) hb ( a, b ) ) ( ConsRFna ) ( AtRMW ) imm ( mo , b, a ) 8 a, b. rf ( b ) = a ^ isSC ( b ) = ) imm ( scr , a, b ) _ ¬ isSC ( a ) ^ @ x. hb ( a, x ) ^ imm ( scr , x, b ) ( SCReads ) 8 a, b, `. lab ( a ) = lab ( b ) = A ( ` ) = ) a = b ( ConsAlloc ) = ( @ a. R ( a, a )) ^ ( R + ⊆ R ) ^ ( R ⊆ P × P ) def def where order ( P, R ) imm ( R, a, b ) = R ( a, b ) ^ @ c. R ( a, c ) ^ R ( c, b ) def def total ( P, R ) = ( 8 a, b. P ( a ) ^ P ( b ) = ) a = b _ R ( a, b ) _ R ( b, a )) scr ( a, b ) = sc ( a, b ) ^ iswrite loc ( b ) ( a ) Viktor Vafeiadis Formal reasoning about the C11 weak memory model 13/32
The C11 weak memory model (simplified) Viktor Vafeiadis Formal reasoning about the C11 weak memory model 14/32
The C11 weak memory model (simplified) Use good tools: ◮ Program logics ◮ Interactive theorem provers (Coq) Viktor Vafeiadis Formal reasoning about the C11 weak memory model 14/32
Two research directions Verify compilation of C11: ◮ Compilation of the atomics to hardware (Batty et al.’11, Sarkar et al.’12) ◮ Source-to-source transformations (see POPL’15) ◮ An actual compiler (future work) Verify concurrent C11 programs: ◮ Using program logics ◮ By reduction to SC (robustness) ◮ Don’t verify, just find bugs. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 15/32
Understanding C11 using relaxed program logics
When should we care about relaxed memory? C11 satisfies the DRF-SC property: Theorem (DRF-SC) If � Prg � SC contains no data races and no weak atomics, then � Prg � C11 = � Prg � SC . ◮ Program logics that disallow data races are trivially sound for the NA+SC fragment of C11. Viktor Vafeiadis Formal reasoning about the C11 weak memory model 17/32
Separation logic Key concept of ownership : ◮ Resourceful reading of Hoare triples. { P } C { Q } ◮ Disjoint parallelism: � � � � � � � � P 1 C 1 Q 1 P 2 C 2 Q 2 � � � � P 1 ∗ P 2 C 1 � C 2 Q 1 ∗ Q 2 Viktor Vafeiadis Formal reasoning about the C11 weak memory model 18/32
Separation logic rules for non-atomic accesses ◮ Allocation gives you permission to access x . � � � � emp x = alloc(); x �→ _ ◮ To access a normal location, you must own it: � � � � x �→ v t = ∗ x ; x �→ v ∧ t = v ∗ x = v ′ ; � � � x �→ v ′ � x �→ v Viktor Vafeiadis Formal reasoning about the C11 weak memory model 19/32
Reasoning about SC accesses ◮ Model SC accesses as non-atomic accesses inside a CCR. ◮ Use concurrent separation logic (CSL) � � � � J ⊢ P C Q ◮ Rule for SC-atomic reads: � � � � emp ⊢ J ∗ P t = ∗ x ; J ∗ Q � � � � J ⊢ t = x . load ( sc ); P Q Viktor Vafeiadis Formal reasoning about the C11 weak memory model 20/32
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 Formal reasoning about the C11 weak memory model 21/32
Recommend
More recommend