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  }
102 
103  return labelRange(begProc, (endProc-begProc));
104 }
105 
106 
108 {
109  const label numProcs = UPstream::nProcs(UPstream::worldComm);
110 
111  // Use hostname
112  // Lowest rank per hostname is the IO rank
113 
114  List<SHA1Digest> digests;
116  {
117  digests.resize(numProcs);
118  }
119 
120  // Could also add lowercase etc, but since hostName()
121  // will be consistent within the same node, there is no need.
122  SHA1Digest myDigest(SHA1(hostName()).digest());
123 
124  // The fixed-length digest allows use of MPI_Gather
126  (
127  myDigest.cdata_bytes(), // Send
128  digests.data_bytes(), // Recv
129  SHA1Digest::max_size(), // Num send/recv per rank
131  );
132 
133  labelList ranks;
134  DynamicList<label> dynRanks;
135 
137  {
138  dynRanks.reserve(numProcs);
139 
140  dynRanks.push_back(0); // Always include master
141  label previ = 0;
142 
143  for (label proci = 1; proci < digests.size(); ++proci)
144  {
145  if (digests[proci] != digests[previ])
146  {
147  dynRanks.push_back(proci);
148  previ = proci;
149  }
150  }
151 
152  ranks.transfer(dynRanks);
153  }
156  return ranks;
157 }
158 
159 
161 (
162  // const bool useHost
163 )
164 {
165  // bool byHostName = useHost;
166  bool byHostName = false;
167 
168  DynamicList<label> dynRanks;
169 
170  Foam::string str(Foam::getEnv("FOAM_IORANKS"));
171 
172  if (!str.empty())
173  {
174  if (str.contains('('))
175  {
176  // Looks like a list - tokenise it
177  ITstream is(str);
178  if (!is.empty())
179  {
180  is >> dynRanks;
181  }
182  }
183  else if (str == "host")
184  {
185  // Select by hostname
186  byHostName = true;
187  }
188  else
189  {
190  // Manual parse
191  dynRanks = splitStringToList<label>(str);
192  }
193  }
194 
195  if (dynRanks.size())
196  {
197  if (!dynRanks.contains(0))
198  {
199  // Could also add silently
200  // dynRanks.push_back(0);
202  << "Rank 0 (master) should be in the IO ranks. Currently:" << nl
203  << " " << flatOutput(dynRanks) << nl
204  << exit(FatalError);
205  }
206 
207  // Never trust user input.
208  // Sort and eliminate any duplicates
209 
210  std::sort(dynRanks.begin(), dynRanks.end());
211 
212  if (dynRanks.front() < 0)
213  {
215  << "Cannot have negative ranks! Currently:" << nl
216  << " " << flatOutput(dynRanks) << nl
217  << exit(FatalError);
218  }
219 
220  labelList ranks;
221 
222  auto last = std::unique(dynRanks.begin(), dynRanks.end());
223 
224  if (last < dynRanks.end())
225  {
226  ranks = dynRanks.slice(0, (last - dynRanks.begin()));
227  }
228  else
229  {
230  ranks = dynRanks;
231  }
232 
233  return ranks;
234  }
235  else if (byHostName)
236  {
238  }
239 
240  return labelList();
241 }
242 
243 
244 bool Foam::fileOperation::isIOrank(const label proci) const
245 {
246  return
247  (
249  ? UPstream::master(comm_)
250  : ioRanks_.empty()
251  ? (proci == 0) // No io-ranks, assume single communicator
252  : ioRanks_.contains(proci) // Found proci in IO rank
253  );
254 }
255 
256 
258 {
259  // Collect the names of the IO masters
261  if (UPstream::master(comm_))
262  {
264  }
266 
267 
268  DynamicList<label> offsetMaster;
269 
270  // Calculate the offsets/counts
271 
273  {
274  label nHostRanks = 0;
275  forAll(hosts, ranki)
276  {
277  if (!hosts[ranki].empty())
278  {
279  ++nHostRanks;
280  }
281  }
282  offsetMaster.reserve(nHostRanks+1);
283 
284  forAll(hosts, ranki)
285  {
286  if (!hosts[ranki].empty())
287  {
288  offsetMaster.push_back(ranki);
289  }
290  }
291 
292  // End of range is nProcs
293  offsetMaster.push_back(hosts.size());
294  }
295 
296  if (offsetMaster.size() > 2)
297  {
298  DetailInfo
299  << "I/O on :" << nl << '(' << nl;
300  for (label group = 1; group < offsetMaster.size(); ++group)
301  {
302  const label beg = offsetMaster[group-1];
303  const label end = offsetMaster[group];
304 
305  DetailInfo
306  << " (" << hosts[beg].c_str() << ' '
307  << (end-beg) << ')' << nl;
308  }
309  DetailInfo
310  << ')' << nl;
311  }
312 }
313 
314 
315 // ************************************************************************* //
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
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:598
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:52
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:50
T & front()
Access first element of the list, position [0].
Definition: UListI.H:237
static bool & parRun() noexcept
Test if this a parallel run.
Definition: UPstream.H:1049
static int & msgType() noexcept
Message tag of standard messages.
Definition: UPstream.H:1229
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:1074
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:409
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:227
bool contains(const T &val) const
True if the value is contained in the list.
Definition: UListI.H:300
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 communicator ranks. Does nothing in non-paral...
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:421
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:1065
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:246
void sort(UList< T > &list)
Sort the list.
Definition: UList.C:296
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:391
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:201
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:1082
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:437
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:435
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
An input stream of tokens.
Definition: ITstream.H:52
Namespace for OpenFOAM.
FlatOutput::OutputAdaptor< Container, Delimiters > flatOutput(const Container &obj, Delimiters delim)
Global flatOutput() function with specified output delimiters.
Definition: FlatOutput.H:225