Loading...
Searching...
No Matches
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-2023 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 "IOstreams.H"
31#include "IOmanip.H"
33#include "Pstream.H"
34
35// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
36
37namespace Foam
38{
40}
41
43// * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
44
45namespace Foam
46{
47
48// Count the number of outstanding communications for a single processor
49static label outstandingComms
50(
51 const labelUList& commToSchedule,
52 const labelUList& procComms
53)
54{
55 label nOutstanding = 0;
56
57 for (const label commPairi : procComms)
58 {
59 if (commToSchedule[commPairi] == -1)
60 {
61 ++nOutstanding;
62 }
63 }
64 return nOutstanding;
66
67} // End namespace Foam
68
69
70// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
71
73(
74 const label nProcs,
75 const List<labelPair>& comms
76)
77:
78 schedule_(comms.size()),
79 procSchedule_(nProcs)
80{
81 // Determine comms per processor.
82 List<DynamicList<label>> procToComms(nProcs);
83
84 forAll(comms, commPairi)
85 {
86 const label proc0 = comms[commPairi].first();
87 const label proc1 = comms[commPairi].second();
88
89 if (proc0 < 0 || proc0 >= nProcs || proc1 < 0 || proc1 >= nProcs)
90 {
92 << "Illegal processor(s): "
93 << comms[commPairi] << abort(FatalError);
94 }
95
96 procToComms[proc0].push_back(commPairi);
97 procToComms[proc1].push_back(commPairi);
98 }
99 // Note: no need to shrink procToComms. Are small.
100
101 if (debug && UPstream::master())
102 {
103 Pout<< "commSchedule : Wanted communication:" << endl;
104
105 forAll(comms, i)
106 {
107 const labelPair& twoProcs = comms[i];
108
109 Pout<< i << ": "
110 << twoProcs.first() << " <-> " << twoProcs.second() << endl;
111 }
112 Pout<< endl;
113
114
115 Pout<< "commSchedule : Schedule:" << endl;
116
117 // Print header. Use buffered output to prevent parallel output messing
118 // up.
119 {
120 OStringStream os;
121 os << "iter|";
122 for (int i = 0; i < nProcs; i++)
123 {
124 os << setw(3) << i;
125 }
126 Pout<< os.str().c_str() << endl;
127 }
128 {
129 OStringStream os;
130 os << "----+";
131 for (int i = 0; i < nProcs; i++)
132 {
133 os << "---";
134 }
135 Pout<< os.str().c_str() << endl;
136 }
137 }
138
139 // Schedule all. Note: crap scheduler. Assumes all communication takes
140 // equally long.
141
142 label nScheduled = 0;
143
144 label iter = 0;
145
146 // Per index into comms the time when it was scheduled
147 labelList commToSchedule(comms.size(), -1);
148
149 while (nScheduled < comms.size())
150 {
151 label oldNScheduled = nScheduled;
152
153 // Find unscheduled comms. This is the comms where the two processors
154 // still have the most unscheduled comms.
155
156 boolList busy(nProcs, false);
157
158 while (true)
159 {
160 label maxComm = -1;
161 label maxNeed = labelMin;
162
163 forAll(comms, commPairi)
164 {
165 const label proc0 = comms[commPairi].first();
166 const label proc1 = comms[commPairi].second();
167
168 if
169 (
170 commToSchedule[commPairi] == -1 // unscheduled
171 && !busy[proc0]
172 && !busy[proc1]
173 )
174 {
175 label need =
176 (
177 outstandingComms(commToSchedule, procToComms[proc0])
178 + outstandingComms(commToSchedule, procToComms[proc1])
179 );
180
181 if (maxNeed < need)
182 {
183 maxNeed = need;
184 maxComm = commPairi;
185 }
186 }
187 }
188
189
190 if (maxComm == -1)
191 {
192 // Found no unscheduled procs.
193 break;
194 }
195
196 // Schedule commPairi in this iteration
197 commToSchedule[maxComm] = nScheduled++;
198 busy[comms[maxComm].first()] = true;
199 busy[comms[maxComm].second()] = true;
200 }
201
202 if (debug && UPstream::master())
203 {
204 label nIterComms = nScheduled-oldNScheduled;
205
206 if (nIterComms > 0)
207 {
208 labelList procToComm(nProcs, -1);
209
210 forAll(commToSchedule, commPairi)
211 {
212 const label sched = commToSchedule[commPairi];
213
214 if (sched >= oldNScheduled && sched < nScheduled)
215 {
216 const label proc0 = comms[commPairi].first();
217 const label proc1 = comms[commPairi].second();
218 procToComm[proc0] = commPairi;
219 procToComm[proc1] = commPairi;
220 }
221 }
222
223 // Print it
224 OStringStream os;
225 os << setw(3) << iter << " |";
226 forAll(procToComm, proci)
227 {
228 if (procToComm[proci] == -1)
229 {
230 os << " ";
231 }
232 else
233 {
234 os << setw(3) << procToComm[proci];
235 }
236 }
237 Pout<< os.str().c_str() << endl;
238 }
239 }
240
241 iter++;
242 }
243
244 if (debug && UPstream::master())
245 {
246 Pout<< endl;
247 }
248
249
250 // Sort commToSchedule to obtain order in comms
251
252 Foam::sortedOrder(commToSchedule, schedule_);
253
254 // Sort schedule_ by processor
255
256 labelList nProcScheduled(nProcs, Zero);
257
258 // Count
259 for (const label commPairi : schedule_)
260 {
261 const labelPair& twoProcs = comms[commPairi];
262
263 nProcScheduled[twoProcs.first()]++;
264 nProcScheduled[twoProcs.second()]++;
265 }
266
267 // Allocate
268 forAll(procSchedule_, proci)
269 {
270 procSchedule_[proci].resize_nocopy(nProcScheduled[proci]);
271 }
272
273 nProcScheduled = 0;
274
275 // Fill
276 for (const label commPairi : schedule_)
277 {
278 const labelPair& twoProcs = comms[commPairi];
279
280 const label proc0 = twoProcs.first();
281 const label proc1 = twoProcs.second();
282
283 procSchedule_[proc0][nProcScheduled[proc0]++] = commPairi;
284 procSchedule_[proc1][nProcScheduled[proc1]++] = commPairi;
285 }
286
287 if (debug && UPstream::master())
288 {
289 Pout<< "commSchedule::commSchedule : Per processor:" << endl;
290
291 forAll(procSchedule_, proci)
292 {
293 const labelList& procComms = procSchedule_[proci];
294
295 Pout<< "Processor " << proci << " talks to processors:" << endl;
296
297 for (const label commPairi : procComms)
298 {
299 const labelPair& twoProcs = comms[commPairi];
300
301 Pout<< " "
302 << (proci == twoProcs[1] ? twoProcs[0] : twoProcs[1])
303 << endl;
304 }
305 }
306 Pout<< endl;
307 }
308}
309
310
311// ************************************************************************* //
Istream and Ostream manipulators taking arguments.
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Input/output from string buffers.
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition List.H:72
void push_back(const T &val)
Append an element at the end of the list.
Definition ListI.H:221
Output to string buffer, using a OSstream. Always UNCOMPRESSED.
const T & first() const noexcept
Access the first element.
Definition Pair.H:137
const T & second() const noexcept
Access the second element.
Definition Pair.H:147
T & first()
Access first element of the list, position [0].
Definition UList.H:957
void size(const label n)
Older name for setAddressableSize.
Definition UList.H:118
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition UPstream.H:1714
Determines the order in which a set of processors should communicate with one another.
commSchedule(const label nProcs, const List< labelPair > &comms)
Construct from wanted communication. Wanted communication is between two processors....
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition className.H:142
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition error.H:600
OBJstream os(runTime.globalPath()/outputName)
Namespace for handling debugging switches.
Definition debug.C:45
Namespace for OpenFOAM.
Pair< label > labelPair
A pair of labels.
Definition Pair.H:54
static label outstandingComms(const labelUList &commToSchedule, const labelUList &procComms)
List< label > labelList
A List of labels.
Definition List.H:62
constexpr label labelMin
Definition label.H:54
Omanip< int > setw(const int i)
Definition IOmanip.H:199
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition Ostream.H:519
labelList sortedOrder(const UList< T > &input)
Return the (stable) sort order for the list.
errorManip< error > abort(error &err)
Definition errorManip.H:139
List< bool > boolList
A List of bools.
Definition List.H:60
static constexpr const zero Zero
Global zero (0).
Definition zero.H:127
error FatalError
Error stream (stdout output on all processes), with additional 'FOAM FATAL ERROR' header text and sta...
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
UList< label > labelUList
A UList of labels.
Definition UList.H:75
#define forAll(list, i)
Loop across all elements in list.
Definition stdFoam.H:299