ENH: parallel runTimeModifiable - master only

This commit is contained in:
mattijs
2010-11-16 12:41:44 +00:00
parent 57a443a183
commit b5dddd8980
13 changed files with 700 additions and 275 deletions

View File

@ -24,21 +24,63 @@ be quite a gain on large numbers of processors.
- all file monitoring is done by an instance of 'fileMonitor' in the Time - all file monitoring is done by an instance of 'fileMonitor' in the Time
class. The fileMonitor class can be found in OSspecific. Default is class. The fileMonitor class can be found in OSspecific. It uses either
to use the (linux-specific) 'inotify' system calls. timestamps as before or the (linux-specific) 'inotify' system framework
If compiled with -DFOAM_USE_STAT it will revert to the current 'stat' system (available only if compiled with -DFOAM_USE_INOTIFY).
calls.
- inotify does not need timestamps. There is no need for fileModificationSkew - the monitoring can be done in one of four modes as set by
OptimisationSwitches::fileModificationChecking
- timeStamp : old behaviour : all nodes check the timestamp
- inotify : using inotify instead of timestamps
- timeStampMaster,inotifyMaster : only the master node checks the file
and only the master node reads it and distribute it to the
slaves. This makes runTimeModifiable possible on distributed
running (see below).
- distributed running:
- set fileModificationChecking to e.g. timeStampMaster
- decompose a case, e.g. cavity
- copy system and constant to processor0/
- put the all the processor* directories on the wanted nodes inside
the case directory. E.g.
- on master have /tmp/cavity/processor0
- on slaveN have /tmp/cavity/processorN
- so to reiterate:
- there is no need for cavity/constant or cavity/system, all the
dictionaries are only in processor0/constant or processor0/system
- the slave processor directories have no system directory and the
constant directory only contains the mesh.
- start the job in distributed mode by specifying the slave roots
(so one less than the number of processors) with
the -roots command line option:
mpirun -np 2 icoFoam -roots '("/tmp")' -parallel
- the alternative to the -roots option is to have a
cavity/system/decomposeParDict on the master with
distributed yes;
roots ("/tmp");
Details:
- timeStampMaster, inotifyMaster : this works only for IOdictionaries that
are READ_IF_MODIFIED. It means that slaves read exactly the same dictionary
as the master so cannot be used for dictionaries that contain e.g. mesh
specific information.
- inotify is a monitoring framework used to monitor changes in
lots of files (e.g. used in desktop searched like beagle). You specify
files to monitor and then get warned for any changes to these files.
It does not need timestamps. There is no need for fileModificationSkew
to allow for time differences. (there can still temporarily be a difference to allow for time differences. (there can still temporarily be a difference
in modified status between different processors due to nfs lagging) in modified status between different processors due to nfs lagging). The big
problem is that it does not work over nfs3 (not sure about nfs4).
- fileMonitor stores two hashtables per file so there is a small overhead - fileMonitor stores two hashtables per file so there is a small overhead
adding and removing files from monitoring. adding and removing files from monitoring.
- if runTimeModifiable is false at start of run no files will get monitored, - if runTimeModifiable is false at start of run no files will get monitored,
however if runTimeModified gets set to false during the run the files however if runTimeModified gets set to false during the run the files
will still get monitored (though never reloaded). This is only a hypothetical will still get monitored (though never reloaded). This is only a hypothetical
@ -46,7 +88,6 @@ problem in that the kernel still stores events for the monitored files. However
inotify is very efficient - e.g. it gets used to track changes on file systems inotify is very efficient - e.g. it gets used to track changes on file systems
for desktop search engines. for desktop search engines.
- in the old system one could call modified() on any object and get - in the old system one could call modified() on any object and get
and uptodate state. In the new system it will return the state from and uptodate state. In the new system it will return the state from
the last runTime++ (which if it triggered any re-reads will have reset the the last runTime++ (which if it triggered any re-reads will have reset the

View File

@ -872,6 +872,14 @@ InfoSwitches
OptimisationSwitches OptimisationSwitches
{ {
fileModificationSkew 10; fileModificationSkew 10;
//- Modification checking:
// - timeStamp : use modification time on file
// - inotify : use inotify framework
// - timeStampMaster : do time stamp (and file reading) only on master.
// - inotifyMaster : do inotify (and file reading) only on master.
fileModificationChecking timeStampMaster;//inotify;timeStamp;inotifyMaster;
commsType nonBlocking; //scheduled; //blocking; commsType nonBlocking; //scheduled; //blocking;
floatTransfer 0; floatTransfer 0;
nProcsSimpleSum 0; nProcsSimpleSum 0;

View File

@ -12,9 +12,9 @@ unset COMP_FLAGS LINK_FLAGS
if [ -f /usr/include/sys/inotify.h -a "${1%USE_STAT}" = "$1" ] if [ -f /usr/include/sys/inotify.h -a "${1%USE_STAT}" = "$1" ]
then then
echo "Found <sys/inotify.h> -- using inotify for file monitoring." echo "Found <sys/inotify.h> -- using inotify for file monitoring."
unset COMP_FLAGS export COMP_FLAGS="-DFOAM_USE_INOTIFY"
else else
export COMP_FLAGS="-DFOAM_USE_STAT" unset COMP_FLAGS
fi fi

View File

@ -32,17 +32,17 @@ Class
#include "PackedList.H" #include "PackedList.H"
#include "PstreamReduceOps.H" #include "PstreamReduceOps.H"
#include "OSspecific.H" #include "OSspecific.H"
#ifdef FOAM_USE_STAT
# include "OSspecific.H"
#include "regIOobject.H" // for fileModificationSkew symbol #include "regIOobject.H" // for fileModificationSkew symbol
#else
#ifdef FOAM_USE_INOTIFY
# include <sys/inotify.h> # include <sys/inotify.h>
# include <sys/ioctl.h> # include <sys/ioctl.h>
# include <errno.h> # include <errno.h>
# define EVENT_SIZE ( sizeof (struct inotify_event) ) # define EVENT_SIZE ( sizeof (struct inotify_event) )
# define EVENT_LEN (EVENT_SIZE + 16) # define EVENT_LEN (EVENT_SIZE + 16)
# define EVENT_BUF_LEN ( 1024 * EVENT_LEN ) # define EVENT_BUF_LEN ( 1024 * EVENT_LEN )
#else
# include "OSspecific.H"
#endif #endif
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -111,38 +111,10 @@ namespace Foam
{ {
public: public:
#ifdef FOAM_USE_STAT const bool useInotify_;
//- From watch descriptor to modified time
DynamicList<time_t> lastMod_;
//- initialize HashTable size // For inotify
inline fileMonitorWatcher(const label sz = 20)
:
lastMod_(sz)
{}
inline bool addWatch(const label watchFd, const fileName& fName)
{
if (watchFd < lastMod_.size() && lastMod_[watchFd] != 0)
{
// Reuse of watchFd : should have lastMod set to 0.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
lastMod_(watchFd) = lastModified(fName);
return true;
}
inline bool removeWatch(const label watchFd)
{
lastMod_[watchFd] = 0;
return true;
}
#else
//- File descriptor for the inotify instance //- File descriptor for the inotify instance
int inotifyFd_; int inotifyFd_;
@ -150,20 +122,32 @@ namespace Foam
DynamicList<label> dirWatches_; DynamicList<label> dirWatches_;
DynamicList<fileName> dirFiles_; DynamicList<fileName> dirFiles_;
// For stat
//- From watch descriptor to modified time
DynamicList<time_t> lastMod_;
//- initialise inotify //- initialise inotify
inline fileMonitorWatcher(const label sz = 20) inline fileMonitorWatcher(const bool useInotify, const label sz = 20)
: :
inotifyFd_(inotify_init()), useInotify_(useInotify)
dirWatches_(sz),
dirFiles_(sz)
{ {
if (useInotify_)
{
#ifdef FOAM_USE_INOTIFY
inotifyFd_ = inotify_init();
dirWatches_.setCapacity(sz);
dirFiles_.setCapacity(sz);
if (inotifyFd_ < 0) if (inotifyFd_ < 0)
{ {
static bool hasWarned = false; static bool hasWarned = false;
if (!hasWarned) if (!hasWarned)
{ {
hasWarned = true; hasWarned = true;
WarningIn("fileMonitorWatcher(const label)") WarningIn("fileMonitorWatcher(const bool, const label)")
<< "Failed allocating an inotify descriptor : " << "Failed allocating an inotify descriptor : "
<< string(strerror(errno)) << endl << string(strerror(errno)) << endl
<< " Please increase the number of allowable " << " Please increase the number of allowable "
@ -171,18 +155,33 @@ namespace Foam
<< " (/proc/sys/fs/inotify/max_user_instances" << " (/proc/sys/fs/inotify/max_user_instances"
<< " on Linux)" << endl << " on Linux)" << endl
<< " , switch off runTimeModifiable." << endl << " , switch off runTimeModifiable." << endl
<< " or compile this file with FOAM_USE_STAT to use" << " or compile this file without "
<< " time stamps instead of inotify." << endl << "FOAM_USE_INOTIFY"
<< " Continuing without additional file monitoring." << " to use time stamps instead of inotify." << endl
<< " Continuing without additional file"
<< " monitoring."
<< endl; << endl;
} }
} }
#else
FatalErrorIn("fileMonitorWatcher(const bool, const label)")
<< "You selected inotify but this file was compiled"
<< " without FOAM_USE_INOTIFY"
<< "Please select another fileModification test method"
<< exit(FatalError);
#endif
}
else
{
lastMod_.setCapacity(sz);
}
} }
//- remove all watches //- remove all watches
inline ~fileMonitorWatcher() inline ~fileMonitorWatcher()
{ {
if (inotifyFd_ >= 0) #ifdef FOAM_USE_INOTIFY
if (useInotify_ && inotifyFd_ >= 0)
{ {
forAll(dirWatches_, i) forAll(dirWatches_, i)
{ {
@ -197,20 +196,32 @@ namespace Foam
} }
} }
} }
#endif
} }
inline bool addWatch(const label watchFd, const fileName& fName) inline bool addWatch(const label watchFd, const fileName& fName)
{
if (useInotify_)
{ {
if (inotifyFd_ < 0) if (inotifyFd_ < 0)
{ {
return false; return false;
} }
// Add/retrieve watch on directory containing file #ifdef FOAM_USE_INOTIFY
label dirWatchID = inotify_add_watch // Add/retrieve watch on directory containing file.
// Note that fName might be non-existing in special situations
// (master-only reading for IODictionaries)
const fileName dir = fName.path();
label dirWatchID = -1;
if (isDir(dir))
{
dirWatchID = inotify_add_watch
( (
inotifyFd_, inotifyFd_,
fName.path().c_str(), dir.c_str(),
IN_CLOSE_WRITE IN_CLOSE_WRITE
); );
@ -222,6 +233,7 @@ namespace Foam
<< string(strerror(errno)) << string(strerror(errno))
<< exit(FatalError); << exit(FatalError);
} }
}
if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1) if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
{ {
@ -234,10 +246,28 @@ namespace Foam
dirWatches_(watchFd) = dirWatchID; dirWatches_(watchFd) = dirWatchID;
dirFiles_(watchFd) = fName.name(); dirFiles_(watchFd) = fName.name();
#endif
}
else
{
if (watchFd < lastMod_.size() && lastMod_[watchFd] != 0)
{
// Reuse of watchFd : should have lastMod set to 0.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
lastMod_(watchFd) = lastModified(fName);
}
return true; return true;
} }
inline bool removeWatch(const label watchFd) inline bool removeWatch(const label watchFd)
{
if (useInotify_)
{ {
if (inotifyFd_ < 0) if (inotifyFd_ < 0)
{ {
@ -245,9 +275,13 @@ namespace Foam
} }
dirWatches_[watchFd] = -1; dirWatches_[watchFd] = -1;
}
else
{
lastMod_[watchFd] = 0;
}
return true; return true;
} }
#endif
}; };
//! @endcond //! @endcond
@ -258,35 +292,9 @@ namespace Foam
void Foam::fileMonitor::checkFiles() const void Foam::fileMonitor::checkFiles() const
{ {
#ifdef FOAM_USE_STAT if (useInotify_)
forAll(watcher_->lastMod_, watchFd)
{ {
time_t oldTime = watcher_->lastMod_[watchFd]; #ifdef FOAM_USE_INOTIFY
if (oldTime != 0)
{
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
if (newTime == 0)
{
state_[watchFd] = DELETED;
}
else
{
if (newTime > (oldTime + regIOobject::fileModificationSkew))
{
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
}
}
}
#else
// Large buffer for lots of events // Large buffer for lots of events
char buffer[EVENT_BUF_LEN]; char buffer[EVENT_BUF_LEN];
@ -318,7 +326,12 @@ void Foam::fileMonitor::checkFiles() const
else if (FD_ISSET(watcher_->inotifyFd_, &fdSet)) else if (FD_ISSET(watcher_->inotifyFd_, &fdSet))
{ {
// Read events // Read events
ssize_t nBytes = read(watcher_->inotifyFd_, buffer, EVENT_BUF_LEN); ssize_t nBytes = read
(
watcher_->inotifyFd_,
buffer,
EVENT_BUF_LEN
);
if (nBytes < 0) if (nBytes < 0)
{ {
@ -344,7 +357,11 @@ void Foam::fileMonitor::checkFiles() const
//Pout<< "file:" << fileName(inotifyEvent->name) << endl; //Pout<< "file:" << fileName(inotifyEvent->name) << endl;
//Pout<< "len:" << inotifyEvent->len << endl; //Pout<< "len:" << inotifyEvent->len << endl;
if ((inotifyEvent->mask & IN_CLOSE_WRITE) && inotifyEvent->len) if
(
(inotifyEvent->mask & IN_CLOSE_WRITE)
&& inotifyEvent->len
)
{ {
// Search for file // Search for file
forAll(watcher_->dirWatches_, i) forAll(watcher_->dirWatches_, i)
@ -373,16 +390,48 @@ void Foam::fileMonitor::checkFiles() const
} }
#endif #endif
} }
else
{
forAll(watcher_->lastMod_, watchFd)
{
time_t oldTime = watcher_->lastMod_[watchFd];
if (oldTime != 0)
{
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
if (newTime == 0)
{
state_[watchFd] = DELETED;
}
else
{
if (newTime > (oldTime + regIOobject::fileModificationSkew))
{
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
}
}
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileMonitor::fileMonitor() Foam::fileMonitor::fileMonitor(const bool useInotify)
: :
useInotify_(useInotify),
state_(20), state_(20),
watchFile_(20), watchFile_(20),
freeWatchFds_(2), freeWatchFds_(2),
watcher_(new fileMonitorWatcher(20)) watcher_(new fileMonitorWatcher(useInotify_, 20))
{} {}
@ -394,6 +443,8 @@ Foam::fileMonitor::~fileMonitor()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// Note: fName might not exist (on slaves if in master-only mode for
// regIOobject)
Foam::label Foam::fileMonitor::addWatch(const fileName& fName) Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
{ {
label watchFd; label watchFd;
@ -458,20 +509,54 @@ const
} }
void Foam::fileMonitor::updateStates(const bool syncPar) const void Foam::fileMonitor::updateStates
(
const bool masterOnly,
const bool syncPar
) const
{
if (Pstream::master() || !masterOnly)
{ {
checkFiles(); checkFiles();
}
if (syncPar) if (syncPar)
{ {
PackedList<2> stats(state_.size()); // Pack current state (might be on master only)
PackedList<2> stats(state_.size(), MODIFIED);
if (Pstream::master() || !masterOnly)
{
forAll(state_, watchFd) forAll(state_, watchFd)
{ {
stats[watchFd] = static_cast<unsigned int>(state_[watchFd]); stats[watchFd] = static_cast<unsigned int>(state_[watchFd]);
} }
// Save local state for warning message below }
PackedList<2> thisProcStats(stats);
// Save local state for warning message below
PackedList<2> thisProcStats;
if (!masterOnly)
{
thisProcStats = stats;
}
// Scatter or reduce to synchronise state
if (masterOnly)
{
// Scatter
if (stats.storage().size() == 1)
{
Pstream::scatter(stats.storage()[0]);
}
else
{
Pstream::listCombineScatter(stats.storage());
}
}
else
{
// Reduce
if (stats.storage().size() == 1) if (stats.storage().size() == 1)
{ {
// Optimisation valid for most cases. // Optimisation valid for most cases.
@ -485,9 +570,21 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
combineReduceFileStates() combineReduceFileStates()
); );
} }
}
// Update local state
forAll(state_, watchFd) forAll(state_, watchFd)
{ {
if (masterOnly)
{
// No need to check for inconsistent state. Just assign.
unsigned int stat = stats[watchFd];
state_[watchFd] = fileState(stat);
}
else
{
// Check for inconsistent state before assigning.
if (thisProcStats[watchFd] != UNMODIFIED) if (thisProcStats[watchFd] != UNMODIFIED)
{ {
if (stats[watchFd] == UNMODIFIED) if (stats[watchFd] == UNMODIFIED)
@ -507,14 +604,17 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
} }
} }
} }
}
void Foam::fileMonitor::setUnmodified(const label watchFd) void Foam::fileMonitor::setUnmodified(const label watchFd)
{ {
#ifdef FOAM_USE_STAT
watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
#endif
state_[watchFd] = UNMODIFIED; state_[watchFd] = UNMODIFIED;
if (!useInotify_)
{
watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
}
} }

View File

@ -28,10 +28,11 @@ Description
Checking for changes to files. Checking for changes to files.
Note Note
The default is to use inotify (Linux specific, since 2.6.13) The default is to use stat to get the timestamp.
Compiling with FOAM_USE_STAT (or if /usr/include/sys/inotify.h Compile with FOAM_USE_INOTIFY to use the inotify
does not exist) uses the stat function call. (Linux specific, since 2.6.13) framework. The problem is that inotify does
not work on nfs3 mounted directories!!
SourceFiles SourceFiles
fileMonitor.C fileMonitor.C
@ -78,6 +79,9 @@ public:
private: private:
// Private data // Private data
//- Whether to use inotify (requires -DFOAM_USE_INOTIFY, see above)
const bool useInotify_;
//- State for all watchFds //- State for all watchFds
mutable DynamicList<fileState> state_; mutable DynamicList<fileState> state_;
@ -111,7 +115,7 @@ public:
// Constructors // Constructors
//- Construct null //- Construct null
fileMonitor(); fileMonitor(const bool useInotify);
//- Destructor //- Destructor
@ -133,7 +137,11 @@ public:
fileState getState(const label watchFd) const; fileState getState(const label watchFd) const;
//- Check state of all files. Updates state_. //- Check state of all files. Updates state_.
void updateStates(const bool syncPar) const; void updateStates
(
const bool masterOnly,
const bool syncPar
) const;
//- Reset state (e.g. after having read it) using handle //- Reset state (e.g. after having read it) using handle
void setUnmodified(const label watchFd); void setUnmodified(const label watchFd);

View File

@ -31,12 +31,61 @@ Description
#include "IOdictionary.H" #include "IOdictionary.H"
#include "objectRegistry.H" #include "objectRegistry.H"
#include "Pstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * // // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
defineTypeNameAndDebug(Foam::IOdictionary, 0); defineTypeNameAndDebug(Foam::IOdictionary, 0);
// * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
// Parallel aware reading, using non-virtual type information (typeName instead
// of type()) because of use in constructor.
void Foam::IOdictionary::readFile(const bool masterOnly)
{
if (Pstream::master() || !masterOnly)
{
if (debug)
{
Pout<< "IOdictionary : Reading " << objectPath()
<< " from file " << endl;
}
readStream(typeName) >> *this;
close();
}
if (masterOnly)
{
// Scatter master data
if (Pstream::master())
{
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
OPstream toSlave(Pstream::scheduled, slave);
IOdictionary::writeData(toSlave);
}
}
else
{
if (debug)
{
Pout<< "IOdictionary : Reading " << objectPath()
<< " from master processor " << Pstream::masterNo() << endl;
}
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
IOdictionary::readData(fromMaster);
}
}
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::IOdictionary::IOdictionary(const IOobject& io) Foam::IOdictionary::IOdictionary(const IOobject& io)
@ -56,17 +105,41 @@ Foam::IOdictionary::IOdictionary(const IOobject& io)
//<< abort(FatalError); //<< abort(FatalError);
} }
// Everyone check or just master
bool masterOnly =
regIOobject::fileModificationChecking == timeStampMaster
|| regIOobject::fileModificationChecking == inotifyMaster;
// Check if header is ok for READ_IF_PRESENT
bool isHeaderOk = false;
if (io.readOpt() == IOobject::READ_IF_PRESENT)
{
if (masterOnly)
{
if (Pstream::master())
{
isHeaderOk = headerOk();
}
Pstream::scatter(isHeaderOk);
}
else
{
isHeaderOk = headerOk();
}
}
if if
( (
( (
io.readOpt() == IOobject::MUST_READ io.readOpt() == IOobject::MUST_READ
|| io.readOpt() == IOobject::MUST_READ_IF_MODIFIED || io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
) )
|| (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk()) || isHeaderOk
) )
{ {
readStream(typeName) >> *this; readFile(masterOnly);
close();
} }
dictionary::name() = IOobject::objectPath(); dictionary::name() = IOobject::objectPath();
@ -90,17 +163,41 @@ Foam::IOdictionary::IOdictionary(const IOobject& io, const dictionary& dict)
<< endl; << endl;
} }
// Everyone check or just master
bool masterOnly =
regIOobject::fileModificationChecking == timeStampMaster
|| regIOobject::fileModificationChecking == inotifyMaster;
// Check if header is ok for READ_IF_PRESENT
bool isHeaderOk = false;
if (io.readOpt() == IOobject::READ_IF_PRESENT)
{
if (masterOnly)
{
if (Pstream::master())
{
isHeaderOk = headerOk();
}
Pstream::scatter(isHeaderOk);
}
else
{
isHeaderOk = headerOk();
}
}
if if
( (
( (
io.readOpt() == IOobject::MUST_READ io.readOpt() == IOobject::MUST_READ
|| io.readOpt() == IOobject::MUST_READ_IF_MODIFIED || io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
) )
|| (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk()) || isHeaderOk
) )
{ {
readStream(typeName) >> *this; readFile(masterOnly);
close();
} }
else else
{ {

View File

@ -57,6 +57,11 @@ class IOdictionary
public dictionary public dictionary
{ {
// Private Member Functions
//- read dictionary from file
void readFile(const bool);
public: public:
TypeName("dictionary"); TypeName("dictionary");

View File

@ -250,8 +250,27 @@ Foam::Time::Time
// Time objects not registered so do like objectRegistry::checkIn ourselves. // Time objects not registered so do like objectRegistry::checkIn ourselves.
if (runTimeModifiable_) if (runTimeModifiable_)
{ {
monitorPtr_.reset(new fileMonitor()); monitorPtr_.reset
controlDict_.watchIndex() = addWatch(controlDict_.filePath()); (
new fileMonitor
(
regIOobject::fileModificationChecking == inotify
|| regIOobject::fileModificationChecking == inotifyMaster
)
);
// File might not exist yet.
fileName f(controlDict_.filePath());
if (!f.size())
{
// We don't have this file but would like to re-read it.
// Possibly if in master-only reading mode. Use a non-existing
// file to keep fileMonitor synced.
f = controlDict_.objectPath();
}
controlDict_.watchIndex() = addWatch(f);
} }
} }
@ -308,19 +327,36 @@ Foam::Time::Time
readLibs_(controlDict_, "libs"), readLibs_(controlDict_, "libs"),
functionObjects_(*this) functionObjects_(*this)
{ {
// Since could not construct regIOobject with setting:
controlDict_.readOpt() = IOobject::MUST_READ_IF_MODIFIED;
setControls(); setControls();
// Time objects not registered so do like objectRegistry::checkIn ourselves. // Time objects not registered so do like objectRegistry::checkIn ourselves.
if (runTimeModifiable_) if (runTimeModifiable_)
{ {
monitorPtr_.reset(new fileMonitor()); monitorPtr_.reset
(
new fileMonitor
(
regIOobject::fileModificationChecking == inotify
|| regIOobject::fileModificationChecking == inotifyMaster
)
);
// File might not exist yet. // File might not exist yet.
fileName f(controlDict_.filePath()); fileName f(controlDict_.filePath());
if (f != fileName::null)
if (!f.size())
{ {
controlDict_.watchIndex() = addWatch(f); // We don't have this file but would like to re-read it.
// Possibly if in master-only reading mode. Use a non-existing
// file to keep fileMonitor synced.
f = controlDict_.objectPath();
} }
controlDict_.watchIndex() = addWatch(f);
} }
} }

View File

@ -211,7 +211,14 @@ void Foam::Time::readModifiedObjects()
// valid filePath). // valid filePath).
// Note: requires same ordering in objectRegistries on different // Note: requires same ordering in objectRegistries on different
// processors! // processors!
monitorPtr_().updateStates(Pstream::parRun()); monitorPtr_().updateStates
(
(
regIOobject::fileModificationChecking == inotifyMaster
|| regIOobject::fileModificationChecking == timeStampMaster
),
Pstream::parRun()
);
// Time handling is special since controlDict_ is the one dictionary // Time handling is special since controlDict_ is the one dictionary
// that is not registered to any database. // that is not registered to any database.

View File

@ -36,6 +36,35 @@ int Foam::regIOobject::fileModificationSkew
Foam::debug::optimisationSwitch("fileModificationSkew", 30) Foam::debug::optimisationSwitch("fileModificationSkew", 30)
); );
namespace Foam
{
template<>
const char* Foam::NamedEnum<Foam::regIOobject::fileCheckTypes, 4>::names[] =
{
"timeStamp",
"timeStampMaster",
"inotify",
"inotifyMaster"
};
}
const Foam::NamedEnum<Foam::regIOobject::fileCheckTypes, 4>
Foam::regIOobject::fileCheckTypesNames;
// Default fileCheck type
Foam::regIOobject::fileCheckTypes Foam::regIOobject::fileModificationChecking
(
fileCheckTypesNames.read
(
debug::optimisationSwitches().lookup
(
"fileModificationChecking"
//Foam::regIOobject::timeStamp
)
)
);
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
@ -149,10 +178,13 @@ bool Foam::regIOobject::checkIn()
} }
fileName f = filePath(); fileName f = filePath();
if (f != fileName::null) if (!f.size())
{ {
watchIndex_ = time().addWatch(f); // We don't have this file but would like to re-read it.
// Possibly if master-only reading mode.
f = objectPath();
} }
watchIndex_ = time().addWatch(f);
} }
// check-in on defaultRegion is allowed to fail, since subsetted meshes // check-in on defaultRegion is allowed to fail, since subsetted meshes

View File

@ -41,6 +41,7 @@ SourceFiles
#include "IOobject.H" #include "IOobject.H"
#include "typeInfo.H" #include "typeInfo.H"
#include "OSspecific.H" #include "OSspecific.H"
#include "NamedEnum.H"
// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
@ -57,6 +58,20 @@ class regIOobject
public IOobject public IOobject
{ {
public:
//- Types of communications
enum fileCheckTypes
{
timeStamp,
timeStampMaster,
inotify,
inotifyMaster
};
static const NamedEnum<fileCheckTypes, 4> fileCheckTypesNames;
private: private:
// Private data // Private data
@ -95,6 +110,8 @@ public:
static int fileModificationSkew; static int fileModificationSkew;
static fileCheckTypes fileModificationChecking;
// Constructors // Constructors

View File

@ -26,7 +26,7 @@ License
#include "regIOobject.H" #include "regIOobject.H"
#include "IFstream.H" #include "IFstream.H"
#include "Time.H" #include "Time.H"
//#include "PstreamReduceOps.H" #include "Pstream.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -170,8 +170,50 @@ bool Foam::regIOobject::readData(Istream&)
bool Foam::regIOobject::read() bool Foam::regIOobject::read()
{ {
bool ok = readData(readStream(type())); // Note: cannot do anything in readStream itself since this is used by
// e.g. GeometricField.
bool masterOnly =
regIOobject::fileModificationChecking == timeStampMaster
|| regIOobject::fileModificationChecking == inotifyMaster;
bool ok;
if (Pstream::master() || !masterOnly)
{
ok = readData(readStream(type()));
close(); close();
}
if (masterOnly)
{
// Scatter master data
if (Pstream::master())
{
for
(
int slave=Pstream::firstSlave();
slave<=Pstream::lastSlave();
slave++
)
{
OPstream toSlave(Pstream::scheduled, slave);
writeData(toSlave);
}
}
else
{
if (IFstream::debug)
{
Pout<< "regIOobject::read() : "
<< "reading object " << name()
<< " from master processor " << Pstream::masterNo()
<< endl;
}
IPstream fromMaster(Pstream::scheduled, Pstream::masterNo());
ok = readData(fromMaster);
}
}
return ok; return ok;
} }

View File

@ -55,6 +55,12 @@ Foam::argList::initValidTables::initValidTables()
); );
argList::addBoolOption("parallel", "run in parallel"); argList::addBoolOption("parallel", "run in parallel");
validParOptions.set("parallel", ""); validParOptions.set("parallel", "");
argList::addOption
(
"roots", "(dir1 .. dirn)",
"slave root directories for distributed running"
);
validParOptions.set("roots", "(dir1 .. dirn)");
Pstream::addValidParOptions(validParOptions); Pstream::addValidParOptions(validParOptions);
} }
@ -511,6 +517,10 @@ Foam::argList::argList
// Case is a single processor run unless it is running parallel // Case is a single processor run unless it is running parallel
int nProcs = 1; int nProcs = 1;
// Roots if running distributed
fileNameList roots;
// If this actually is a parallel run // If this actually is a parallel run
if (parRunControl_.parRun()) if (parRunControl_.parRun())
{ {
@ -520,10 +530,21 @@ Foam::argList::argList
// establish rootPath_/globalCase_/case_ for master // establish rootPath_/globalCase_/case_ for master
getRootCase(); getRootCase();
IFstream decompDictStream // See if running distributed (different roots for different procs)
( label dictNProcs = -1;
rootPath_/globalCase_/"system/decomposeParDict" fileName source;
);
if (options_.found("roots"))
{
IStringStream str(options_["roots"]);
str >> roots;
dictNProcs = roots.size()+1;
source = "roots-command-line";
}
else
{
source = rootPath_/globalCase_/"system/decomposeParDict";
IFstream decompDictStream(source);
if (!decompDictStream.good()) if (!decompDictStream.good())
{ {
@ -535,14 +556,17 @@ Foam::argList::argList
dictionary decompDict(decompDictStream); dictionary decompDict(decompDictStream);
label dictNProcs dictNProcs = readLabel
(
readLabel
( (
decompDict.lookup("numberOfSubdomains") decompDict.lookup("numberOfSubdomains")
)
); );
if (decompDict.lookupOrDefault("distributed", false))
{
decompDict.lookup("roots") >> roots;
}
}
// Check number of processors. // Check number of processors.
// nProcs => number of actual procs // nProcs => number of actual procs
// dictNProcs => number of procs specified in decompositionDict // dictNProcs => number of procs specified in decompositionDict
@ -555,18 +579,17 @@ Foam::argList::argList
if (dictNProcs > Pstream::nProcs()) if (dictNProcs > Pstream::nProcs())
{ {
FatalError FatalError
<< decompDictStream.name() << source
<< " specifies " << dictNProcs << " specifies " << dictNProcs
<< " processors but job was started with " << " processors but job was started with "
<< Pstream::nProcs() << " processors." << Pstream::nProcs() << " processors."
<< exit(FatalError); << exit(FatalError);
} }
// distributed data // distributed data
if (decompDict.lookupOrDefault("distributed", false)) if (roots.size())
{ {
fileNameList roots;
decompDict.lookup("roots") >> roots;
forAll(roots, i) forAll(roots, i)
{ {
roots[i] = roots[i].expand(); roots[i] = roots[i].expand();
@ -575,7 +598,8 @@ Foam::argList::argList
if (roots.size() != Pstream::nProcs()-1) if (roots.size() != Pstream::nProcs()-1)
{ {
FatalError FatalError
<< "number of entries in decompositionDict::roots" << "number of entries in roots "
<< roots.size()
<< " is not equal to the number of slaves " << " is not equal to the number of slaves "
<< Pstream::nProcs()-1 << Pstream::nProcs()-1
<< exit(FatalError); << exit(FatalError);
@ -709,8 +733,12 @@ Foam::argList::argList
if (parRunControl_.parRun()) if (parRunControl_.parRun())
{ {
Info<< "Slaves : " << slaveProcs << nl Info<< "Slaves : " << slaveProcs << nl;
<< "Pstream initialized with:" << nl if (roots.size())
{
Info<< "Roots : " << roots << nl;
}
Info<< "Pstream initialized with:" << nl
<< " floatTransfer : " << Pstream::floatTransfer << nl << " floatTransfer : " << Pstream::floatTransfer << nl
<< " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl << " nProcsSimpleSum : " << Pstream::nProcsSimpleSum << nl
<< " commsType : " << " commsType : "
@ -726,6 +754,10 @@ Foam::argList::argList
{ {
jobInfo.add("slaves", slaveProcs); jobInfo.add("slaves", slaveProcs);
} }
if (roots.size())
{
jobInfo.add("roots", roots);
}
jobInfo.write(); jobInfo.write();
// Switch on signal trapping. We have to wait until after Pstream::init // Switch on signal trapping. We have to wait until after Pstream::init