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.

E.7. PROMELA PARABLE: DYNTICKS AND PREEMPTABLE RCU 255called from the irq_enter() and irq_exit() interruptentry/exit functions. These rcu_irq_enter()and rcu_irq_exit() functions are needed to allowRCU to reliably handle situations where a dynticksidleCPUs is momentarily powered up for an interrupthandler containing RCU read-side critical sections.With these changes in place, Steve’s systembooted reliably, but Paul continued inspecting thecode periodically on the assumption that we couldnot possibly have gotten the code right on the firsttry.Paul reviewed the code repeatedly from October2007 to February 2008, and almost always found atleast one bug. In one case, Paul even coded andtestedafixbeforerealizingthatthebugwasillusory,and in fact in all cases, the “bug” turned out to beillusory.Near the end of February, Paul grew tired ofthis game. He therefore decided to enlist the aidof Promela and spin [Hol03], as described in AppendixE.ThefollowingpresentsaseriesofsevenincreasinglyrealisticPromelamodels,thelastofwhichpasses, consuming about 40GB of main memory forthe state space.More important, Promela and Spin did find a verysubtle bug for me!!!Quick Quiz E.6: Yeah, that’s great!!! Now, justwhat am I supposed to do if I don’t happen to havea machine with 40GB of main memory???Still better would be to come up with a simplerand faster algorithm that has a smaller state space.Even better would be an algorithm so simple thatits correctness was obvious to the casual observer!Section E.7.1 gives an overview of preemptableRCU’s dynticks interface, Section E.7.2, and SectionE.7.3 lists lessons (re)learned during this effort.E.7.1 Introduction to PreemptableRCU and dynticksThe per-CPU dynticks_progress_counter variableis central to the interface between dynticks andpreemptable RCU. This variable has an even valuewhenever the corresponding CPU is in dynticks-idlemode, and an odd value otherwise. A CPU exitsdynticks-idle mode for the following three reasons:1. to start running a task,2. when entering the outermost of a possiblynested set of interrupt handlers, and3. when entering an NMI handler.Preemptable RCU’s grace-period machinery samplesthe value of the dynticks_progress_countervariable in order to determine when a dynticks-idleCPU may safely be ignored.The following three sections give an overview ofthe task interface, the interrupt/NMI interface, andthe use of the dynticks_progress_counter variableby the grace-period machinery.E.7.1.1 Task InterfaceWhen a given CPU enters dynticks-idle mode becauseit has no more tasks to run, it invokes rcu_enter_nohz():1 static inline void rcu_enter_nohz(void)2 {3 mb();4 __get_cpu_var(dynticks_progress_counter)++;5 WARN_ON(__get_cpu_var(dynticks_progress_counter) & 0x1);6 }This function simply increments dynticks_progress_counter and checks that the result iseven, but first executing a memory barrier to ensurethat any other CPU that sees the new value ofdynticks_progress_counter will also see the completionof any prior RCU read-side critical sections.Similarly, when a CPU that is in dynticks-idlemode prepares to start executing a newly runnabletask, it invokes rcu_exit_nohz:1 static inline void rcu_exit_nohz(void)2 {3 __get_cpu_var(dynticks_progress_counter)++;4 mb();5 WARN_ON(!(__get_cpu_var(dynticks_progress_counter) &6 0x1));7 }This function again increments dynticks_progress_counter, but follows it with a memorybarrier to ensure that if any other CPU sees theresult of any subsequent RCU read-side criticalsection, then that other CPU will also see the incrementedvalue of dynticks_progress_counter.Finally, rcu_exit_nohz() checks that the result ofthe increment is an odd value.The rcu_enter_nohz() and rcu_exit_nohzfunctions handle the case where a CPU enters andexits dynticks-idle mode due to task execution, butdoes not handle interrupts, which are covered in thefollowing section.E.7.1.2 Interrupt InterfaceThe rcu_irq_enter() and rcu_irq_exit() functionshandle interrupt/NMI entry and exit, respectively.Of course, nested interrupts must also beproperly accounted for. The possibility of nestedinterrupts is handled by a second per-CPU variable,rcu_update_flag, which is incremented upon

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

Saved successfully!

Ooh no, something went wrong!