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