10.07.2015 Views

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

Is Parallel Programming Hard, And, If So, What Can You Do About It?

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

260 APPENDIX E. FORMAL VERIFICATION32 shouldexit = 0;33 snap = dynticks_progress_counter;34 grace_period_state = GP_WAITING;35 }36 do37 :: 1 ->38 atomic {39 assert(!shouldexit);40 shouldexit = dyntick_nohz_done;41 curr = dynticks_progress_counter;42 if43 :: (curr == snap) && ((curr & 1) == 0) ->44 break;45 :: (curr != snap) ->46 break;47 :: else -> skip;48 fi;49 }50 od;51 grace_period_state = GP_DONE;52 }We have added the shouldexit variable on line 5,which we initialize to zero on line 10. Line 17asserts that shouldexit is not set, while line 18sets shouldexit to the dyntick_nohz_done variablemaintained by dyntick_nohz(). This assertionwill therefore trigger if we attempt to take morethan one pass through the wait-for-counter-flipacknowledgementloop after dyntick_nohz() hascompleted execution. After all, if dyntick_nohz()isdone, thentherecannotbeanymorestatechangesto force us out of the loop, so going through twicein this state means an infinite loop, which in turnmeans no end to the grace period.Lines 32, 39, and 40 operate in a similar mannerfor the second (memory-barrier) loop.However, running this model(dyntickRCU-base-sl-busted.spin) resultsin failure, as line 23 is checking that the wrong variableis even. Upon failure, spin writes out a “trail”file (dyntickRCU-base-sl-busted.spin.trail)file, which records the sequence of states thatlead to the failure. Use the spin -t -p -g -ldyntickRCU-base-sl-busted.spin command tocause spin to retrace this sequence of state, printingthe statements executed and the values of variables(dyntickRCU-base-sl-busted.spin.trail.txt).Note that the line numbers do not matchthe listing above due to the fact that spintakes both functions in a single file. However,the line numbers do match the full model(dyntickRCU-base-sl-busted.spin).We see that the dyntick_nohz() process completedat step 34 (search for “34:”), but that thegrace_period() process nonetheless failed to exitthe loop. The value of curr is 6 (see step 35) andthat the value of snap is 5 (see step 17). Thereforethe first condition on line 21 above does not holdbecause curr!=snap, and the second condition online 23 does not hold either because snap is odd andbecause curr is only one greater than snap.<strong>So</strong> one of these two conditions has to be incorrect.Referring to the comment block in rcu_try_flip_waitack_needed() for the first condition:<strong>If</strong> the CPU remained in dynticks mode forthe entire time and didn’t take any interrupts,NM<strong>Is</strong>, SM<strong>Is</strong>, or whatever, then itcannot be in the middle of an rcu_read_lock(), so the next rcu_read_lock() itexecutes must use the new value of thecounter. <strong>So</strong> we can safely pretend that thisCPU already acknowledged the counter.The first condition does match this, because ifcurr==snap and if curr is even, then the correspondingCPU has been in dynticks-idle mode theentire time, as required. <strong>So</strong> let’s look at the commentblock for the second condition:<strong>If</strong> the CPU passed through or entered adynticks idle phase with no active irq handlers,then, as above, we can safely pretendthat this CPU already acknowledged thecounter.The first part of the condition is correct, becauseif curr and snap differ by two, there will be at leastone even number in between, corresponding to havingpassed completely through a dynticks-idle phase.However, the second part of the condition correspondsto having started in dynticks-idle mode, nothaving finished in this mode. We therefore need tobe testing curr rather than snap for being an evennumber.The corrected C code is as follows:1 static inline int2 rcu_try_flip_waitack_needed(int cpu)3 {4 long curr;5 long snap;67 curr = per_cpu(dynticks_progress_counter, cpu);8 snap = per_cpu(rcu_dyntick_snapshot, cpu);9 smp_mb();10 if ((curr == snap) && ((curr & 0x1) == 0))11 return 0;12 if ((curr - snap) > 2 || (curr & 0x1) == 0)13 return 0;14 return 1;15 }Lines 10-13 can now be combined and simplified,resulting in the following. A similar simplificationcan be applied to rcu_try_flip_waitmb_needed.1 static inline int2 rcu_try_flip_waitack_needed(int cpu)3 {4 long curr;5 long snap;6

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!