1 #ifndef LIBGEODECOMP_PARALLELIZATION_HIPARSIMULATOR_VANILLASTEPPER_H 2 #define LIBGEODECOMP_PARALLELIZATION_HIPARSIMULATOR_VANILLASTEPPER_H 3 4 #include <libgeodecomp/parallelization/hiparsimulator/commonstepper.h> 5 #include <libgeodecomp/storage/updatefunctor.h> 6 7 namespace LibGeoDecomp { 8 namespace HiParSimulator { 9 10 /** 11 * As its name implies, the VanillaStepper is the simplest 12 * implementation of the Stepper concept: single threaded and no 13 * accelerator offloading. It does however overlap communication and 14 * calculation and support wide halos (halos = ghostzones). Ghost 15 * zones of width k mean that synchronization only needs to be done 16 * every k'th (nano) step. 17 */ 18 template<typename CELL_TYPE> 19 class VanillaStepper : public CommonStepper<CELL_TYPE> 20 { 21 public: 22 friend class VanillaStepperRegionTest; 23 friend class VanillaStepperBasicTest; 24 friend class VanillaStepperTest; 25 26 typedef typename Stepper<CELL_TYPE>::Topology Topology; 27 const static int DIM = Topology::DIM; 28 const static unsigned NANO_STEPS = APITraits::SelectNanoSteps<CELL_TYPE>::VALUE; 29 30 typedef class CommonStepper<CELL_TYPE> ParentType; 31 typedef typename ParentType::GridType GridType; 32 typedef PartitionManager<Topology> PartitionManagerType; 33 typedef PatchBufferFixed<GridType, GridType, 1> PatchBufferType1; 34 typedef PatchBufferFixed<GridType, GridType, 2> PatchBufferType2; 35 typedef typename ParentType::PatchAccepterVec PatchAccepterVec; 36 37 using CommonStepper<CELL_TYPE>::initializer; 38 using CommonStepper<CELL_TYPE>::patchAccepters; 39 using CommonStepper<CELL_TYPE>::patchProviders; 40 using CommonStepper<CELL_TYPE>::partitionManager; 41 using CommonStepper<CELL_TYPE>::chronometer; 42 using CommonStepper<CELL_TYPE>::notifyPatchAccepters; 43 using CommonStepper<CELL_TYPE>::notifyPatchProviders; 44 45 using CommonStepper<CELL_TYPE>::innerSet; 46 using CommonStepper<CELL_TYPE>::saveKernel; 47 using CommonStepper<CELL_TYPE>::restoreRim; 48 using CommonStepper<CELL_TYPE>::globalNanoStep; 49 using CommonStepper<CELL_TYPE>::rim; 50 using CommonStepper<CELL_TYPE>::resetValidGhostZoneWidth; 51 using CommonStepper<CELL_TYPE>::initGridsCommon; 52 using CommonStepper<CELL_TYPE>::getVolatileKernel; 53 using CommonStepper<CELL_TYPE>::saveRim; 54 using CommonStepper<CELL_TYPE>::getInnerRim; 55 using CommonStepper<CELL_TYPE>::restoreKernel; 56 57 using CommonStepper<CELL_TYPE>::curStep; 58 using CommonStepper<CELL_TYPE>::curNanoStep; 59 using CommonStepper<CELL_TYPE>::validGhostZoneWidth; 60 using CommonStepper<CELL_TYPE>::ghostZoneWidth; 61 using CommonStepper<CELL_TYPE>::oldGrid; 62 using CommonStepper<CELL_TYPE>::newGrid; 63 using CommonStepper<CELL_TYPE>::rimBuffer; 64 using CommonStepper<CELL_TYPE>::kernelBuffer; 65 using CommonStepper<CELL_TYPE>::kernelFraction; 66 67 inline VanillaStepper( 68 boost::shared_ptr<PartitionManagerType> partitionManager, 69 boost::shared_ptr<Initializer<CELL_TYPE> > initializer, 70 const PatchAccepterVec& ghostZonePatchAccepters = PatchAccepterVec(), 71 const PatchAccepterVec& innerSetPatchAccepters = PatchAccepterVec()) : 72 CommonStepper<CELL_TYPE>( 73 partitionManager, 74 initializer, 75 ghostZonePatchAccepters, 76 innerSetPatchAccepters) 77 { 78 initGrids(); 79 } 80 81 private: update1()82 inline void update1() 83 { 84 TimeTotal t(&chronometer); 85 unsigned index = ghostZoneWidth() - --validGhostZoneWidth; 86 const Region<DIM>& region = innerSet(index); 87 { 88 TimeComputeInner t(&chronometer); 89 90 UpdateFunctor<CELL_TYPE>()( 91 region, 92 Coord<DIM>(), 93 Coord<DIM>(), 94 *oldGrid, 95 &*newGrid, 96 curNanoStep); 97 std::swap(oldGrid, newGrid); 98 99 ++curNanoStep; 100 if (curNanoStep == NANO_STEPS) { 101 curNanoStep = 0; 102 ++curStep; 103 } 104 } 105 106 notifyPatchAccepters(region, ParentType::INNER_SET, globalNanoStep()); 107 108 if (validGhostZoneWidth == 0) { 109 updateGhost(); 110 resetValidGhostZoneWidth(); 111 } 112 113 notifyPatchProviders(region, ParentType::INNER_SET, globalNanoStep()); 114 } 115 initGrids()116 inline void initGrids() 117 { 118 initGridsCommon(); 119 120 notifyPatchAccepters( 121 rim(), 122 ParentType::GHOST, 123 globalNanoStep()); 124 notifyPatchAccepters( 125 innerSet(0), 126 ParentType::INNER_SET, 127 globalNanoStep()); 128 129 saveRim(globalNanoStep()); 130 updateGhost(); 131 } 132 133 /** 134 * computes the next ghost zone at time "t_1 = globalNanoStep() + 135 * ghostZoneWidth()". Expects that oldGrid has its kernel and its 136 * outer ghostzone updated to time "globalNanoStep()" and that the 137 * inner ghostzones (rim) at time t_1 can be retrieved from the 138 * internal patch buffer. Will leave oldgrid in a state so that 139 * its whole ownRegion() will be at time t_1 and the rim will be 140 * saved to the patchBuffer at "t2 = t1 + ghostZoneWidth()". 141 */ updateGhost()142 inline void updateGhost() 143 { 144 { 145 TimeComputeGhost t(&chronometer); 146 147 // fixme: skip all this ghost zone buffering for 148 // ghostZoneWidth == 1? 149 150 // 1: Prepare grid. The following update of the ghostzone will 151 // destroy parts of the kernel, which is why we'll 152 // save/restore those. 153 saveKernel(); 154 // We need to restore the rim since it got destroyed while the 155 // kernel was updated. 156 restoreRim(false); 157 } 158 159 // 2: actual ghostzone update 160 std::size_t oldNanoStep = curNanoStep; 161 std::size_t oldStep = curStep; 162 std::size_t curGlobalNanoStep = globalNanoStep(); 163 164 for (std::size_t t = 0; t < ghostZoneWidth(); ++t) { 165 notifyPatchProviders(rim(t), ParentType::GHOST, globalNanoStep()); 166 167 { 168 TimeComputeGhost timer(&chronometer); 169 170 const Region<DIM>& region = rim(t + 1); 171 UpdateFunctor<CELL_TYPE>()( 172 region, 173 Coord<DIM>(), 174 Coord<DIM>(), 175 *oldGrid, 176 &*newGrid, 177 curNanoStep); 178 179 ++curNanoStep; 180 if (curNanoStep == NANO_STEPS) { 181 curNanoStep = 0; 182 curStep++; 183 } 184 185 std::swap(oldGrid, newGrid); 186 187 ++curGlobalNanoStep; 188 } 189 190 notifyPatchAccepters(rim(), ParentType::GHOST, curGlobalNanoStep); 191 } 192 193 { 194 TimeComputeGhost t(&chronometer); 195 curNanoStep = oldNanoStep; 196 curStep = oldStep; 197 198 saveRim(curGlobalNanoStep); 199 if (ghostZoneWidth() % 2) { 200 std::swap(oldGrid, newGrid); 201 } 202 203 // 3: restore grid for kernel update 204 restoreRim(true); 205 restoreKernel(); 206 } 207 } 208 }; 209 210 } 211 } 212 213 #endif 214