commSchedule.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9 -------------------------------------------------------------------------------
10 License
11  This file is part of OpenFOAM.
12 
13  OpenFOAM is free software: you can redistribute it and/or modify it
14  under the terms of the GNU General Public License as published by
15  the Free Software Foundation, either version 3 of the License, or
16  (at your option) any later version.
17 
18  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
19  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
20  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
21  for more details.
22 
23  You should have received a copy of the GNU General Public License
24  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "commSchedule.H"
29 #include "SortableList.H"
30 #include "boolList.H"
31 #include "IOstreams.H"
32 #include "IOmanip.H"
33 #include "StringStream.H"
34 #include "Pstream.H"
35 
36 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40  defineTypeNameAndDebug(commSchedule, 0);
41 }
42 
43 
44 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
45 
46 Foam::label Foam::commSchedule::outstandingComms
47 (
48  const labelList& commToSchedule,
49  DynamicList<label>& procComms
50 ) const
51 {
52  label nOutstanding = 0;
53 
54  forAll(procComms, i)
55  {
56  if (commToSchedule[procComms[i]] == -1)
57  {
58  nOutstanding++;
59  }
60  }
61  return nOutstanding;
62 }
63 
64 
65 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
66 
68 (
69  const label nProcs,
70  const List<labelPair>& comms
71 )
72 :
73  schedule_(comms.size()),
74  procSchedule_(nProcs)
75 {
76  // Determine comms per processor.
77  List<DynamicList<label>> procToComms(nProcs);
78 
79  forAll(comms, commI)
80  {
81  label proc0 = comms[commI][0];
82  label proc1 = comms[commI][1];
83 
84  if (proc0 < 0 || proc0 >= nProcs || proc1 < 0 || proc1 >= nProcs)
85  {
87  << "Illegal processor " << comms[commI] << abort(FatalError);
88  }
89 
90  procToComms[proc0].append(commI);
91  procToComms[proc1].append(commI);
92  }
93  // Note: no need to shrink procToComms. Are small.
94 
95  if (debug && Pstream::master())
96  {
97  Pout<< "commSchedule::commSchedule : Wanted communication:" << endl;
98 
99  forAll(comms, i)
100  {
101  const labelPair& twoProcs = comms[i];
102 
103  Pout<< i << ": "
104  << twoProcs[0] << " with " << twoProcs[1] << endl;
105  }
106  Pout<< endl;
107 
108 
109  Pout<< "commSchedule::commSchedule : Schedule:" << endl;
110 
111  // Print header. Use buffered output to prevent parallel output messing
112  // up.
113  {
115  os << "iter|";
116  for (int i = 0; i < nProcs; i++)
117  {
118  os << setw(3) << i;
119  }
120  Pout<< os.str().c_str() << endl;
121  }
122  {
124  os << "----+";
125  for (int i = 0; i < nProcs; i++)
126  {
127  os << "---";
128  }
129  Pout<< os.str().c_str() << endl;
130  }
131  }
132 
133  // Schedule all. Note: crap scheduler. Assumes all communication takes
134  // equally long.
135 
136  label nScheduled = 0;
137 
138  label iter = 0;
139 
140  // Per index into comms the time when it was scheduled
141  labelList commToSchedule(comms.size(), -1);
142 
143  while (nScheduled < comms.size())
144  {
145  label oldNScheduled = nScheduled;
146 
147  // Find unscheduled comms. This is the comms where the two processors
148  // still have the most unscheduled comms.
149 
150  boolList busy(nProcs, false);
151 
152  while (true)
153  {
154  label maxCommI = -1;
155  label maxNeed = labelMin;
156 
157  forAll(comms, commI)
158  {
159  label proc0 = comms[commI][0];
160  label proc1 = comms[commI][1];
161 
162  if
163  (
164  commToSchedule[commI] == -1 // unscheduled
165  && !busy[proc0]
166  && !busy[proc1]
167  )
168  {
169  label need =
170  outstandingComms(commToSchedule, procToComms[proc0])
171  + outstandingComms(commToSchedule, procToComms[proc1]);
172 
173  if (need > maxNeed)
174  {
175  maxNeed = need;
176  maxCommI = commI;
177  }
178  }
179  }
180 
181 
182  if (maxCommI == -1)
183  {
184  // Found no unscheduled procs.
185  break;
186  }
187 
188  // Schedule commI in this iteration
189  commToSchedule[maxCommI] = nScheduled++;
190  busy[comms[maxCommI][0]] = true;
191  busy[comms[maxCommI][1]] = true;
192  }
193 
194  if (debug && Pstream::master())
195  {
196  label nIterComms = nScheduled-oldNScheduled;
197 
198  if (nIterComms > 0)
199  {
200  labelList procToComm(nProcs, -1);
201 
202  forAll(commToSchedule, commI)
203  {
204  label sched = commToSchedule[commI];
205 
206  if (sched >= oldNScheduled && sched < nScheduled)
207  {
208  label proc0 = comms[commI][0];
209  procToComm[proc0] = commI;
210  label proc1 = comms[commI][1];
211  procToComm[proc1] = commI;
212  }
213  }
214 
215  // Print it
217  os << setw(3) << iter << " |";
218  forAll(procToComm, proci)
219  {
220  if (procToComm[proci] == -1)
221  {
222  os << " ";
223  }
224  else
225  {
226  os << setw(3) << procToComm[proci];
227  }
228  }
229  Pout<< os.str().c_str() << endl;
230  }
231  }
232 
233  iter++;
234  }
235 
236  if (debug && Pstream::master())
237  {
238  Pout<< endl;
239  }
240 
241 
242  // Sort commToSchedule and obtain order in comms
243  schedule_ = SortableList<label>(commToSchedule).indices();
244 
245  // Sort schedule_ by processor
246 
247  labelList nProcScheduled(nProcs, Zero);
248 
249  // Count
250  forAll(schedule_, i)
251  {
252  label commI = schedule_[i];
253  const labelPair& twoProcs = comms[commI];
254 
255  nProcScheduled[twoProcs[0]]++;
256  nProcScheduled[twoProcs[1]]++;
257  }
258  // Allocate
259  forAll(procSchedule_, proci)
260  {
261  procSchedule_[proci].setSize(nProcScheduled[proci]);
262  }
263  nProcScheduled = 0;
264  // Fill
265  forAll(schedule_, i)
266  {
267  label commI = schedule_[i];
268  const labelPair& twoProcs = comms[commI];
269 
270  label proc0 = twoProcs[0];
271  procSchedule_[proc0][nProcScheduled[proc0]++] = commI;
272 
273  label proc1 = twoProcs[1];
274  procSchedule_[proc1][nProcScheduled[proc1]++] = commI;
275  }
276 
277  if (debug && Pstream::master())
278  {
279  Pout<< "commSchedule::commSchedule : Per processor:" << endl;
280 
281  forAll(procSchedule_, proci)
282  {
283  const labelList& procComms = procSchedule_[proci];
284 
285  Pout<< "Processor " << proci << " talks to processors:" << endl;
286 
287  forAll(procComms, i)
288  {
289  const labelPair& twoProcs = comms[procComms[i]];
290 
291  label nbr = (twoProcs[1] == proci ? twoProcs[0] : twoProcs[1]);
292 
293  Pout<< " " << nbr << endl;
294  }
295  }
296  Pout<< endl;
297  }
298 }
299 
300 
301 // ************************************************************************* //
Foam::expressions::patchExpr::debug
int debug
Static debugging option.
Foam::labelList
List< label > labelList
A List of labels.
Definition: List.H:67
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
boolList.H
Foam::Zero
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:457
StringStream.H
Input/output from string buffers.
Foam::List::append
void append(const T &val)
Append an element at the end of the list.
Definition: ListI.H:175
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:369
Foam::Pout
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:296
commSchedule.H
SortableList.H
IOmanip.H
Istream and Ostream manipulators taking arguments.
Foam::FatalError
error FatalError
os
OBJstream os(runTime.globalPath()/outputName)
Foam::SortableList
A list that is sorted upon construction or when explicitly requested with the sort() method.
Definition: List.H:60
Pstream.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:144
Foam::setw
Omanip< int > setw(const int i)
Definition: IOmanip.H:199
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
Foam::Pair< label >
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:63
Foam::OStringStream
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
Definition: StringStream.H:227
Foam::SortableList::indices
const labelList & indices() const
Return the list of sorted indices. Updated every sort.
Definition: SortableList.H:108
Foam::labelMin
constexpr label labelMin
Definition: label.H:60
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::commSchedule::commSchedule
commSchedule(const label nProcs, const List< labelPair > &comms)
Construct from wanted communication. Wanted communication is between.
Definition: commSchedule.C:68