ENH: add -verbose support into argList

- similar to -dry-run handling, can be interrogated from argList,
  which makes it simpler to add into utilities.

- support multiple uses of -dry-run and -verbose to increase the
  level. For example, could have

    someApplication -verbose -verbose

 and inside of the application:

    if (args.verbose() > 2) ...

BUG: error with empty distributed roots specification (fixes #2196)

- previously used the size of distributed roots to transmit if the
  case was running in distributed mode, but this behaves rather poorly
  with bad input. Specifically, the following questionable setup:

      distributed true;
      roots ( /*none*/ );

  Now transmit the ParRunControl distributed() value instead,
  and also emit a gentle warning for the user:

      WARNING: running distributed but did not specify roots!
This commit is contained in:
Mark Olesen
2021-11-05 21:02:21 +01:00
parent c45c649d15
commit 5a121119e6
16 changed files with 249 additions and 135 deletions

View File

@ -28,6 +28,7 @@ License
#include "argList.H"
#include "OSspecific.H"
#include "Switch.H"
#include "clock.H"
#include "dictionary.H"
#include "IOobject.H"
@ -110,7 +111,7 @@ Foam::argList::initValidTables::initValidTables()
(
"opt-switch",
"name=val",
"Specify the value of a registered optimisation switch (int/bool)."
"Specify the value of a registered optimisation switch."
" Default is 1 if the value is omitted."
" (Can be used multiple times)",
true // advanced option
@ -326,7 +327,7 @@ void Foam::argList::addBoolOption
bool advanced
)
{
addOption(optName, "", usage, advanced);
argList::addOption(optName, "", usage, advanced);
}
@ -455,7 +456,17 @@ void Foam::argList::addDryRunOption
bool advanced
)
{
addOption("dry-run", "", usage, advanced);
argList::addBoolOption("dry-run", usage, advanced);
}
void Foam::argList::addVerboseOption
(
const string& usage,
bool advanced
)
{
argList::addBoolOption("verbose", usage, advanced);
}
@ -469,7 +480,7 @@ void Foam::argList::noFunctionObjects(bool addWithOption)
if (addWithOption)
{
addBoolOption
argList::addBoolOption
(
"withFunctionObjects",
"Execute functionObjects",
@ -487,7 +498,7 @@ void Foam::argList::noJobInfo()
void Foam::argList::noLibs()
{
addBoolOption
argList::addBoolOption
(
"no-libs",
"Disable use of the controlDict libs entry",
@ -768,11 +779,6 @@ void Foam::argList::setCasePaths()
// Executable name, unless already present in the environment
setEnv("FOAM_EXECUTABLE", executable_, false);
if (validOptions.found("dry-run") && options_.found("dry-run"))
{
runControl_.dryRun(true);
}
}
@ -847,6 +853,9 @@ Foam::argList::argList
// Set executable name immediately - useful when emitting errors.
executable_ = fileName(args_[0]).name();
// Count -dry-run and -verbose switches
int numDryRun = 0, numVerbose = 0;
// Check arguments and options, argv[0] was already handled
int nArgs = 1;
for (int argi = 1; argi < args_.size(); ++argi)
@ -862,15 +871,31 @@ Foam::argList::argList
{
Warning
<< "Ignoring lone '-' on the command-line" << endl;
continue;
}
else if
// Option known and expects an argument?
// - use Switch for a tri-state
// True : known option, expects a parameter
// False : known option, no parameter
// bad() : unknown option
Switch wantArg(Switch::INVALID);
auto optIter = validOptions.cfind(optName);
if
(
validOptions.lookup(optName, "").size()
|| validParOptions.lookup(optName, "").size()
optIter.found()
|| (optIter = validParOptions.cfind(optName)).found()
)
{
// If the option is known to require an argument,
// get it or emit a FatalError.
wantArg = !optIter.val().empty();
}
if (wantArg)
{
// Known option and expects a parameter
// - get it or emit a FatalError.
++argi;
if (argi >= args_.size())
@ -883,12 +908,16 @@ Foam::argList::argList
<< "See '" << executable_ << " -help' for usage"
<< nl << nl;
Pstream::exit(1); // works for serial and parallel
Pstream::exit(1); // works for serial and parallel
}
commandLine_ += ' ';
commandLine_ += args_[argi];
//
// Special handling of these options
//
if (strcmp(optName, "lib") == 0)
{
// The '-lib' option:
@ -921,7 +950,7 @@ Foam::argList::argList
}
else
{
// Regular option:
// Regular option (with a parameter):
// Duplicates handled by using the last -option specified
options_.set(optName, args_[argi]);
}
@ -932,6 +961,19 @@ Foam::argList::argList
// registered as existing.
options_.insert(optName, "");
// Special increment handling for some known flags
if (wantArg.good())
{
if (strcmp(optName, "dry-run") == 0)
{
++numDryRun;
}
else if (strcmp(optName, "verbose") == 0)
{
++numVerbose;
}
}
}
}
else
@ -944,6 +986,10 @@ Foam::argList::argList
}
}
// Commit number of -dry-run and -verbose flag occurrences
runControl_.dryRun(numDryRun);
runControl_.verbose(numVerbose);
args_.resize(nArgs);
parse(checkArgs, checkOpts, initialise);
@ -1043,7 +1089,7 @@ void Foam::argList::parse
foamVersion::printBuildInfo(Info.stdStream(), false);
FatalError.write(Info, false);
Pstream::exit(1); // works for serial and parallel
Pstream::exit(1); // works for serial and parallel
}
if (initialise)
@ -1227,7 +1273,13 @@ void Foam::argList::parse
{
source = "-roots";
runControl_.distributed(true);
if (roots.size() != 1)
if (roots.empty())
{
FatalErrorInFunction
<< "The -roots option must contain values"
<< exit(FatalError);
}
if (roots.size() > 1)
{
dictNProcs = roots.size()+1;
}
@ -1235,17 +1287,27 @@ void Foam::argList::parse
else if (options_.found("hostRoots"))
{
source = "-hostRoots";
roots.resize(Pstream::nProcs()-1, fileName::null);
runControl_.distributed(true);
ITstream is(this->lookup("hostRoots"));
List<Tuple2<wordRe, fileName>> hostRoots(is);
checkITstream(is, "hostRoots");
if (hostRoots.empty())
{
FatalErrorInFunction
<< "The -hostRoots option must contain values"
<< exit(FatalError);
}
// Match machine names to roots
roots.resize(Pstream::nProcs()-1, fileName::null);
for (const auto& hostRoot : hostRoots)
{
labelList matched
(
findStrings(hostRoot.first(), hostMachine)
findMatchingStrings(hostRoot.first(), hostMachine)
);
for (const label matchi : matched)
{
@ -1275,7 +1337,7 @@ void Foam::argList::parse
}
}
if (roots.size() != 1)
if (roots.size() > 1)
{
dictNProcs = roots.size()+1;
}
@ -1312,6 +1374,13 @@ void Foam::argList::parse
nDomainsMandatory = true;
runControl_.distributed(true);
decompDict.readEntry("roots", roots);
if (roots.empty())
{
DetailInfo
<< "WARNING: running distributed"
<< " but did not specify roots!" << nl;
}
}
// Get numberOfSubdomains if it exists.
@ -1330,7 +1399,7 @@ void Foam::argList::parse
{
// Optional if using default location
DetailInfo
<< "Warning: running without decomposeParDict "
<< "WARNING: running without decomposeParDict "
<< this->relativePath(source) << nl;
}
else
@ -1415,8 +1484,13 @@ void Foam::argList::parse
{
options_.set("case", roots[subproci-1]/globalCase_);
OPstream toSubproc(Pstream::commsTypes::scheduled, subproci);
toSubproc << args_ << options_ << roots.size();
OPstream toProc(Pstream::commsTypes::scheduled, subproci);
toProc
<< args_ << options_
<< runControl_.distributed()
<< label(runControl_.dryRun())
<< label(runControl_.verbose());
}
options_.erase("case");
@ -1463,24 +1537,34 @@ void Foam::argList::parse
// Distribute the master's argument list (unaltered)
for (const int subproci : Pstream::subProcs())
{
OPstream toSubproc(Pstream::commsTypes::scheduled, subproci);
toSubproc << args_ << options_ << roots.size();
OPstream toProc(Pstream::commsTypes::scheduled, subproci);
toProc
<< args_ << options_
<< runControl_.distributed()
<< label(runControl_.dryRun())
<< label(runControl_.verbose());
}
}
}
else
{
// Collect the master's argument list
label nroots;
bool isDistributed;
label numDryRun, numVerbose;
IPstream fromMaster
(
Pstream::commsTypes::scheduled,
Pstream::masterNo()
);
fromMaster >> args_ >> options_ >> nroots;
fromMaster
>> args_ >> options_
>> isDistributed
>> numDryRun >> numVerbose;
runControl_.distributed(nroots);
runControl_.distributed(isDistributed);
runControl_.dryRun(numDryRun);
runControl_.verbose(numVerbose);
// Establish rootPath_/globalCase_/case_ for sub-process
setCasePaths();

View File

@ -366,16 +366,23 @@ public:
//- Return the run control (parallel, dry-run etc)
inline const ParRunControl& runControl() const noexcept;
//- Return the dryRun flag
inline bool dryRun() const noexcept;
//- Modify the dryRun flag
inline bool dryRun(const bool on) noexcept;
//- Return distributed flag
//- (i.e. are rootPaths different on different machines)
inline bool distributed() const noexcept;
//- Return the dry-run flag
inline int dryRun() const noexcept;
//- Modify the dry-run flag
inline int dryRun(const int level) noexcept;
//- Return the verbose flag
inline int verbose() const noexcept;
//- Modify the verbose flag
inline int verbose(const int level) noexcept;
//- Mutable access to the loaded dynamic libraries
inline dlLibraryTable& libs() const noexcept;
@ -603,10 +610,17 @@ public:
// Queries the Foam::infoDetailLevel flag.
static bool bannerEnabled();
//- Add a 'dry-run' bool option to validOptions with usage information
//- Enable a 'dry-run' bool option, with usage information
static void addDryRunOption
(
const string& usage, //! usage information (mandatory)
const string& usage, //! usage information (expected)
bool advanced = false
);
//- Enable a 'verbose' bool option, with usage information
static void addVerboseOption
(
const string& usage, //! usage information (expected)
bool advanced = false
);

View File

@ -107,21 +107,33 @@ Foam::argList::runControl() const noexcept
}
inline bool Foam::argList::dryRun() const noexcept
inline bool Foam::argList::distributed() const noexcept
{
return runControl_.distributed();
}
inline int Foam::argList::dryRun() const noexcept
{
return runControl_.dryRun();
}
inline bool Foam::argList::dryRun(const bool on) noexcept
inline int Foam::argList::dryRun(const int level) noexcept
{
return runControl_.dryRun(on);
return runControl_.dryRun(level);
}
inline bool Foam::argList::distributed() const noexcept
inline int Foam::argList::verbose() const noexcept
{
return runControl_.distributed();
return runControl_.verbose();
}
inline int Foam::argList::verbose(const int level) noexcept
{
return runControl_.verbose(level);
}

View File

@ -54,7 +54,8 @@ namespace Foam
class ParRunControl
{
bool dryRun_;
int dryRun_;
int verbose_;
bool parallel_;
bool distributed_;
@ -63,7 +64,8 @@ public:
//- Default construct
ParRunControl()
:
dryRun_(false),
dryRun_(0),
verbose_(0),
parallel_(false),
distributed_(false)
{}
@ -79,49 +81,68 @@ public:
}
//- Initialize Pstream for a parallel run
void runPar(int& argc, char**& argv, bool needsThread)
{
if (!UPstream::init(argc, argv, needsThread))
// Parallel Control
//- Initialize Pstream for a parallel run
void runPar(int& argc, char**& argv, bool needsThread)
{
Info<< "Failed to start parallel run" << endl;
UPstream::exit(1);
if (!UPstream::init(argc, argv, needsThread))
{
Info<< "Failed to start parallel run" << endl;
UPstream::exit(1);
}
parallel_ = true;
}
parallel_ = true;
}
//- True if set as 'dry-run'
bool dryRun() const noexcept
{
return dryRun_;
}
//- True if this is a parallel run
bool parRun() const noexcept
{
return parallel_;
}
//- Set as 'dry-run', return old value
bool dryRun(bool on) noexcept
{
bool old(dryRun_);
dryRun_ = on;
return old;
}
//- True if this is a parallel run and uses distributed roots.
bool distributed() const noexcept
{
return (parallel_ && distributed_);
}
//- True if this is a parallel run
bool parRun() const noexcept
{
return parallel_;
}
//- Set use of distributed roots, but only if actually parallel
void distributed(bool on) noexcept
{
distributed_ = (parallel_ && on);
}
//- True if this is a parallel run and uses distributed roots.
bool distributed() const noexcept
{
return (parallel_ && distributed_);
}
//- Set use of distributed roots, but only if actually parallel
void distributed(bool on) noexcept
{
distributed_ = (parallel_ && on);
}
// General Control
//- Non-zero if set as 'dry-run'
int dryRun() const noexcept
{
return dryRun_;
}
//- Change 'dry-run', return old value
int dryRun(const int level) noexcept
{
int old(dryRun_);
dryRun_ = level;
return old;
}
//- Non-zero if set as 'verbose'
int verbose() const noexcept
{
return verbose_;
}
//- Change 'verbose', return old value
int verbose(const int level) noexcept
{
int old(verbose_);
verbose_ = level;
return old;
}
};