fileOperationRanks.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) 2022-2023 OpenCFD Ltd.
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 "fileOperation.H"
29 #include "stringOps.H"
30 #include "ITstream.H"
31 #include "Pstream.H"
32 #include "SHA1.H"
33 #include "OSspecific.H" // for hostName()
34 #include <cinttypes>
35 
36 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
37 
38 namespace Foam
39 {
40 
41 // Parse space, comma, semicolon separated list of integers, floats etc...
42 template<class PrimitiveType>
43 static List<PrimitiveType> splitStringToList(const std::string& str)
44 {
45  const SubStrings<std::string> items = stringOps::splitAny(str, " ,;");
46 
47  DynamicList<PrimitiveType> values(items.size());
48 
49  for (const auto& item : items)
50  {
51  const std::string s(item.str());
52 
53  PrimitiveType val;
54 
55  if (Foam::read(s, val))
56  {
57  values.push_back(val);
58  }
59  else
60  {
61  // Report errors? Could get noisy...
62  }
63  }
64 
65  return List<PrimitiveType>(std::move(values));
66 }
67 
68 } // End namespace Foam
69 
70 
71 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
72 
74 {
75  // Fast path - no IO ranks.
76  if (mainIOranks.empty())
77  {
78  return labelRange();
79  }
80 
81  // The lowest numbered rank is the IO rank
82  // - linear search for the enclosing range
83  // - fallback is proc = 0, which silently adds master (0) into IO ranks
84 
85  label begProc = 0;
86  label endProc = UPstream::nProcs(UPstream::worldComm);
87 
88  const label myProci = UPstream::myProcNo(UPstream::worldComm);
89 
90  forAllReverse(mainIOranks, i)
91  {
92  if (mainIOranks[i] <= myProci)
93  {
94  begProc = mainIOranks[i];
95  if (i+1 < mainIOranks.size())
96  {
97  endProc = mainIOranks[i+1];
98  }
99  break;
100  }
101  }
103  Pout<< "subRanks: " << labelRange(begProc, (endProc-begProc)) << endl;
104 
105  return labelRange(begProc, (endProc-begProc));
106 }
107 
108 
110 {
111  const label numProcs = UPstream::nProcs(UPstream::worldComm);
112 
113  // Use hostname
114  // Lowest rank per hostname is the IO rank
115 
116  List<SHA1Digest> digests;
118  {
119  digests.resize(numProcs);
120  }
121 
122  // Could also add lowercase etc, but since hostName()
123  // will be consistent within the same node, there is no need.
124  SHA1Digest myDigest(SHA1(hostName()).digest());
125 
126  // The fixed-length digest allows use of MPI_Gather
128  (
129  myDigest.cdata_bytes(), // Send
130  digests.data_bytes(), // Recv
131  SHA1Digest::max_size(), // Num send/recv per rank
133  );
134 
135  labelList ranks;
136  DynamicList<label> dynRanks;
137 
139  {
140  dynRanks.reserve(numProcs);
141 
142  dynRanks.push_back(0); // Always include master
143  label previ = 0;
144 
145  for (label proci = 1; proci < digests.size(); ++proci)
146  {
147  if (digests[proci] != digests[previ])
148  {
149  dynRanks.push_back(proci);
150  previ = proci;
151  }
152  }
153 
154  ranks.transfer(dynRanks);
155  }
158  return ranks;
159 }
160 
161 
163 (
164  // const bool useHost
165 )
166 {
167  // bool byHostName = useHost;
168  bool byHostName = false;
169 
170  DynamicList<label> dynRanks;
171 
172  Foam::string str(Foam::getEnv("FOAM_IORANKS"));
173 
174  if (!str.empty())
175  {
176  if (str.contains('('))
177  {
178  // Looks like a list - tokenise it
179  ITstream is(str);
180  if (!is.empty())
181  {
182  is >> dynRanks;
183  }
184  }
185  else if (str == "host")
186  {
187  // Select by hostname
188  byHostName = true;
189  }
190  else
191  {
192  // Manual parse
193  dynRanks = splitStringToList<label>(str);
194  }
195  }
196 
197  if (dynRanks.size())
198  {
199  if (!dynRanks.contains(0))
200  {
201  // Could also add silently
202  // dynRanks.push_back(0);
204  << "Rank 0 (master) should be in the IO ranks. Currently:" << nl
205  << " " << flatOutput(dynRanks) << nl
206  << exit(FatalError);
207  }
208 
209  // Never trust user input.
210  // Sort and eliminate any duplicates
211 
212  std::sort(dynRanks.begin(), dynRanks.end());
213 
214  if (dynRanks.front() < 0)
215  {
217  << "Cannot have negative ranks! Currently:" << nl
218  << " " << flatOutput(dynRanks) << nl
219  << exit(FatalError);
220  }
221 
222  labelList ranks;
223 
224  auto last = std::unique(dynRanks.begin(), dynRanks.end());
225 
226  if (last < dynRanks.end())
227  {
228  ranks = dynRanks.slice(0, (last - dynRanks.begin()));
229  }
230  else
231  {
232  ranks = dynRanks;
233  }
234 
235  return ranks;
236  }
237  else if (byHostName)
238  {
240  }
241 
242  return labelList();
243 }
244 
245 
246 bool Foam::fileOperation::isIOrank(const label proci) const
247 {
248  return
249  (
251  ? UPstream::master(comm_)
252  : ioRanks_.empty()
253  ? (proci == 0) // No io-ranks, assume single communicator
254  : ioRanks_.contains(proci) // Found proci in IO rank
255  );
256 }
257 
258 
260 {
261  // Collect the names of the IO masters
263  if (UPstream::master(comm_))
264  {
266  }
268 
269 
270  DynamicList<label> offsetMaster;
271 
272  // Calculate the offsets/counts
273 
275  {
276  label nHostRanks = 0;
277  forAll(hosts, ranki)
278  {
279  if (!hosts[ranki].empty())
280  {
281  ++nHostRanks;
282  }
283  }
284  offsetMaster.reserve(nHostRanks+1);
285 
286  forAll(hosts, ranki)
287  {
288  if (!hosts[ranki].empty())
289  {
290  offsetMaster.push_back(ranki);
291  }
292  }
293 
294  // End of range is nProcs
295  offsetMaster.push_back(hosts.size());
296  }
297 
298  if (offsetMaster.size() > 2)
299  {
300  DetailInfo
301  << "I/O on :" << nl << '(' << nl;
302  for (label group = 1; group < offsetMaster.size(); ++group)
303  {
304  const label beg = offsetMaster[group-1];
305  const label end = offsetMaster[group];
306 
307  DetailInfo
308  << " (" << hosts[beg].c_str() << ' '
309  << (end-beg) << ')' << nl;
310  }
311  DetailInfo
312  << ')' << nl;
313  }
314 }
315 
316 
317 // ************************************************************************* //
bool contains(const T &val, label pos=0) const
Is the value contained in the list?
Definition: UListI.H:257
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:116
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
void resize(const label len)
Adjust allocated size of list.
Definition: ListI.H:132
error FatalError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL ERROR&#39; header text and sta...
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:578
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: BitOps.H:56
static labelList getGlobalHostIORanks()
Get list of global IO master ranks based on the hostname. It is assumed that each host range is conti...
A range or interval of labels defined by a start and a size.
Definition: labelRange.H:51
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
T & front()
Access first element of the list, position [0].
Definition: UListI.H:194
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1004
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1184
string getEnv(const std::string &envName)
Get environment value for given envName.
Definition: POSIX.C:339
static int myProcNo(const label communicator=worldComm)
Rank of this process in the communicator (starting from masterNo()). Can be negative if the process i...
Definition: UPstream.H:1029
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:411
Sub-ranges of a string with a structure similar to std::match_results, but without the underlying reg...
Definition: CStringList.H:57
void push_back(const T &val)
Append an element at the end of the list.
Definition: ListI.H:185
char * data_bytes() noexcept
Return pointer to the underlying array serving as data storage,.
Definition: UListI.H:243
UList< label > labelUList
A UList of labels.
Definition: UList.H:78
static void broadcast(Type &value, const label comm=UPstream::worldComm)
Broadcast content (contiguous or non-contiguous) to all processes in communicator.
bool read(const char *buf, int32_t &val)
Same as readInt32.
Definition: int32.H:127
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:414
constexpr const char *const group
Group name for atomic constants.
List< T > values(const HashTable< T, Key, Hash > &tbl, const bool doSort=false)
List of values from HashTable, optionally sorted.
Definition: HashOps.H:164
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
static label nProcs(const label communicator=worldComm)
Number of ranks in parallel run (for given communicator). It is 1 for serial run. ...
Definition: UPstream.H:1020
static void gatherList(const List< commsStruct > &comms, List< T > &values, const int tag, const label comm)
Gather data, but keep individual values separate. Uses the specified communication schedule...
A 1D vector of objects of type <T> that resizes itself as necessary to accept the new objects...
Definition: DynamicList.H:51
SubList< T > slice(const label pos, label len=-1)
Return SubList slice (non-const access) - no range checking.
Definition: SubList.H:192
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:348
static void mpiGather(const char *sendData, char *recvData, int count, const label communicator=worldComm)
Receive identically-sized char data from all ranks.
#define DetailInfo
Definition: evalEntry.C:30
iterator begin() noexcept
Return an iterator to begin traversing the UList.
Definition: UListI.H:321
string hostName()
Return the system&#39;s host name, as per hostname(1)
Definition: POSIX.C:371
constexpr auto end(C &c) -> decltype(c.end())
Return iterator to the end of the container c.
Definition: stdFoam.H:194
static labelRange subRanks(const labelUList &mainIOranks)
Get (contiguous) range/bounds of ranks addressed within the given main io-ranks.
Foam::SubStrings< StringType > splitAny(const StringType &str, const std::string &delim)
Split string into sub-strings using any characters in delimiter.
void printRanks() const
Helper: output which ranks are IO.
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1037
static constexpr unsigned max_size() noexcept
The dimensioned size of the digest is always 20 bytes.
Definition: SHA1Digest.H:180
static List< PrimitiveType > splitStringToList(const std::string &str)
bool isIOrank(const label proci) const
Is proci a master rank in the communicator (in parallel) or a master rank in the IO ranks (non-parall...
#define forAllReverse(list, i)
Reverse loop across all elements in list.
Definition: stdFoam.H:430
static labelList getGlobalIORanks()
Get list of global IO ranks from FOAM_IORANKS env variable. If set, these correspond to the IO master...
iterator end() noexcept
Return an iterator to end traversing the UList.
Definition: UListI.H:365
List< label > labelList
A List of labels.
Definition: List.H:62
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
A class for handling character strings derived from std::string.
Definition: string.H:72
prefixOSstream Pout
OSstream wrapped stdout (std::cout) with parallel prefix.
An input stream of tokens.
Definition: ITstream.H:48
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225