codedBase.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) 2016-2020 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
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 "codedBase.H"
30 #include "SHA1Digest.H"
31 #include "dynamicCode.H"
32 #include "dynamicCodeContext.H"
33 #include "dlLibraryTable.H"
34 #include "Pstream.H"
35 #include "PstreamReduceOps.H"
36 #include "OSspecific.H"
37 #include "Ostream.H"
38 #include "regIOobject.H"
39 
40 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
41 
42 namespace Foam
43 {
44  defineTypeNameAndDebug(codedBase, 0);
45 }
46 
47 
48 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
49 
50 namespace Foam
51 {
52 
54 static inline void writeEntryIfPresent
55 (
56  Ostream& os,
57  const dictionary& dict,
58  const word& key
59 )
60 {
61  const entry* eptr = dict.findEntry(key, keyType::LITERAL);
62 
63  if (eptr)
64  {
65  const tokenList& toks = eptr->stream();
66 
67  if (!toks.empty())
68  {
69  os.writeEntry(key, toks[0]);
70  }
71  }
72 }
74 
75 } // End namespace Foam
76 
77 
78 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
79 
81 {
82  writeEntryIfPresent(os, dict, "codeInclude");
83  writeEntryIfPresent(os, dict, "localCode");
84  writeEntryIfPresent(os, dict, "code");
85  writeEntryIfPresent(os, dict, "codeOptions");
86  writeEntryIfPresent(os, dict, "codeLibs");
87 }
88 
89 
90 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
91 
92 void* Foam::codedBase::loadLibrary
93 (
94  const fileName& libPath,
95  const std::string& funcName,
96  const dynamicCodeContext& context
97 ) const
98 {
99  // Avoid compilation by loading an existing library
100 
101  void* handle = libs().open(libPath, false);
102 
103  if (!handle)
104  {
105  return handle;
106  }
107 
108  // Verify the loaded version and unload if needed
109 
110  // Manual execution of code after loading.
111  // This is mandatory for codedBase.
112 
113  const bool ok = libs().loadHook(handle, funcName, false);
114 
115  if (!ok)
116  {
117  FatalIOErrorInFunction(context.dict())
118  << "Failed symbol lookup " << funcName.c_str() << nl
119  << "from " << libPath << nl
120  << exit(FatalIOError);
121 
122  handle = nullptr;
123  if (!libs().close(libPath, false))
124  {
125  FatalIOErrorInFunction(context.dict())
126  << "Failed unloading library " << libPath << nl
127  << exit(FatalIOError);
128  }
129  }
130 
131  return handle;
132 }
133 
134 
135 void Foam::codedBase::unloadLibrary
136 (
137  const fileName& libPath,
138  const std::string& funcName,
139  const dynamicCodeContext& context
140 ) const
141 {
142  void* handle = libs().open(libPath, false);
143 
144  if (!handle)
145  {
146  return;
147  }
148 
149  // Manual execution of code before unloading.
150  // This is mandatory for codedBase.
151 
152  const bool ok = libs().unloadHook(handle, funcName, false);
153 
154  if (!ok)
155  {
156  IOWarningInFunction(context.dict())
157  << "Failed looking up symbol " << funcName << nl
158  << "from " << libPath << nl;
159  }
160 
161  if (!libs().close(libPath, false))
162  {
163  FatalIOErrorInFunction(context.dict())
164  << "Failed unloading library " << libPath << nl
165  << exit(FatalIOError);
166  }
167 }
168 
169 
170 void Foam::codedBase::createLibrary
171 (
172  dynamicCode& dynCode,
173  const dynamicCodeContext& context
174 ) const
175 {
176  bool create =
178  || (regIOobject::fileModificationSkew <= 0); // not NFS
179 
180  if (create)
181  {
182  // Write files for new library
183  if (!dynCode.upToDate(context))
184  {
185  // filter with this context
186  dynCode.reset(context);
187 
188  this->prepare(dynCode, context);
189 
190  if (!dynCode.copyOrCreateFiles(true))
191  {
192  FatalIOErrorInFunction(context.dict())
193  << "Failed writing files for" << nl
194  << dynCode.libRelPath() << nl
195  << exit(FatalIOError);
196  }
197  }
198 
199  if (!dynCode.wmakeLibso())
200  {
201  FatalIOErrorInFunction(context.dict())
202  << "Failed wmake " << dynCode.libRelPath() << nl
203  << exit(FatalIOError);
204  }
205  }
206 
207 
208  // all processes must wait for compile to finish
210  {
211  //- Since the library has only been compiled on the master the
212  // other nodes need to pick this library up through NFS
213  // We do this by just polling a few times using the
214  // fileModificationSkew.
215 
216  const fileName libPath = dynCode.libPath();
217 
218  off_t mySize = Foam::fileSize(libPath);
219  off_t masterSize = mySize;
220  Pstream::scatter(masterSize);
221 
222  for
223  (
224  label iter = 0;
226  iter++
227  )
228  {
229  DebugPout
230  << "on processor " << Pstream::myProcNo()
231  << " have masterSize:" << masterSize
232  << " and localSize:" << mySize
233  << endl;
234 
235  if (mySize == masterSize)
236  {
237  break;
238  }
239  else if (mySize > masterSize)
240  {
241  FatalIOErrorInFunction(context.dict())
242  << "Excessive size when reading (NFS mounted) library "
243  << nl << libPath << nl
244  << "on processor " << Pstream::myProcNo()
245  << " detected size " << mySize
246  << " whereas master size is " << masterSize
247  << " bytes." << nl
248  << "If your case is NFS mounted increase"
249  << " fileModificationSkew or maxFileModificationPolls;"
250  << nl << "If your case is not NFS mounted"
251  << " (so distributed) set fileModificationSkew"
252  << " to 0"
253  << exit(FatalIOError);
254  }
255  else
256  {
257  DebugPout
258  << "Local file " << libPath
259  << " not of same size (" << mySize
260  << ") as master ("
261  << masterSize << "). Waiting for "
263  << " seconds." << endl;
264 
266 
267  // Recheck local size
268  mySize = Foam::fileSize(libPath);
269  }
270  }
271 
272 
273  // Finished doing iterations. Do final check
274  if (mySize != masterSize)
275  {
276  FatalIOErrorInFunction(context.dict())
277  << "Cannot read (NFS mounted) library " << nl
278  << libPath << nl
279  << "on processor " << Pstream::myProcNo()
280  << " detected size " << mySize
281  << " whereas master size is " << masterSize
282  << " bytes." << nl
283  << "If your case is NFS mounted increase"
284  << " fileModificationSkew or maxFileModificationPolls;"
285  << nl << "If your case is not NFS mounted"
286  << " (so distributed) set fileModificationSkew"
287  << " to 0"
288  << exit(FatalIOError);
289  }
290 
291  DebugPout
292  << "on processor " << Pstream::myProcNo()
293  << " after waiting: have masterSize:" << masterSize
294  << " and localSize:" << mySize << endl;
295  }
296  reduce(create, orOp<bool>());
297 }
298 
299 
300 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
301 
303 {
304  context_.setCodeContext(dict);
305 }
306 
307 
308 void Foam::codedBase::append(const std::string& str)
309 {
310  context_.append(str);
311 }
312 
313 
315 (
316  const word& name,
317  const dynamicCodeContext& context
318 ) const
319 {
321  (
322  "codedBase::updateLibrary()",
323  context.dict()
324  );
325 
326  // codeName: name + _<sha1>
327  // codeDir : name
328  dynamicCode dynCode
329  (
330  name + context.sha1().str(true),
331  name
332  );
333 
334  const fileName libPath = dynCode.libPath();
335 
336 
337  // The correct library was already loaded => we are done
338  if (libs().findLibrary(libPath))
339  {
340  return;
341  }
342 
343  DetailInfo
344  << "Using dynamicCode for " << this->description().c_str()
345  << " at line " << context.dict().startLineNumber()
346  << " in " << context.dict().name() << endl;
347 
348 
349  // Remove instantiation of fvPatchField provided by library
350  this->clearRedirect();
351 
352  // May need to unload old library
353  unloadLibrary
354  (
355  oldLibPath_,
356  dlLibraryTable::basename(oldLibPath_),
357  context
358  );
359 
360  // Try loading an existing library (avoid compilation when possible)
361  if (!loadLibrary(libPath, dynCode.codeName(), context))
362  {
363  createLibrary(dynCode, context);
364 
365  loadLibrary(libPath, dynCode.codeName(), context);
366  }
367 
368  // Retain for future reference
369  oldLibPath_ = libPath;
370 }
371 
372 
374 (
375  const word& name,
376  const dictionary& dict
377 ) const
378 {
379  updateLibrary(name, dynamicCodeContext(dict));
380 }
381 
382 
384 {
385  if (context_.valid())
386  {
387  updateLibrary(name, context_);
388  }
389  else
390  {
391  updateLibrary(name, dynamicCodeContext(this->codeDict()));
392  }
393 }
394 
395 
396 // ************************************************************************* //
regIOobject.H
Foam::codedBase::append
void append(const std::string &str)
Add content to SHA1 hashing.
Definition: codedBase.C:308
Foam::BitSetOps::create
bitSet create(const label n, const labelHashSet &locations, const bool on=true)
Create a bitSet with length n with the specified on locations.
Definition: BitOps.C:123
OSspecific.H
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
Foam::word
A class for handling words, derived from Foam::string.
Definition: word.H:62
Foam::fileName
A class for handling file names.
Definition: fileName.H:69
Foam::codedBase::writeCodeDict
static void writeCodeDict(Ostream &os, const dictionary &dict)
Write code-dictionary contents.
Definition: codedBase.C:80
Foam::SHA1::str
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with '_' prefix.
Definition: SHA1I.H:123
Foam::dynamicCode
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:59
Foam::dlLibraryTable::basename
static word basename(const fileName &libPath)
Library basename without leading 'lib' or trailing '.so'.
Definition: dlLibraryTable.C:60
Foam::dynamicCodeContext::dict
const dictionary & dict() const
Return the parent dictionary context.
Definition: dynamicCodeContext.H:128
Foam::regIOobject::fileModificationSkew
static float fileModificationSkew
Definition: regIOobject.H:133
Foam::dynamicCodeContext
Encapsulation of dynamic code dictionaries.
Definition: dynamicCodeContext.H:53
Foam::regIOobject::maxFileModificationPolls
static int maxFileModificationPolls
Definition: regIOobject.H:135
Foam::UPstream::master
static bool master(const label communicator=worldComm)
Am I the master process.
Definition: UPstream.H:458
Foam::Pstream::scatter
static void scatter(const List< commsStruct > &comms, T &Value, const int tag, const label comm)
Scatter data. Distribute without modification. Reverse of gather.
Definition: gatherScatter.C:150
Foam::FatalIOError
IOerror FatalIOError
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:350
dynamicCodeContext.H
Foam::codedBase::setCodeContext
void setCodeContext(const dictionary &dict)
Set code context from a dictionary.
Definition: codedBase.C:302
SHA1Digest.H
Foam::reduce
void reduce(const List< UPstream::commsStruct > &comms, T &Value, const BinaryOp &bop, const int tag, const label comm)
Definition: PstreamReduceOps.H:51
Foam::dictionary::name
const fileName & name() const
The dictionary name.
Definition: dictionary.H:446
Foam::fileSize
off_t fileSize(const fileName &name, const bool followLink=true)
Return size of file or -1 on failure (normally follows symbolic links).
Definition: MSwindows.C:676
Foam::name
word name(const complex &c)
Return string representation of complex.
Definition: complex.C:76
Foam::dynamicCode::checkSecurity
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:64
Foam::dictionary::startLineNumber
label startLineNumber() const
Return line number of first token in dictionary.
Definition: dictionary.C:205
dynamicCode.H
DetailInfo
#define DetailInfo
Definition: evalEntry.C:36
dict
dictionary dict
Definition: searchingEngine.H:14
Foam::dictionary
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:121
Pstream.H
Foam
Namespace for OpenFOAM.
Definition: atmBoundaryLayer.C:33
PstreamReduceOps.H
Inter-processor communication reduction functions.
DebugPout
#define DebugPout
Report an information message using Foam::Pout.
Definition: messageStream.H:370
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::tokenList
List< token > tokenList
List of tokens, used for a IOdictionary entry.
Definition: tokenList.H:44
Ostream.H
Foam::UPstream::myProcNo
static int myProcNo(const label communicator=worldComm)
Number of this process (starting from masterNo() = 0)
Definition: UPstream.H:464
Foam::nl
constexpr char nl
Definition: Ostream.H:385
dlLibraryTable.H
Foam::dictionary::findEntry
entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX)
Find for an entry (non-const access) with the given keyword.
Definition: dictionary.C:374
codedBase.H
FatalIOErrorInFunction
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:401
Foam::keyType::LITERAL
String literal.
Definition: keyType.H:73
Foam::Ostream
An Ostream is an abstract base class for all output systems (streams, files, token lists,...
Definition: Ostream.H:56
IOWarningInFunction
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Definition: messageStream.H:315
Foam::dynamicCodeContext::sha1
const SHA1 & sha1() const
Return SHA1 calculated from options, libs, include, code.
Definition: dynamicCodeContext.H:164
Foam::codedBase::updateLibrary
void updateLibrary(const word &name, const dynamicCodeContext &context) const
Update library as required, using the given context.
Definition: codedBase.C:315
Foam::defineTypeNameAndDebug
defineTypeNameAndDebug(combustionModel, 0)
Foam::sleep
unsigned int sleep(const unsigned int sec)
Sleep for the specified number of seconds.
Definition: MSwindows.C:1096