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

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

View File

@ -32,17 +32,17 @@ Class
#include "PackedList.H"
#include "PstreamReduceOps.H"
#include "OSspecific.H"
#include "regIOobject.H" // for fileModificationSkew symbol
#ifdef FOAM_USE_STAT
# include "OSspecific.H"
# include "regIOobject.H" // for fileModificationSkew symbol
#else
#ifdef FOAM_USE_INOTIFY
# include <sys/inotify.h>
# include <sys/ioctl.h>
# include <errno.h>
# define EVENT_SIZE ( sizeof (struct inotify_event) )
# define EVENT_LEN (EVENT_SIZE + 16)
# define EVENT_BUF_LEN ( 1024 * EVENT_LEN )
#else
# include "OSspecific.H"
#endif
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
@ -111,78 +111,77 @@ namespace Foam
{
public:
#ifdef FOAM_USE_STAT
//- From watch descriptor to modified time
DynamicList<time_t> lastMod_;
const bool useInotify_;
//- initialize HashTable size
inline fileMonitorWatcher(const label sz = 20)
:
lastMod_(sz)
{}
// For inotify
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);
}
//- File descriptor for the inotify instance
int inotifyFd_;
lastMod_(watchFd) = lastModified(fName);
return true;
}
//- Current watchIDs and corresponding directory id
DynamicList<label> dirWatches_;
DynamicList<fileName> dirFiles_;
inline bool removeWatch(const label watchFd)
{
lastMod_[watchFd] = 0;
return true;
}
// For stat
//- From watch descriptor to modified time
DynamicList<time_t> lastMod_;
#else
//- File descriptor for the inotify instance
int inotifyFd_;
//- Current watchIDs and corresponding directory id
DynamicList<label> dirWatches_;
DynamicList<fileName> dirFiles_;
//- initialise inotify
inline fileMonitorWatcher(const label sz = 20)
inline fileMonitorWatcher(const bool useInotify, const label sz = 20)
:
inotifyFd_(inotify_init()),
dirWatches_(sz),
dirFiles_(sz)
useInotify_(useInotify)
{
if (inotifyFd_ < 0)
if (useInotify_)
{
static bool hasWarned = false;
if (!hasWarned)
#ifdef FOAM_USE_INOTIFY
inotifyFd_ = inotify_init();
dirWatches_.setCapacity(sz);
dirFiles_.setCapacity(sz);
if (inotifyFd_ < 0)
{
hasWarned = true;
WarningIn("fileMonitorWatcher(const label)")
<< "Failed allocating an inotify descriptor : "
<< string(strerror(errno)) << endl
<< " Please increase the number of allowable "
<< "inotify instances" << endl
<< " (/proc/sys/fs/inotify/max_user_instances"
<< " on Linux)" << endl
<< " , switch off runTimeModifiable." << endl
<< " or compile this file with FOAM_USE_STAT to use"
<< " time stamps instead of inotify." << endl
<< " Continuing without additional file monitoring."
<< endl;
static bool hasWarned = false;
if (!hasWarned)
{
hasWarned = true;
WarningIn("fileMonitorWatcher(const bool, const label)")
<< "Failed allocating an inotify descriptor : "
<< string(strerror(errno)) << endl
<< " Please increase the number of allowable "
<< "inotify instances" << endl
<< " (/proc/sys/fs/inotify/max_user_instances"
<< " on Linux)" << endl
<< " , switch off runTimeModifiable." << endl
<< " or compile this file without "
<< "FOAM_USE_INOTIFY"
<< " to use time stamps instead of inotify." << endl
<< " Continuing without additional file"
<< " monitoring."
<< 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
inline ~fileMonitorWatcher()
{
if (inotifyFd_ >= 0)
#ifdef FOAM_USE_INOTIFY
if (useInotify_ && inotifyFd_ >= 0)
{
forAll(dirWatches_, i)
{
@ -197,57 +196,92 @@ namespace Foam
}
}
}
#endif
}
inline bool addWatch(const label watchFd, const fileName& fName)
{
if (inotifyFd_ < 0)
if (useInotify_)
{
return false;
if (inotifyFd_ < 0)
{
return false;
}
#ifdef FOAM_USE_INOTIFY
// 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_,
dir.c_str(),
IN_CLOSE_WRITE
);
if (dirWatchID < 0)
{
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Failed adding watch " << watchFd
<< " to directory " << fName << " due to "
<< string(strerror(errno))
<< exit(FatalError);
}
}
if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
{
// Reuse of watchFd : should have dir watchID set to -1.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
dirWatches_(watchFd) = dirWatchID;
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);
}
// Add/retrieve watch on directory containing file
label dirWatchID = inotify_add_watch
(
inotifyFd_,
fName.path().c_str(),
IN_CLOSE_WRITE
);
if (dirWatchID < 0)
{
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Failed adding watch " << watchFd
<< " to directory " << fName << " due to "
<< string(strerror(errno))
<< exit(FatalError);
}
if (watchFd < dirWatches_.size() && dirWatches_[watchFd] != -1)
{
// Reuse of watchFd : should have dir watchID set to -1.
FatalErrorIn("addWatch(const label, const fileName&)")
<< "Problem adding watch " << watchFd
<< " to file " << fName
<< abort(FatalError);
}
dirWatches_(watchFd) = dirWatchID;
dirFiles_(watchFd) = fName.name();
return true;
}
inline bool removeWatch(const label watchFd)
{
if (inotifyFd_ < 0)
if (useInotify_)
{
return false;
}
if (inotifyFd_ < 0)
{
return false;
}
dirWatches_[watchFd] = -1;
dirWatches_[watchFd] = -1;
}
else
{
lastMod_[watchFd] = 0;
}
return true;
}
#endif
};
//! @endcond
@ -258,131 +292,146 @@ namespace Foam
void Foam::fileMonitor::checkFiles() const
{
#ifdef FOAM_USE_STAT
forAll(watcher_->lastMod_, watchFd)
if (useInotify_)
{
time_t oldTime = watcher_->lastMod_[watchFd];
#ifdef FOAM_USE_INOTIFY
// Large buffer for lots of events
char buffer[EVENT_BUF_LEN];
if (oldTime != 0)
while (true)
{
const fileName& fName = watchFile_[watchFd];
time_t newTime = lastModified(fName);
struct timeval zeroTimeout = {0, 0};
if (newTime == 0)
//- Pre-allocated structure containing file descriptors
fd_set fdSet;
// Add notify descriptor to select fd_set
FD_ZERO(&fdSet);
FD_SET(watcher_->inotifyFd_, &fdSet);
int ready = select
(
watcher_->inotifyFd_+1, // num filedescriptors in fdSet
&fdSet, // fdSet with only inotifyFd
NULL, // No writefds
NULL, // No errorfds
&zeroTimeout // eNo timeout
);
if (ready < 0)
{
state_[watchFd] = DELETED;
FatalErrorIn("fileMonitor::updateStates()")
<< "Problem in issuing select."
<< abort(FatalError);
}
else if (FD_ISSET(watcher_->inotifyFd_, &fdSet))
{
// Read events
ssize_t nBytes = read
(
watcher_->inotifyFd_,
buffer,
EVENT_BUF_LEN
);
if (nBytes < 0)
{
FatalErrorIn("fileMonitor::updateStates(const fileName&)")
<< "read of " << watcher_->inotifyFd_
<< " failed with " << label(nBytes)
<< abort(FatalError);
}
// Go through buffer, consuming events
int i = 0;
while (i < nBytes)
{
const struct inotify_event* inotifyEvent =
reinterpret_cast<const struct inotify_event*>
(
&buffer[i]
);
//Pout<< "watchFd:" << inotifyEvent->wd << nl
// << "mask:" << inotifyEvent->mask << nl
// << endl;
//Pout<< "file:" << fileName(inotifyEvent->name) << endl;
//Pout<< "len:" << inotifyEvent->len << endl;
if
(
(inotifyEvent->mask & IN_CLOSE_WRITE)
&& inotifyEvent->len
)
{
// Search for file
forAll(watcher_->dirWatches_, i)
{
label id = watcher_->dirWatches_[i];
if
(
id == inotifyEvent->wd
&& inotifyEvent->name == watcher_->dirFiles_[i]
)
{
// Correct directory and name
state_[i] = MODIFIED;
}
}
}
i += EVENT_SIZE + inotifyEvent->len;
}
}
else
{
if (newTime > (oldTime + regIOobject::fileModificationSkew))
// No data
return;
}
}
#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)
{
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
state_[watchFd] = DELETED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
}
}
}
#else
// Large buffer for lots of events
char buffer[EVENT_BUF_LEN];
while (true)
{
struct timeval zeroTimeout = {0, 0};
//- Pre-allocated structure containing file descriptors
fd_set fdSet;
// Add notify descriptor to select fd_set
FD_ZERO(&fdSet);
FD_SET(watcher_->inotifyFd_, &fdSet);
int ready = select
(
watcher_->inotifyFd_+1, // num filedescriptors in fdSet
&fdSet, // fdSet with only inotifyFd
NULL, // No writefds
NULL, // No errorfds
&zeroTimeout // eNo timeout
);
if (ready < 0)
{
FatalErrorIn("fileMonitor::updateStates()")
<< "Problem in issuing select."
<< abort(FatalError);
}
else if (FD_ISSET(watcher_->inotifyFd_, &fdSet))
{
// Read events
ssize_t nBytes = read(watcher_->inotifyFd_, buffer, EVENT_BUF_LEN);
if (nBytes < 0)
{
FatalErrorIn("fileMonitor::updateStates(const fileName&)")
<< "read of " << watcher_->inotifyFd_
<< " failed with " << label(nBytes)
<< abort(FatalError);
}
// Go through buffer, consuming events
int i = 0;
while (i < nBytes)
{
const struct inotify_event* inotifyEvent =
reinterpret_cast<const struct inotify_event*>
(
&buffer[i]
);
//Pout<< "watchFd:" << inotifyEvent->wd << nl
// << "mask:" << inotifyEvent->mask << nl
// << endl;
//Pout<< "file:" << fileName(inotifyEvent->name) << endl;
//Pout<< "len:" << inotifyEvent->len << endl;
if ((inotifyEvent->mask & IN_CLOSE_WRITE) && inotifyEvent->len)
{
// Search for file
forAll(watcher_->dirWatches_, i)
if (newTime > (oldTime + regIOobject::fileModificationSkew))
{
label id = watcher_->dirWatches_[i];
if
(
id == inotifyEvent->wd
&& inotifyEvent->name == watcher_->dirFiles_[i]
)
{
// Correct directory and name
state_[i] = MODIFIED;
}
watcher_->lastMod_[watchFd] = newTime;
state_[watchFd] = MODIFIED;
}
else
{
state_[watchFd] = UNMODIFIED;
}
}
i += EVENT_SIZE + inotifyEvent->len;
}
}
else
{
// No data
return;
}
}
#endif
}
// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
Foam::fileMonitor::fileMonitor()
Foam::fileMonitor::fileMonitor(const bool useInotify)
:
useInotify_(useInotify),
state_(20),
watchFile_(20),
freeWatchFds_(2),
watcher_(new fileMonitorWatcher(20))
watcher_(new fileMonitorWatcher(useInotify_, 20))
{}
@ -394,6 +443,8 @@ Foam::fileMonitor::~fileMonitor()
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
// Note: fName might not exist (on slaves if in master-only mode for
// regIOobject)
Foam::label Foam::fileMonitor::addWatch(const fileName& fName)
{
label watchFd;
@ -458,50 +509,97 @@ const
}
void Foam::fileMonitor::updateStates(const bool syncPar) const
void Foam::fileMonitor::updateStates
(
const bool masterOnly,
const bool syncPar
) const
{
checkFiles();
if (Pstream::master() || !masterOnly)
{
checkFiles();
}
if (syncPar)
{
PackedList<2> stats(state_.size());
forAll(state_, watchFd)
// Pack current state (might be on master only)
PackedList<2> stats(state_.size(), MODIFIED);
if (Pstream::master() || !masterOnly)
{
stats[watchFd] = static_cast<unsigned int>(state_[watchFd]);
forAll(state_, watchFd)
{
stats[watchFd] = static_cast<unsigned int>(state_[watchFd]);
}
}
// Save local state for warning message below
PackedList<2> thisProcStats(stats);
if (stats.storage().size() == 1)
// Save local state for warning message below
PackedList<2> thisProcStats;
if (!masterOnly)
{
// Optimisation valid for most cases.
reduce(stats.storage()[0], reduceFileStates());
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
{
Pstream::listCombineGather
(
stats.storage(),
combineReduceFileStates()
);
// Reduce
if (stats.storage().size() == 1)
{
// Optimisation valid for most cases.
reduce(stats.storage()[0], reduceFileStates());
}
else
{
Pstream::listCombineGather
(
stats.storage(),
combineReduceFileStates()
);
}
}
// Update local state
forAll(state_, watchFd)
{
if (thisProcStats[watchFd] != UNMODIFIED)
if (masterOnly)
{
if (stats[watchFd] == UNMODIFIED)
// 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)
{
WarningIn("fileMonitor::updateStates(const bool) const")
<< "Delaying reading " << watchFile_[watchFd]
<< " due to inconsistent "
"file time-stamps between processors"
<< endl;
}
else
{
unsigned int stat = stats[watchFd];
state_[watchFd] = fileState(stat);
if (stats[watchFd] == UNMODIFIED)
{
WarningIn("fileMonitor::updateStates(const bool) const")
<< "Delaying reading " << watchFile_[watchFd]
<< " due to inconsistent "
"file time-stamps between processors"
<< endl;
}
else
{
unsigned int stat = stats[watchFd];
state_[watchFd] = fileState(stat);
}
}
}
}
@ -511,10 +609,12 @@ void Foam::fileMonitor::updateStates(const bool syncPar) const
void Foam::fileMonitor::setUnmodified(const label watchFd)
{
#ifdef FOAM_USE_STAT
watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
#endif
state_[watchFd] = UNMODIFIED;
if (!useInotify_)
{
watcher_->lastMod_[watchFd] = lastModified(watchFile_[watchFd]);
}
}

View File

@ -28,10 +28,11 @@ Description
Checking for changes to files.
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
does not exist) uses the stat function call.
Compile with FOAM_USE_INOTIFY to use the inotify
(Linux specific, since 2.6.13) framework. The problem is that inotify does
not work on nfs3 mounted directories!!
SourceFiles
fileMonitor.C
@ -78,6 +79,9 @@ public:
private:
// Private data
//- Whether to use inotify (requires -DFOAM_USE_INOTIFY, see above)
const bool useInotify_;
//- State for all watchFds
mutable DynamicList<fileState> state_;
@ -111,7 +115,7 @@ public:
// Constructors
//- Construct null
fileMonitor();
fileMonitor(const bool useInotify);
//- Destructor
@ -133,7 +137,11 @@ public:
fileState getState(const label watchFd) const;
//- 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
void setUnmodified(const label watchFd);

View File

@ -31,12 +31,61 @@ Description
#include "IOdictionary.H"
#include "objectRegistry.H"
#include "Pstream.H"
// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
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 * * * * * * * * * * * * * * //
Foam::IOdictionary::IOdictionary(const IOobject& io)
@ -56,17 +105,41 @@ Foam::IOdictionary::IOdictionary(const IOobject& io)
//<< 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
(
(
io.readOpt() == IOobject::MUST_READ
|| io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
)
|| (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk())
|| isHeaderOk
)
{
readStream(typeName) >> *this;
close();
readFile(masterOnly);
}
dictionary::name() = IOobject::objectPath();
@ -90,17 +163,41 @@ Foam::IOdictionary::IOdictionary(const IOobject& io, const dictionary& dict)
<< 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
(
(
io.readOpt() == IOobject::MUST_READ
|| io.readOpt() == IOobject::MUST_READ_IF_MODIFIED
)
|| (io.readOpt() == IOobject::READ_IF_PRESENT && headerOk())
|| isHeaderOk
)
{
readStream(typeName) >> *this;
close();
readFile(masterOnly);
}
else
{

View File

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

View File

@ -250,8 +250,27 @@ Foam::Time::Time
// Time objects not registered so do like objectRegistry::checkIn ourselves.
if (runTimeModifiable_)
{
monitorPtr_.reset(new fileMonitor());
controlDict_.watchIndex() = addWatch(controlDict_.filePath());
monitorPtr_.reset
(
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"),
functionObjects_(*this)
{
// Since could not construct regIOobject with setting:
controlDict_.readOpt() = IOobject::MUST_READ_IF_MODIFIED;
setControls();
// Time objects not registered so do like objectRegistry::checkIn ourselves.
if (runTimeModifiable_)
{
monitorPtr_.reset(new fileMonitor());
monitorPtr_.reset
(
new fileMonitor
(
regIOobject::fileModificationChecking == inotify
|| regIOobject::fileModificationChecking == inotifyMaster
)
);
// File might not exist yet.
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).
// Note: requires same ordering in objectRegistries on different
// 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
// that is not registered to any database.

View File

@ -36,6 +36,35 @@ int Foam::regIOobject::fileModificationSkew
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 * * * * * * * * * * * * * * //
@ -149,10 +178,13 @@ bool Foam::regIOobject::checkIn()
}
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

View File

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

View File

@ -26,7 +26,7 @@ License
#include "regIOobject.H"
#include "IFstream.H"
#include "Time.H"
//#include "PstreamReduceOps.H"
#include "Pstream.H"
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
@ -170,8 +170,50 @@ bool Foam::regIOobject::readData(Istream&)
bool Foam::regIOobject::read()
{
bool ok = readData(readStream(type()));
close();
// 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();
}
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;
}

View File

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