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-2023 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 "objectRegistry.H"
35 #include "IOdictionary.H"
36 #include "Pstream.H"
37 #include "PstreamReduceOps.H"
38 #include "OSspecific.H"
39 #include "Ostream.H"
40 #include "Time.H"
41 #include "regIOobject.H"
42 
43 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
44 
45 namespace Foam
46 {
47  defineTypeNameAndDebug(codedBase, 0);
48 }
49 
50 
51 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
52 
53 namespace Foam
54 {
55 
56 static inline void writeEntryIfPresent
57 (
58  Ostream& os,
59  const dictionary& dict,
60  const word& key
61 )
62 {
63  const entry* eptr = dict.findEntry(key, keyType::LITERAL);
64  if (!eptr)
65  {
66  // Nothing to do
67  }
68  else if (eptr->isDict())
69  {
70  eptr->dict().writeEntry(os);
71  }
72  else
73  {
74  const tokenList& toks = eptr->stream();
75 
76  if (!toks.empty()) // Could also check that it is a string-type
77  {
78  os.writeEntry(key, toks[0]);
79  }
80  }
81 }
82 
83 } // End namespace Foam
84 
85 
86 // * * * * * * * * * * * * * Static Member Functions * * * * * * * * * * * * //
87 
88 void Foam::codedBase::writeCodeDict(Ostream& os, const dictionary& dict)
89 {
90  writeEntryIfPresent(os, dict, "codeContext");
91  writeEntryIfPresent(os, dict, "codeInclude");
92  writeEntryIfPresent(os, dict, "localCode");
93  writeEntryIfPresent(os, dict, "code");
94  writeEntryIfPresent(os, dict, "codeOptions");
95  writeEntryIfPresent(os, dict, "codeLibs");
96 }
97 
98 
99 const Foam::dictionary&
101 (
102  const objectRegistry& obr,
103  const word& dictName
104 )
105 {
106  auto* dictptr = obr.getObjectPtr<IOdictionary>(dictName);
107 
108  if (!dictptr)
109  {
110  dictptr = new IOdictionary
111  (
112  IOobject
113  (
114  dictName,
115  obr.time().system(),
116  obr,
120  )
121  );
122 
123  obr.store(dictptr);
124  }
125 
126  return *dictptr;
127 }
128 
129 
130 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
131 
132 void* Foam::codedBase::loadLibrary
133 (
134  const fileName& libPath,
135  const std::string& funcName,
136  const dynamicCodeContext& context
137 ) const
138 {
139  // Avoid compilation by loading an existing library
140 
141  void* handle = libs().open(libPath, false);
142 
143  if (!handle)
144  {
145  return handle;
146  }
147 
148  // Verify the loaded version and unload if needed
149 
150  // Manual execution of code after loading.
151  // This is mandatory for codedBase.
152 
153  const bool ok = libs().loadHook(handle, funcName, false);
154 
155  if (!ok)
156  {
157  FatalIOErrorInFunction(context.dict())
158  << "Failed symbol lookup " << funcName.c_str() << nl
159  << "from " << libPath << nl
160  << exit(FatalIOError);
161 
162  handle = nullptr;
163  if (!libs().close(libPath, false))
164  {
165  FatalIOErrorInFunction(context.dict())
166  << "Failed unloading library " << libPath << nl
167  << exit(FatalIOError);
168  }
169  }
170 
171  return handle;
172 }
173 
174 
175 void Foam::codedBase::unloadLibrary
176 (
177  const fileName& libPath,
178  const std::string& funcName,
179  const dynamicCodeContext& context
180 ) const
181 {
182  void* handle = libs().open(libPath, false);
183 
184  if (!handle)
185  {
186  return;
187  }
188 
189  // Manual execution of code before unloading.
190  // This is mandatory for codedBase.
191 
192  const bool ok = libs().unloadHook(handle, funcName, false);
193 
194  if (!ok)
195  {
196  IOWarningInFunction(context.dict())
197  << "Failed looking up symbol " << funcName << nl
198  << "from " << libPath << nl;
199  }
200 
201  if (!libs().close(libPath, false))
202  {
203  FatalIOErrorInFunction(context.dict())
204  << "Failed unloading library " << libPath << nl
205  << exit(FatalIOError);
206  }
207 }
208 
209 
210 void Foam::codedBase::createLibrary
211 (
212  dynamicCode& dynCode,
213  const dynamicCodeContext& context
214 ) const
215 {
216  // No library?
217  // The overall master should compile it (so only it needs a compiler) and
218  // - see if it appears at the other processors
219  // - or copy it across if it does not
220 
221  // Indicates NFS filesystem
222  const bool isNFS = (IOobject::fileModificationSkew > 0);
223 
224  if
225  (
226  (UPstream::master() || !isNFS)
227  && !dynCode.upToDate(context)
228  )
229  {
230  // Filter with this context
231  dynCode.reset(context);
232 
233  this->prepare(dynCode, context);
234 
235  if (!dynCode.copyOrCreateFiles(true))
236  {
237  FatalIOErrorInFunction(context.dict())
238  << "Failed writing files for" << nl
239  << dynCode.libRelPath() << nl
240  << exit(FatalIOError);
241  }
242 
243  if (!dynCode.wmakeLibso())
244  {
245  FatalIOErrorInFunction(context.dict())
246  << "Failed wmake " << dynCode.libRelPath() << nl
247  << exit(FatalIOError);
248  }
249  }
250 
251  if (isNFS)
252  {
253  // Wait for compile to finish before attempting filesystem polling
255  }
256 
257  // Broadcast distributed...
259  dynamicCode::waitForFile(dynCode.libPath(), context.dict());
260 }
261 
262 
263 // * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
266 {
267  context_.setCodeContext(dict);
268 }
269 
270 
271 void Foam::codedBase::append(const std::string& str)
272 {
273  context_.append(str);
274 }
275 
276 
278 (
279  const word& name,
280  const dynamicCodeContext& context
281 ) const
282 {
284  (
285  "codedBase::updateLibrary()",
286  context.dict()
287  );
288 
289  // codeName: name + _<sha1>
290  // codeDir : name
291  dynamicCode dynCode
292  (
293  name + context.sha1().str(true),
294  name
295  );
296 
297  const fileName libPath = dynCode.libPath();
298 
299 
300  // The correct library was already loaded => we are done
301  if (libs().findLibrary(libPath))
302  {
303  return;
304  }
305 
306  DetailInfo
307  << "Using dynamicCode for " << this->description().c_str()
308  << " at line " << context.dict().startLineNumber()
309  << " in " << context.dict().name() << endl;
310 
311 
312  // Remove instantiation of fvPatchField provided by library
313  this->clearRedirect();
314 
315  // May need to unload old library
316  unloadLibrary(oldLibPath_, dlLibraryTable::basename(oldLibPath_), context);
317 
318  // Try loading an existing library (avoid compilation when possible)
319  void* lib = loadLibrary(libPath, dynCode.codeName(), context);
320 
321  if (returnReduceOr(lib == nullptr))
322  {
323  if (lib)
324  {
325  // Ensure consistency
326  unloadLibrary(libPath, dlLibraryTable::basename(libPath), context);
327  }
328 
329  createLibrary(dynCode, context);
330 
331  loadLibrary(libPath, dynCode.codeName(), context);
332  }
334  // Retain for future reference
335  oldLibPath_ = libPath;
336 }
337 
338 
340 (
341  const word& name,
343 ) const
344 {
345  updateLibrary(name, dynamicCodeContext(dict));
346 }
347 
348 
349 void Foam::codedBase::updateLibrary(const word& name) const
350 {
351  if (context_.valid())
352  {
353  updateLibrary(name, context_);
354  }
355  else
356  {
357  updateLibrary(name, dynamicCodeContext(this->codeDict()));
358  }
359 }
360 
361 
362 // ************************************************************************* //
void writeEntry(Ostream &os) const
Write sub-dictionary with its dictName as its header.
Definition: dictionaryIO.C:157
dictionary dict
A class for handling file names.
Definition: fileName.H:71
Inter-processor communication reduction functions.
std::string str(const bool prefixed=false) const
The digest (40-byte) text representation, optionally with &#39;_&#39; prefix.
Definition: SHA1I.H:114
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:125
static float fileModificationSkew
Time skew (seconds) for file modification checks.
Definition: IOobject.H:331
A list of keyword definitions, which are a keyword followed by a number of values (eg...
Definition: dictionary.H:120
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 void waitForFile(const fileName &file, const dictionary &contextDict)
Wait for libPath() file to appear on sub-ranks.
Definition: dynamicCode.C:532
constexpr char nl
The newline &#39;\n&#39; character (0x0a)
Definition: Ostream.H:49
bool empty() const noexcept
True if List is empty (ie, size() is zero)
Definition: UList.H:632
const word dictName("faMeshDefinition")
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:487
virtual const dictionary & dict() const =0
Return dictionary, if entry is a dictionary.
bool store()
Register object with its registry and transfer ownership to the registry.
Definition: regIOobjectI.H:36
Ostream & writeEntry(const keyType &key, const T &value)
Write a keyword/value entry.
Definition: Ostream.H:312
Ignore writing from objectRegistry::writeObject()
static label worldComm
Communicator for all ranks. May differ from commGlobal() if local worlds are in use.
Definition: UPstream.H:411
void append(const std::string &str)
Add content to SHA1 hashing.
Definition: codedBase.C:264
const fileName & name() const noexcept
The dictionary name.
Definition: dictionaryI.H:41
IOdictionary is derived from dictionary and IOobject to give the dictionary automatic IO functionalit...
Definition: IOdictionary.H:50
Functions used by OpenFOAM that are specific to POSIX compliant operating systems and need to be repl...
const dictionary & dict() const noexcept
Return the parent dictionary context.
word name(const expressions::valueTypeCode typeCode)
A word representation of a valueTypeCode. Empty for INVALID.
Definition: exprTraits.C:52
static word basename(const fileName &libPath)
Library basename without leading &#39;lib&#39; or trailing &#39;.so&#39;.
A class for handling words, derived from Foam::string.
Definition: word.H:63
Type * getObjectPtr(const word &name, const bool recursive=false) const
Return non-const pointer to the object of the given Type, using a const-cast to have it behave like a...
static void * loadLibrary(const Foam::fileName &libName)
Definition: POSIX.C:111
const Time & time() const noexcept
Return time registry.
const word & system() const noexcept
Return system name.
Definition: TimePathsI.H:95
String literal.
Definition: keyType.H:82
#define DetailInfo
Definition: evalEntry.C:30
void setCodeContext(const dictionary &dict)
Set code context from a dictionary.
Definition: codedBase.C:258
An Ostream is an abstract base class for all output systems (streams, files, token lists...
Definition: Ostream.H:55
OBJstream os(runTime.globalPath()/outputName)
defineTypeNameAndDebug(combustionModel, 0)
static void writeEntryIfPresent(Ostream &os, const dictionary &dict, const word &key)
Definition: codedBase.C:50
Tools for handling dynamic code compilation.
Definition: dynamicCode.H:56
Encapsulation of dynamic code dictionaries.
void updateLibrary(const word &name, const dynamicCodeContext &context) const
Update library as required, using the given context.
Definition: codedBase.C:271
#define FatalIOErrorInFunction(ios)
Report an error message using Foam::FatalIOError.
Definition: error.H:607
auto key(const Type &t) -> typename std::enable_if< std::is_enum< Type >::value, typename std::underlying_type< Type >::type >::type
Definition: foamGltfBase.H:103
static bool master(const label communicator=worldComm)
True if process corresponds to the master rank in the communicator.
Definition: UPstream.H:1037
const entry * findEntry(const word &keyword, enum keyType::option matchOpt=keyType::REGEX) const
Find an entry (const access) with the given keyword.
Definition: dictionaryI.H:80
virtual bool isDict() const noexcept
Return true if this entry is a dictionary.
Definition: entry.H:287
#define IOWarningInFunction(ios)
Report an IO warning using Foam::Warning.
Registry of regIOobjects.
virtual ITstream & stream() const =0
Return token stream, if entry is a primitive entry.
bool returnReduceOr(const bool value, const label comm=UPstream::worldComm)
Perform logical (or) MPI Allreduce on a copy. Uses UPstream::reduceOr.
static void checkSecurity(const char *title, const dictionary &)
Check security for creating dynamic code.
Definition: dynamicCode.C:59
Defines the attributes of an object for which implicit objectRegistry management is supported...
Definition: IOobject.H:171
Request registration (bool: true)
static void writeCodeDict(Ostream &os, const dictionary &dict)
Write code-dictionary contents.
Definition: codedBase.C:81
label startLineNumber() const
Return line number of first token in dictionary.
Definition: dictionary.C:198
virtual const dictionary & codeDict() const =0
Namespace for OpenFOAM.
A keyword and a list of tokens is an &#39;entry&#39;.
Definition: entry.H:63
static void barrier(const label communicator, UPstream::Request *req=nullptr)
Impose a synchronisation barrier (optionally non-blocking)
Definition: UPstream.C:83
const SHA1 & sha1() const noexcept
The SHA1 calculated from options, libs, include, code, etc.
IOerror FatalIOError
Error stream (stdout output on all processes), with additional &#39;FOAM FATAL IO ERROR&#39; header text and ...