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