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

You also want an ePaper? Increase the reach of your titles

YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.

E.7. PROMELA PARABLE: DYNTICKS AND PREEMPTABLE RCU 25936 :: (curr == snap) && ((curr & 1) == 0) ->37 break;38 :: (curr != snap) ->39 break;40 :: 1 -> skip;41 fi;42 }43 od;44 grace_period_state = GP_DONE;45 }Lines 6, 10, 25, 26, 29, and 44 update this variable(combining atomically with algorithmic operationswhere feasible) to allow the dyntick_nohz() processto verify the basic RCU safety property. Theform of this verification is to assert that the valueof the grace_period_state variable cannot jumpfrom GP_IDLE to GP_DONE during a time period overwhich RCU readers could plausibly persist.Quick Quiz E.13: Giventhereareapairofbackto-backchanges to grace_period_state on lines 25and 26, how can we be sure that line 25’s changeswon’t be lost?The dyntick_nohz() Promela process implementsthis verification as shown below:1 proctype dyntick_nohz()2 {3 byte tmp;4 byte i = 0;5 bit old_gp_idle;67 do8 :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;9 :: i < MAX_DYNTICK_LOOP_NOHZ ->10 tmp = dynticks_progress_counter;11 atomic {12 dynticks_progress_counter = tmp + 1;13 old_gp_idle = (grace_period_state == GP_IDLE);14 assert((dynticks_progress_counter & 1) == 1);15 }16 atomic {17 tmp = dynticks_progress_counter;18 assert(!old_gp_idle ||19 grace_period_state != GP_DONE);20 }21 atomic {22 dynticks_progress_counter = tmp + 1;23 assert((dynticks_progress_counter & 1) == 0);24 }25 i++;26 od;27 }Line 13 sets a new old_gp_idle flag if the valueof the grace_period_state variable is GP_IDLE atthe beginning of task execution, and the assertionat lines 18 and 19 fire if the grace_period_statevariable has advanced to GP_DONE during task execution,which would be illegal given that a singleRCU read-side critical section could span the entireintervening time period.Theresultingmodel(dyntickRCU-base-s.spin),when run with the runspin.sh script, generates 964statesandpasseswithouterrors, whichisreassuring.That said, although safety is critically important, itis also quite important to avoid indefinitely stallinggrace periods. The next section therefore covers verifyingliveness.E.7.2.3 Validating LivenessAlthough liveness can be difficult to prove, there isa simple trick that applies here. The first step is tomake dyntick_nohz() indicate that it is done via adyntick_nohz_done variable, as shown on line 27 ofthe following:1 proctype dyntick_nohz()2 {3 byte tmp;4 byte i = 0;5 bit old_gp_idle;67 do8 :: i >= MAX_DYNTICK_LOOP_NOHZ -> break;9 :: i < MAX_DYNTICK_LOOP_NOHZ ->10 tmp = dynticks_progress_counter;11 atomic {12 dynticks_progress_counter = tmp + 1;13 old_gp_idle = (grace_period_state == GP_IDLE);14 assert((dynticks_progress_counter & 1) == 1);15 }16 atomic {17 tmp = dynticks_progress_counter;18 assert(!old_gp_idle ||19 grace_period_state != GP_DONE);20 }21 atomic {22 dynticks_progress_counter = tmp + 1;23 assert((dynticks_progress_counter & 1) == 0);24 }25 i++;26 od;27 dyntick_nohz_done = 1;28 }With this variable in place, we can add assertionsto grace_period() to check for unnecessary blockageas follows:1 proctype grace_period()2 {3 byte curr;4 byte snap;5 bit shouldexit;67 grace_period_state = GP_IDLE;8 atomic {9 printf("MDLN = %d\n", MAX_DYNTICK_LOOP_NOHZ);10 shouldexit = 0;11 snap = dynticks_progress_counter;12 grace_period_state = GP_WAITING;13 }14 do15 :: 1 ->16 atomic {17 assert(!shouldexit);18 shouldexit = dyntick_nohz_done;19 curr = dynticks_progress_counter;20 if21 :: (curr == snap) && ((curr & 1) == 0) ->22 break;23 :: (curr - snap) > 2 || (snap & 1) == 0 ->24 break;25 :: else -> skip;26 fi;27 }28 od;29 grace_period_state = GP_DONE;30 grace_period_state = GP_IDLE;31 atomic {

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

Saved successfully!

Ooh no, something went wrong!