diff --git a/src/sst/core/checkpointAction.cc b/src/sst/core/checkpointAction.cc index 89b24ea79..f624f25fd 100644 --- a/src/sst/core/checkpointAction.cc +++ b/src/sst/core/checkpointAction.cc @@ -154,6 +154,7 @@ CheckpointAction::execute() void CheckpointAction::createCheckpoint(Simulation_impl* sim) { + if ( 0 == rank_.rank && 0 == rank_.thread ) { const double now = sst_get_cpu_time(); sim->getSimulationOutput().output( @@ -212,9 +213,11 @@ CheckpointAction::createCheckpoint(Simulation_impl* sim) // No need to barrier here since rank 0 thread 0 will be the first // to execute in the loop below and everything else will wait for ( uint32_t r = 0; r < num_ranks.rank; ++r ) { + if ( r == rank_.rank ) { // If this is my rank go ahead for ( uint32_t t = 0; t < num_ranks.thread; ++t ) { + // If this is my thread go ahead if ( t == rank_.thread ) { sim->checkpoint_append_registry(directory + "/" + registry_name, filename); @@ -254,6 +257,11 @@ CheckpointAction::createCheckpoint(Simulation_impl* sim) SimTime_t CheckpointAction::check(SimTime_t current_time) { +#if 0 + Simulation_impl* sim = Simulation_impl::getSimulation(); + sim->getSimulationOutput().output( + "skk:T %d: checkpointAction.cc: check()\n", rank_.thread); +#endif // The if-logic is a little weird, but it's trying to minimize the // number of branches in the normal case of no checkpoint being // initiated. This will also handle the case where both a sim and @@ -271,6 +279,11 @@ CheckpointAction::check(SimTime_t current_time) return next_sim_time_; } +bool +CheckpointAction::getCheckpoint() +{ + return generate_; +} void CheckpointAction::setCheckpoint() { @@ -331,6 +344,14 @@ initializeCheckpointInfrastructure(Config* cfg, bool rt_can_ckpt, int myRank) std::string checkpoint_dir_name = ""; if ( myRank == 0 ) { + // Verify prefix format (no '/') + const std::string prefix = cfg->checkpoint_prefix(); + size_t foundPos = prefix.find('/'); + if ( foundPos != std::string::npos ) { + throw std::invalid_argument("Invalid checkpoint prefix: " + prefix); + } + + // Create checkpoint directory path SST::Util::Filesystem& fs = Simulation_impl::getSimulation()->filesystem; checkpoint_dir_name = fs.createUniqueDirectory(cfg->checkpoint_prefix()); } diff --git a/src/sst/core/checkpointAction.h b/src/sst/core/checkpointAction.h index fcf4577f7..b0e5a9caf 100644 --- a/src/sst/core/checkpointAction.h +++ b/src/sst/core/checkpointAction.h @@ -76,6 +76,9 @@ class CheckpointAction : public Action */ void insertIntoTimeVortex(Simulation_impl* sim); + /** Get checkpoint flag */ + bool getCheckpoint(); + /** Generate a checkpoint next time check() is called */ void setCheckpoint(); diff --git a/src/sst/core/impl/interactive/cmdLineEditor.cc b/src/sst/core/impl/interactive/cmdLineEditor.cc index c3e4038d2..4d803a3ee 100644 --- a/src/sst/core/impl/interactive/cmdLineEditor.cc +++ b/src/sst/core/impl/interactive/cmdLineEditor.cc @@ -11,6 +11,8 @@ #include "sst/core/impl/interactive/cmdLineEditor.h" +#include "cmdLineEditor.h" + #include #include #include @@ -119,18 +121,52 @@ CmdLineEditor::selectMatches(const std::list& list, const std::stri newtoken = matches[0] + " "; return true; } - else if ( matches.size() > 0 ) { - // list all matching strings - writeStr("\n"); - for ( const std::string& s : matches ) { - writeStr(s); - writeStr(" "); - } - writeStr("\n"); + if ( matches.size() == 0 ) return false; + + if ( tab_state == TAB_STATE::FILL_COMMON ) { + // find and fill in the longest common string + newtoken = findLongestCommonPrefix(matches); + tab_state = TAB_STATE::LIST_COMMON; +#ifdef _KEYB_DEBUG_ + dbgFile << "tab_state <- LIST_COMMON" << std::endl; +#endif + return true; } + + // Handle TAB_STATE::LIST_COMMON) + writeStr("\n"); + for ( const std::string& s : matches ) { + writeStr(s); + writeStr(" "); + } + writeStr("\n"); + return false; } +std::string +CmdLineEditor::findLongestCommonPrefix(const std::vector& strings) +{ + if ( strings.empty() ) return ""; + const std::string& first_str = strings[0]; + int prefix_length = 0; + for ( size_t i = 0; i < first_str.length(); ++i ) { + char currentChar = first_str[i]; + bool allMatch = true; + for ( size_t j = 1; j < strings.size(); ++j ) { + if ( i >= strings[j].length() || strings[j][i] != currentChar ) { + allMatch = false; + break; + } + } + if ( allMatch ) + prefix_length++; + else + break; + } + return first_str.substr(0, prefix_length); +} + void CmdLineEditor::flush_bad_escape() { @@ -167,8 +203,8 @@ CmdLineEditor::auto_complete(std::string& cmd) else if ( tokens.size() == 1 && !hasTrailingSpace ) { // find all matching command strings starting with tokens[0] std::vector matches; - bool exact_match = selectMatches(cmdStrings, tokens[0], matches, cmd); - if ( exact_match ) { + bool fill_line = selectMatches(cmdStrings, tokens[0], matches, cmd); + if ( fill_line ) { curpos = cmd.size() + prompt.size() + 1; #ifdef _KEYB_DEBUG_ // dbgFile << "prompt&" << &prompt << "'" << prompt << "'(" << prompt.size() << ") " @@ -195,8 +231,8 @@ CmdLineEditor::auto_complete(std::string& cmd) else { std::vector matches; std::string newtoken; - bool exact_match = selectMatches(listing, tokens[tokens.size() - 1], matches, newtoken); - if ( exact_match ) { + bool fill_line = selectMatches(listing, tokens[tokens.size() - 1], matches, newtoken); + if ( fill_line ) { std::stringstream s; for ( size_t i = 0; i < tokens.size() - 1; i++ ) s << tokens[i] << " "; @@ -239,6 +275,9 @@ CmdLineEditor::getline(const std::vector& cmdHistory, std::string& writeStr(prompt_line.str()); curpos = history[index].size() + prompt.size() + 1; + // EOF + bool end_of_file = false; + // Start checking for keys char c; int bytesRead = 1; @@ -247,6 +286,15 @@ CmdLineEditor::getline(const std::vector& cmdHistory, std::string& #ifdef _KEYB_DEBUG_ dbgFile << std::hex << (int)c << std::endl; #endif + // Always reset TAB behavior if tab key not entered + if ( c != tab_char ) { + tab_state = TAB_STATE::FILL_COMMON; +#ifdef _KEYB_DEBUG_ + dbgFile << "tab_state <- FILL_COMMON" << std::endl; +#endif + } + + // Handle the key pressed if ( c == lf_char ) { // Done if line feed break; @@ -313,11 +361,16 @@ CmdLineEditor::getline(const std::vector& cmdHistory, std::string& redraw_line(history[index]); } else if ( c == ctrl_d ) { - // delete character at cursor int position = curpos - prompt.size() - 1; + if ( position == 0 && history[index].size() == 0 ) { + // if the line is empty then quit (tactcomplabs/sst-core #32) + end_of_file = true; + break; + } if ( position < 0 || position >= (int)history[index].size() ) { - continue; + continue; // Something went wrong } + // delete the next character history[index].erase(position, 1); redraw_line(history[index]); } @@ -371,6 +424,10 @@ CmdLineEditor::getline(const std::vector& cmdHistory, std::string& this->restoreTermMode(); // set the new line info - newcmd = history[index]; + if ( end_of_file ) + newcmd = "quit"; + else + newcmd = history[index]; + writeStr("\n"); } diff --git a/src/sst/core/impl/interactive/cmdLineEditor.h b/src/sst/core/impl/interactive/cmdLineEditor.h index 35a121cc5..00a7dc718 100644 --- a/src/sst/core/impl/interactive/cmdLineEditor.h +++ b/src/sst/core/impl/interactive/cmdLineEditor.h @@ -88,21 +88,26 @@ class CmdLineEditor // debug helper std::ofstream dbgFile; + // tab behaviors + enum TAB_STATE { FILL_COMMON, LIST_COMMON }; + private: termios originalTerm; std::list cmdStrings = {}; std::function& callback)> listing_callback_ = nullptr; - int curpos = -1; - int checktty(int rc); - int setRawMode(); - int restoreTermMode(); - bool read2chars(char (&seq)[3]); - void move_cursor_left(); - void move_cursor_right(int slen); - void auto_complete(std::string& cmd); - bool selectMatches(const std::list& list, const std::string& searchfor, - std::vector& matches, std::string& newcmd); + int curpos = -1; + TAB_STATE tab_state = TAB_STATE::FILL_COMMON; + int checktty(int rc); + int setRawMode(); + int restoreTermMode(); + bool read2chars(char (&seq)[3]); + void move_cursor_left(); + void move_cursor_right(int slen); + void auto_complete(std::string& cmd); + bool selectMatches(const std::list& list, const std::string& searchfor, + std::vector& matches, std::string& newcmd); + std::string findLongestCommonPrefix(const std::vector& strings); private: // yet more string helpers diff --git a/src/sst/core/impl/interactive/simpleDebug.cc b/src/sst/core/impl/interactive/simpleDebug.cc index 18d1d54a2..fb8277b0e 100644 --- a/src/sst/core/impl/interactive/simpleDebug.cc +++ b/src/sst/core/impl/interactive/simpleDebug.cc @@ -30,6 +30,15 @@ namespace SST::IMPL::Interactive { +// Static Initialization +//TODO kg is there a naming convention for static vars? +bool SimpleDebugger::autoCompleteEnable = true; +std::ofstream SimpleDebugger::loggingFile; +std::ifstream SimpleDebugger::replayFile; +std::string SimpleDebugger::loggingFilePath = "sst-console.out"; +std::string SimpleDebugger::replayFilePath = "sst-console.in"; +bool SimpleDebugger::enLogging = false; +bool SimpleDebugger::confirm_ = true; SimpleDebugger::SimpleDebugger(Params& params) : InteractiveConsole() { @@ -40,11 +49,15 @@ SimpleDebugger::SimpleDebugger(Params& params) : if ( sstReplayFilePath.size() > 0 ) injectedCommand << "replay " << sstReplayFilePath << std::endl; // Populate the command registry - cmdRegistry = { + cmdRegistry = CommandRegistry({ { "help", "?", "<[CMD]>: show this help or detailed command help", ConsoleCommandGroup::GENERAL, [this](std::vector& tokens) { return cmd_help(tokens); } }, { "verbose", "v", "[mask]: set verbosity mask or print if no mask specified", ConsoleCommandGroup::GENERAL, [this](std::vector& tokens) { return cmd_verbose(tokens); } }, + { "info", "info", "\"current\"|\"all\" print summary for current thread or all threads", + ConsoleCommandGroup::GENERAL, [this](std::vector& tokens) { return cmd_info(tokens); } }, + { "thread", "thd", "[threadID]: switch to specified thread ID", ConsoleCommandGroup::GENERAL, + [this](std::vector& tokens) { return cmd_thread(tokens); } }, { "confirm", "cfm", ": set confirmation requests on (default) or off", ConsoleCommandGroup::GENERAL, [this](std::vector& tokens) { return cmd_setConfirm(tokens); } }, { "pwd", "pwd", "print the current working directory in the object map", ConsoleCommandGroup::NAVIGATION, @@ -97,12 +110,14 @@ SimpleDebugger::SimpleDebugger(Params& params) : [this](std::vector& tokens) { return cmd_autoComplete(tokens); } }, { "clear", "clr", "reset terminal", ConsoleCommandGroup::MISC, [this](std::vector& tokens) { return cmd_clear(tokens); } }, - { "spinThread", "spin", "enter spin loop. See SimpleDebugger::cmd_spinThread", ConsoleCommandGroup::MISC, - [this](std::vector& tokens) { return cmd_spinThread(tokens); } }, - }; + { "define", "def", "define a user command sequence", ConsoleCommandGroup::MISC, + [this](std::vector& tokens) { return cmd_define(tokens); } }, + { "document", "doc", "document help for a user defined command", ConsoleCommandGroup::MISC, + [this](std::vector& tokens) { return cmd_document(tokens); } }, + }); // Detailed help from some commands. Can also add general things like 'help navigation' - cmdHelp = { + cmdRegistry.cmdHelp = { { "verbose", "[mask]: set verbosity mask or print if no mask specified\n" "\tA mask is used to select which features to enable verbosity.\n" "\tTo turn on all features set the mask to 0xffffffff\n" @@ -112,6 +127,7 @@ SimpleDebugger::SimpleDebugger(Params& params) : { "set", " : sets an object in the current scope to the provided value\n" "\tobject must be a 'fundamental type' (arithmetic or string)\n" "\t e.g. set mystring hello world" }, + { "examine", "[e][]: prints object in the current scope\n" }, { "watchpoints", "Manage watchpoints (with or without tracing)\n" "\tA can be a or a sequence of comparisons combined with a \n" @@ -123,7 +139,9 @@ SimpleDebugger::SimpleDebugger(Params& params) : "\t'watch' creates a default watchpoint that breaks into an interactive console when triggered\n" "\t'trace' creates a watchpoint with a trace buffer to trace a set of variables and trigger an \n" "\tAvailable actions include: \n" - "\t interactive, printTrace, checkpoint, set , printStatus, or shutdown" }, + "\t interactive, printTrace, checkpoint, set , printStatus, or shutdown" + "\t Note: checkpoint action must be enabled at startup via the '--checkpoint-enable' command line " + "option\n" }, { "watch", ": adds watchpoint to the watchlist; breaks into interactive console when triggered\n" "\tExample: watch var1 > 90 && var2 < 100 || var3 changed" }, { "trace", @@ -164,19 +182,25 @@ SimpleDebugger::SimpleDebugger(Params& params) : "\ttab: auto-completion\n" "\tctrl-a: move cursor to beginning of line\n" "\tctrl-b: move cursor to the left\n" - "\tctrl-d: delete character at cursor\n" + "\tctrl-d: delete character at cursor or quit debugger\n" "\tctrl-e: move cursor to end of line\n" "\tctrl-f: move cursor to the right\n" }, + { "define", ": enter a command sequence for a user defined command.\n" + "Terminate the sequence by typing \"end\"\n" }, + { "document", ": provide help documentation for a user defined command.\n" + "The first line will be summarized in the short help text.\n" + "Remaining lines will be provided in detailed help\n" + "Terminate the sequence by typing \"end\"\n" }, }; // Command autofill strings std::list cmdStrings; - for ( const ConsoleCommand& c : cmdRegistry ) { + for ( const ConsoleCommand& c : cmdRegistry.getRegistryVector() ) { cmdStrings.emplace_back(c.str_long()); cmdStrings.emplace_back(c.str_short()); } cmdStrings.sort(); - cmdLineEditor.set_cmd_strings(cmdStrings); // could also realize as callback to generalize + cmdLineEditor.set_cmd_strings(cmdStrings); // Callback for directory listing strings cmdLineEditor.set_listing_callback([this](std::list& vec) { get_listing_strings(vec); }); @@ -189,9 +213,46 @@ SimpleDebugger::~SimpleDebugger() } void +SimpleDebugger::summary() +{ +#if 0 + RankInfo info = getRank(); + RankInfo nRanks = getNumRanks(); + std::count << "\n(Rank:" << info.rank << " / " << nRanks.rank + << " Thread:" << info.thread << "/" << nRanks.thread + << ")\n"; + std::cout << " -- Trigger Status\n"; +#endif + + std::cout << " -- Component Summary\n"; +#if 0 + std::vector tokens; + if (nullptr == obj_) { + obj_ = getComponentObjectMap(); + } + cmd_ls(tokens); +#else + SST::Core::Serialization::ObjectMap* baseObj = getComponentObjectMap(); + auto& vars = baseObj->getVariables(); + for ( auto& x : vars ) { + if ( x.second->isFundamental() ) { + std::cout << x.first << " = " << x.second->get() << " (" << x.second->getType() << ")" << std::endl; + } + else { + std::cout << x.first.c_str() << "/ (" << x.second->getType() << ")\n"; + } + } + std::cout << std::endl; +#endif +} + +int SimpleDebugger::execute(const std::string& msg) { - printf("Entering interactive mode at time %" PRI_SIMTIME " \n", getCurrentSimCycle()); + RankInfo info = getRank(); + RankInfo nRanks = getNumRanks(); + printf("\n---- Rank%d:Thread%d: Entering interactive mode at time %" PRI_SIMTIME " \n", info.rank, info.thread, + getCurrentSimCycle()); printf("%s\n", msg.c_str()); // Create a new ObjectMap @@ -200,20 +261,40 @@ SimpleDebugger::execute(const std::string& msg) // Descend into the name_stack cd_name_stack(); - done = false; + done = false; + retState = DONE; + + // Select the input source and next command line std::string line; while ( !done ) { - try { + // User input prompt (except during user command) + if ( eStack.size() == 0 ) std::cout << "> " << std::flush; + + // Logging disable has edge cases for stack push/pop + bool squashLogging = false; + // User input prompt - std::cout << "> " << std::flush; + // std::cout << "R" << info.rank << ":T" << info.thread << "> " << std::flush; if ( !injectedCommand.str().empty() ) { - // Injected command stream (currently just one command) + // Injected commands allow sst command line options to cause actions (currently only replay) line = injectedCommand.str(); injectedCommand.str(""); std::cout << line << std::endl; } + else if ( eStack.size() > 0 ) { + // Do no log internals of user defined command + squashLogging = true; + // Execute next instruction in a user defined command + line = eState.next(); + if ( eState.ret() ) { + eState = eStack.top(); + eStack.pop(); + // back to normal command entry + if ( eStack.size() == 0 ) cmdHistoryBuf.enable(true); + } + } else if ( replayFile.is_open() ) { // Replay commands from file if ( std::getline(replayFile, line) ) { @@ -237,10 +318,11 @@ SimpleDebugger::execute(const std::string& msg) std::getline(std::cin, line); } + // We have a constructed command line. Ship it dispatch_cmd(line); - // Command Logging - if ( enLogging ) loggingFile << line.c_str() << std::endl; + // Log commands if enabled and not executing a user defined command + if ( enLogging && !squashLogging ) loggingFile << line.c_str() << std::endl; // This prevents logging the 'logging' command if ( loggingFile.is_open() ) enLogging = true; } @@ -248,9 +330,9 @@ SimpleDebugger::execute(const std::string& msg) std::cout << "Parsing error. Ignoring " << line << std::endl; } } - // Save the position on the name_stack, and clear obj_ save_name_stack(); + return retState; } // Save the name stack of the current position, and clear obj_ @@ -334,19 +416,64 @@ SimpleDebugger::dispatch_cmd(std::string& cmd) } } - // Search for the requested command and execute it if found. - for ( auto consoleCommand : cmdRegistry ) { - if ( consoleCommand.match(tokens[0]) ) { - bool succeed = consoleCommand.exec(tokens); + // Check for 'end' string to terminate special line entry modes + if ( (line_entry_mode != LINE_ENTRY_MODE::NORMAL) && (cmd == "end") ) { + if ( line_entry_mode == LINE_ENTRY_MODE::DEFINE ) + cmdRegistry.commitUserCommand(); + else if ( line_entry_mode == LINE_ENTRY_MODE::DOCUMENT ) + cmdRegistry.commitDocCommand(); + else { + std::cout << "Error: unknown line entry mode" << std::endl; + assert(false); + } + + line_entry_mode = LINE_ENTRY_MODE::NORMAL; + std::cout << "[ returning to normal line entry mode ]" << std::endl; + return true; + } + + // Do the right thing based on the entry mode + switch ( line_entry_mode ) { + case LINE_ENTRY_MODE::NORMAL: + { + // normal execution + auto consoleCommand = cmdRegistry.seek(tokens[0], CommandRegistry::SEARCH_TYPE::BUILTIN); + if ( consoleCommand.second ) { + bool succeed = consoleCommand.first.exec(tokens); cmdHistoryBuf.append(cmd); return succeed; } - } + // user defined entry + consoleCommand = cmdRegistry.seek(tokens[0], CommandRegistry::SEARCH_TYPE::USER); + if ( consoleCommand.second ) { + cmdHistoryBuf.append(cmd); + // Do nothing if user command is empty + if ( cmdRegistry.commandIsEmpty(tokens[0]) ) return true; + // save current context + eStack.push(eState); + // new context for user call + eState = { consoleCommand.first, tokens, cmdRegistry.userCommandInsts(tokens[0]) }; + // History capture disabled when stack size > 0 + cmdHistoryBuf.enable(false); + return true; + } - // No matching command found - std::cout << "Unknown command: " << tokens[0].c_str() << std::endl; - cmdHistoryBuf.append(cmd); // want garbled command so we can fix using command line editor - return false; + // No matching command found but keep in history so we can fix it + std::cout << "Unknown command: " << tokens[0].c_str() << std::endl; + cmdHistoryBuf.append(cmd); + return false; + } + case LINE_ENTRY_MODE::DEFINE: + // entering a user defined command + cmdRegistry.appendUserCommand(tokens[0], cmd); + return true; + case LINE_ENTRY_MODE::DOCUMENT: + cmdRegistry.appendDocCommand(cmd); + return true; + default: + std::cout << "INTERNAL ERROR: unhandled line entry mode" << std::endl; + return false; + } // switch (line_entry_mode) } // @@ -379,14 +506,24 @@ SimpleDebugger::cmd_help(std::vector& tokens) // First check for specific command help if ( tokens.size() == 1 ) { for ( const auto& g : GroupText ) { - std::cout << "--- " << g.second << " ---" << std::endl; - for ( const auto& c : cmdRegistry ) { - if ( g.first == c.group() ) std::cout << c << std::endl; + if ( g.first != ConsoleCommandGroup::USER ) { + std::cout << "--- " << g.second << " ---" << std::endl; + for ( const auto& c : cmdRegistry.getRegistryVector() ) { + if ( g.first == c.group() ) std::cout << c << std::endl; + } + } + else if ( cmdRegistry.getUserRegistryVector().size() > 0 ) { + std::cout << "--- " << g.second << " ---" << std::endl; + for ( const auto& c : cmdRegistry.getUserRegistryVector() ) { + if ( g.first == c.group() ) { + std::cout << c << std::endl; + } + } } } - std::cout << "\nMore detailed help also available for:\n"; + std::cout << "\nMore detailed help available for:\n"; std::stringstream s; - for ( const auto& pair : cmdHelp ) { + for ( const auto& pair : cmdRegistry.cmdHelp ) { if ( (s.str().length() + pair.first.length() > 39) ) { std::cout << "\t" << s.str() << std::endl; s.str(""); @@ -401,11 +538,11 @@ SimpleDebugger::cmd_help(std::vector& tokens) if ( tokens.size() > 1 ) { std::string c = tokens[1]; - if ( cmdHelp.find(c) != cmdHelp.end() ) { - std::cout << c << " " << cmdHelp.at(c) << std::endl; + if ( cmdRegistry.cmdHelp.find(c) != cmdRegistry.cmdHelp.end() ) { + std::cout << c << " " << cmdRegistry.cmdHelp.at(c) << std::endl; } else { - for ( auto& creg : cmdRegistry ) { + for ( auto& creg : cmdRegistry.getRegistryVector() ) { if ( creg.match(c) ) std::cout << creg << std::endl; } } @@ -439,6 +576,81 @@ SimpleDebugger::cmd_verbose(std::vector& tokens) return true; } +bool +SimpleDebugger::cmd_info(std::vector& UNUSED(tokens)) +{ + + if ( tokens.size() != 2 ) { + printf("Invalid format for info command (info \"current\"|\"all\")\n"); + return false; + } + + RankInfo info = getRank(); + RankInfo nRanks = getNumRanks(); + if ( tokens[1] == "current" ) { + std::cout << "Rank " << info.rank << "/" << nRanks.rank << ", Thread " << info.thread << "/" << nRanks.thread + << " (Process " << getppid() << ")" << std::endl; + } + else if ( tokens[1] == "all" ) { + if ( nRanks.rank == 1 && nRanks.thread == 1 ) { + std::cout << "Rank " << info.rank << "/" << nRanks.rank << ", Thread " << info.thread << "/" + << nRanks.thread << " (Process " << getppid() << ")" << std::endl; + } + else { + // Return to syncmanager to print summary for all threads + retState = SUMMARY; // summary info + done = true; + } + } + else { + printf("Invalid argument for info command: %s (info \"current\"|\"all\")\n", tokens[1].c_str()); + return false; + } + return true; +} + +// thread : switches to new thread +bool +SimpleDebugger::cmd_thread(std::vector& tokens) +{ + + if ( tokens.size() != 2 ) { + printf("Invalid format for thread command (thread )\n"); + return false; + } + + RankInfo info = getRank(); + RankInfo nRanks = getNumRanks(); + int threadID; + + // Get threadID + try { + threadID = std::stoi(tokens[1]); + } + catch ( const std::invalid_argument& e ) { + std::cout << "Invalid argument for threadID: " << tokens[1] << std::endl; + return false; + } + catch ( const std::out_of_range& e ) { + std::cout << "Out of range for threadID: " << tokens[1] << std::endl; + return false; + } + + // Check if valid threadID + if ( threadID < 0 || threadID >= static_cast(nRanks.thread) ) { + printf("ThreadID %d out of range (0:%d)\n", threadID, nRanks.thread - 1); + return false; + } + + // If not current thread, set retState and done flag + if ( threadID != static_cast(info.thread) ) { + retState = threadID; + done = true; + } + return true; +} + + // pwd: print current working directory bool SimpleDebugger::cmd_pwd(std::vector& UNUSED(tokens)) @@ -492,10 +704,18 @@ SimpleDebugger::get_listing_strings(std::list& list) bool SimpleDebugger::cmd_cd(std::vector& tokens) { +#if 1 if ( tokens.size() != 2 ) { printf("Invalid format for cd command (cd )\n"); return false; } +#else + // skk This works but doesn't delete/deactivate like objmap selectParent + if ( tokens.size() == 1 ) { + obj_ = getComponentObjectMap(); + return; + } +#endif // Allow for trailing '/' std::string selection = tokens[1]; @@ -517,7 +737,7 @@ SimpleDebugger::cmd_cd(std::vector& tokens) } bool loop_detected = false; - SST::Core::Serialization::ObjectMap* new_obj = obj_->selectVariable(selection, loop_detected); + SST::Core::Serialization::ObjectMap* new_obj = obj_->selectVariable(selection, loop_detected, confirm_); if ( !new_obj || (new_obj == obj_) ) { printf("Unknown object in cd command: %s\n", selection.c_str()); return false; @@ -559,9 +779,9 @@ SimpleDebugger::cmd_print(std::vector& tokens) } // See if have a -r or not - int recurse = 0; + int recurse = 4; // default -r depth std::string tok = tokens[1]; - if ( tok.size() >= 2 && tok[0] == '-' && tok[1] == 'r' ) { + if ( (tok.size() >= 2) && (tok[0] == '-') && (tok[1] == 'r') ) { // Got a -r std::string num = tok.substr(2); if ( num.size() != 0 ) { @@ -574,9 +794,17 @@ SimpleDebugger::cmd_print(std::vector& tokens) } } else { - recurse = 4; // default -r depth + std::string num = tok.substr(2); + if ( num.size() != 0 ) { + try { + recurse = SST::Core::from_string(num); + } + catch ( std::invalid_argument& e ) { + printf("Invalid number format specified with -r: %s\n", tok.c_str()); + return false; + } + } } - var_index = 2; } @@ -593,7 +821,6 @@ SimpleDebugger::cmd_print(std::vector& tokens) bool found; std::string listing = obj_->listVariable(tokens[var_index], found, recurse); - if ( !found ) { printf("Unknown object in print command: %s\n", tokens[1].c_str()); return false; @@ -702,6 +929,22 @@ SimpleDebugger::cmd_run(std::vector& tokens) return false; } } + else if ( tokens.size() == 3 ) { + std::string time = tokens[1] + tokens[2]; + try { + TimeConverter* tc = getTimeConverter(time); + std::string msg = format_string("Running clock %" PRI_SIMTIME " sim cycles", tc->getFactor()); + schedule_interactive(tc->getFactor(), msg); + } + catch ( std::exception& e ) { + printf("Unknown time in call to run: %s\n", time.c_str()); + return false; + } + } + else if ( tokens.size() != 1 ) { + printf("Too many arguments for 'run