Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extended help #977

Merged
merged 1 commit into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/sst/core/bootsst.cc
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ main(int argc, char* argv[])
// Create a ConfigShred object. This object won't print any error
// messages about unknown command line options, that will be
// deferred to the actual sstsim.x executable.
SST::ConfigShared cfg(true, true, true, true, true);
SST::ConfigShared cfg(true, true, true, true);

// Make a copy of the argv array (shallow)
char* argv_copy[argc + 1];
Expand Down
2 changes: 1 addition & 1 deletion src/sst/core/bootsstinfo.cc
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ main(int argc, char* argv[])
// for the wrapper. We will suppress output so that it won't
// report unknown options which are only parsed by the actual
// sst-info executable.
SST::ConfigShared cfg(true, true, true, true, true);
SST::ConfigShared cfg(true, true, true, true);

// Make a copy of the argv array (shallow)
char* argv_copy[argc + 1];
Expand Down
66 changes: 58 additions & 8 deletions src/sst/core/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,14 @@ class ConfigHelper
{
public:
// Print usage
static int printHelp(Config* cfg, const std::string& UNUSED(arg)) { return cfg->printUsage(); }
static int printUsage(Config* cfg, const std::string& UNUSED(arg)) { return cfg->printUsage(); }

// Print usage
static int printHelp(Config* cfg, const std::string& arg)
{
if ( arg != "" ) return cfg->printExtHelp(arg);
return cfg->printUsage();
}

// Prints the SST version
static int printVersion(Config* UNUSED(cfg), const std::string& UNUSED(arg))
Expand Down Expand Up @@ -355,6 +362,39 @@ class ConfigHelper
return 0;
}

static std::string getProfilingExtHelp()
{
std::string msg = "Profiling Points [EXPERIMENTAL]:\n\n";
msg.append(
"NOTE: Profiling points are still in development and syntax for enabling profiling tools, as well as "
"available profiling points is subject to change. However, it is intended that profiling points "
"will continue to be supported into the future.\n\n");
msg.append(" Profiling points are points in the code where a profiling tool can be instantiated. The "
"profiling tool allows you to collect various data about code segments. There are currently three "
"profiling points in SST core:\n");
msg.append(" - clock: profiles calls to user registered clock handlers\n");
msg.append(" - event: profiles calls to user registered event handlers set on Links\n");
msg.append(" - sync: profiles calls into the SyncManager (only valid for parallel simulations)\n");
msg.append("\n");
msg.append(" The format for enabling profile point is a semicolon separated list where each item specifies "
"details for a given profiling tool using the following format:\n");
msg.append(" name:type(params)[point]\n");
msg.append(" name: name of tool to be shown in output\n");
msg.append(" type: type of profiling tool in ELI format (lib.type)\n");
msg.append(" params: optional parameters to pass to profiling tool, format is key=value,key=value...\n");
msg.append(" point: profiling point to load the tool into\n");
msg.append("\n");
msg.append("Profiling tools can all be enabled in a single instance of --enable-profiling, or you can use "
"multiple instances of --enable-profiling can be used to enable more than one profiling tool. It "
"is also possible to attach more than one profiling tool to a given profiling point.\n");
msg.append("\n");
msg.append("Examples:\n");
msg.append(
" --enable-profiling=\"events:sst.profile.handler.event.time.high_resolution(level=component)[event]\"\n");
msg.append(" --enable-profiling=\"clocks:sst.profile.handler.clock.count(level=subcomponent)[clock]\"\n");
msg.append(" --enable-profiling=sync:sst.profile.sync.time.steady[sync]\n");
return msg;
}

// Advanced options - debug

Expand Down Expand Up @@ -464,8 +504,13 @@ Config::print()
std::cout << "no_env_config = " << no_env_config_ << std::endl;
}

static std::vector<AnnotationInfo> annotations = {
{ 'S',
"Options annotated with 'S' can be set in the SDL file (input configuration file)\n - Note: Options set on the "
"command line take precedence over options set in the SDL file\n" }
};

Config::Config(uint32_t num_ranks, bool first_rank) : ConfigShared(!first_rank, false)
Config::Config(uint32_t num_ranks, bool first_rank) : ConfigShared(!first_rank, annotations)
{
// Basic Options
first_rank_ = first_rank;
Expand Down Expand Up @@ -567,7 +612,10 @@ Config::insertOptions()
using namespace std::placeholders;
/* Informational options */
DEF_SECTION_HEADING("Informational Options");
DEF_FLAG("help", 'h', "Print help message", std::bind(&ConfigHelper::printHelp, this, _1));
DEF_FLAG("usage", 'h', "Print usage information.", std::bind(&ConfigHelper::printUsage, this, _1));
DEF_ARG(
"help", 0, "option", "Print extended help information for requested option.",
std::bind(&ConfigHelper::printHelp, this, _1), false);
DEF_FLAG("version", 'V', "Print SST Release Version", std::bind(&ConfigHelper::printVersion, this, _1));

/* Basic Options */
Expand Down Expand Up @@ -679,11 +727,11 @@ Config::insertOptions()

/* Advanced Features - Profiling */
DEF_SECTION_HEADING("Advanced Options - Profiling (EXPERIMENTAL)");
DEF_ARG(
DEF_ARG_EH(
"enable-profiling", 0, "POINTS",
"Enables default profiling for the specified points. Argument is a semicolon separated list specifying the "
"points to enable.",
std::bind(&ConfigHelper::enableProfiling, this, _1), true);
std::bind(&ConfigHelper::enableProfiling, this, _1), std::bind(&ConfigHelper::getProfilingExtHelp), true);
DEF_ARG(
"profiling-output", 0, "FILE", "Set output location for profiling data [stdout (default) or a filename]",
std::bind(&ConfigHelper::setProfilingOutput, this, _1), true);
Expand Down Expand Up @@ -721,8 +769,6 @@ Config::getUsagePrelude()
{
std::string prelude = "Usage: sst [options] config-file\n";
prelude.append(" Arguments to options contained in [] are optional\n");
prelude.append(" Options available to be set in the sdl file (input configuration file) are denoted by (S)\n");
prelude.append(" - Options set on the command line take precedence over options set in the SDL file\n");
prelude.append(" Notes on flag options (options that take an optional BOOL value):\n");
prelude.append(" - BOOL values can be expressed as true/false, yes/no, on/off or 1/0\n");
prelude.append(" - Program default for flags is false\n");
Expand Down Expand Up @@ -782,7 +828,11 @@ Config::checkArgsAfterParsing()
bool
Config::setOptionFromModel(const string& entryName, const string& value)
{
return setOptionExternal(entryName, value);
// Check to make sure option is settable in the SDL file
if ( getAnnotation(entryName, 'S') ) { return setOptionExternal(entryName, value); }
fprintf(stderr, "ERROR: Option \"%s\" is not available to be set in the SDL file\n", entryName.c_str());
exit(-1);
return false;
}


Expand Down
2 changes: 1 addition & 1 deletion src/sst/core/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ class Config : public ConfigShared, public SST::Core::Serialization::serializabl
Default constructor used for serialization. At this point,
first_rank_ is no longer needed, so just initialize to false.
*/
Config() : ConfigShared(true, true), first_rank_(false) {}
Config() : ConfigShared(true, {}), first_rank_(false) {}

//// Functions for use in main

Expand Down
118 changes: 95 additions & 23 deletions src/sst/core/configBase.cc
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,11 @@ ConfigBase::parseBoolean(const std::string& arg, bool& success, const std::strin

void
ConfigBase::addOption(
struct option opt, const char* argname, const char* desc, std::function<int(const char* arg)> callback, bool header,
bool sdl_avail)
struct option opt, const char* argname, const char* desc, std::function<int(const char* arg)> callback,
std::vector<bool> annotations, std::function<std::string(void)> ext_help)
{
// Put this into the options vector
options.emplace_back(opt, argname, desc, callback, header, sdl_avail, false);
options.emplace_back(opt, argname, desc, callback, false, annotations, ext_help, false);

LongOption& new_option = options.back();

Expand All @@ -74,6 +74,9 @@ ConfigBase::addOption(
// Increment the number of options
num_options++;

// See if there is extended help
if ( ext_help ) has_extended_help_ = true;

// See if this is the longest option
size_t size = 0;
if ( new_option.opt.name != nullptr ) { size = strlen(new_option.opt.name); }
Expand All @@ -95,6 +98,18 @@ ConfigBase::addOption(
short_options_string.append("::");
}
}

// Handle any extra help functions
if ( ext_help ) { extra_help_map[opt.name] = ext_help; }
}

void
ConfigBase::addHeading(const char* desc)
{
struct option opt = { "", optional_argument, 0, 0 };
std::vector<bool> vec;
options.emplace_back(
opt, "", desc, std::function<int(const char* arg)>(), true, vec, std::function<std::string(void)>(), false);
}

std::string
Expand All @@ -121,6 +136,7 @@ ConfigBase::addPositionalCallback(std::function<int(int num, const char* arg)> c
positional_args = callback;
}


int
ConfigBase::printUsage()
{
Expand All @@ -138,14 +154,21 @@ ConfigBase::printUsage()
if ( errno == E_OK ) MAX_WIDTH = x;
}

const char* sdl_indicator = suppress_sdl_ ? "" : "(S)";
const uint32_t sdl_start = longest_option + 6;
const uint32_t desc_start = sdl_start + strlen(sdl_indicator) + 1;
const uint32_t desc_width = MAX_WIDTH - desc_start;
const uint32_t ann_start = longest_option + 6;
const uint32_t desc_start = ann_start + annotations_.size() + 2;
const uint32_t desc_width = MAX_WIDTH - desc_start;

/* Print usage */
/* Print usage prelude */
fprintf(stderr, "%s", getUsagePrelude().c_str());

/* Print info about annotations */
if ( has_extended_help_ ) { fprintf(stderr, "\nOptions annotated with 'H' have extended help available\n"); }
for ( size_t i = 0; i < annotations_.size(); ++i ) {
fprintf(stderr, "%s\n", annotations_[i].help.c_str());
}

// Print info about annotations

for ( auto& option : options ) {
if ( option.header ) {
// Just a section heading
Expand All @@ -164,17 +187,26 @@ ConfigBase::printUsage()
if ( option.opt.has_arg != no_argument ) { npos += fprintf(stderr, "=%s", option.argname.c_str()); }
// If we have already gone beyond the description start,
// description starts on new line
if ( npos >= sdl_start ) {
if ( npos >= ann_start ) {
fprintf(stderr, "\n");
npos = 0;
}

// If this can be set in the sdl file, start description with
// "(S)"
while ( npos < sdl_start ) {
// Get to the start of the annotations
while ( npos < ann_start ) {
npos += fprintf(stderr, " ");
}
if ( option.sdl_avail ) { npos += fprintf(stderr, "%s", sdl_indicator); }

// Print the annotations
// First check for extended help
npos += fprintf(stderr, "%c", option.ext_help ? 'H' : ' ');

// Now do the rest of the annotations
for ( size_t i = 0; i < annotations_.size(); ++i ) {
char c = ' ';
if ( option.annotations.size() >= (i + 1) && option.annotations[i] ) c = annotations_[i].annotation;
npos += fprintf(stderr, "%c", c);
}

const char* text = option.desc.c_str();
while ( text != nullptr && *text != '\0' ) {
Expand Down Expand Up @@ -209,6 +241,25 @@ ConfigBase::printUsage()
return 1; /* Should not continue */
}


int
ConfigBase::printExtHelp(const std::string& option)
{
if ( suppress_print_ ) return 1;

if ( extra_help_map.find(option) == extra_help_map.end() ) {
fprintf(stderr, "No additional help found for option \"%s\"\n", option.c_str());
}
else {
std::function<std::string(void)>& func = extra_help_map[option];
std::string help = func();
fprintf(stderr, "%s\n", help.c_str());
}

return 1; /* Should not continue */
}


int
ConfigBase::parseCmdLine(int argc, char* argv[], bool ignore_unknown)
{
Expand Down Expand Up @@ -348,21 +399,42 @@ ConfigBase::setOptionExternal(const string& entryName, const string& value)
// NOTE: print outs in this function will not be suppressed
for ( auto& option : options ) {
if ( !entryName.compare(option.opt.name) ) {
if ( option.sdl_avail ) {
// If this was set on the command line, skip it
if ( option.set_cmdline ) return false;
return option.callback(value.c_str());
}
else {
fprintf(stderr, "ERROR: Option \"%s\" is not available to be set in the SDL file\n", entryName.c_str());
exit(-1);
return false;
}
if ( option.set_cmdline ) return false;
return option.callback(value.c_str());
}
}
fprintf(stderr, "ERROR: Unknown configuration entry \"%s\"\n", entryName.c_str());
exit(-1);
return false;
}

bool
ConfigBase::getAnnotation(const std::string& entryName, char annotation)
{
// Need to look for the index of the annotation
size_t index = std::numeric_limits<size_t>::max();
for ( size_t i = 0; i < annotations_.size(); ++i ) {
if ( annotations_[i].annotation == annotation ) { index = i; }
}

if ( index == std::numeric_limits<size_t>::max() ) {
fprintf(stderr, "ERROR: Searching for unknown annotation: '%c'\n", annotation);
exit(-1);
}

// NOTE: print outs in this function will not be suppressed
for ( auto& option : options ) {
if ( !entryName.compare(option.opt.name) ) {
// Check for the annotation. If the index is not in the
// vector, we assume false
if ( option.annotations.size() <= index ) return false;
return option.annotations[index];
}
}

fprintf(stderr, "ERROR: Unknown configuration entry \"%s\"\n", entryName.c_str());
exit(-1);
return false;
}

} // namespace SST
Loading
Loading