Skip to content

Commit 31535b6

Browse files
committed
Interactive Console Updates
* Support for single-rank, multithreaded interactive debug console. Breaks into interactive console is at a sync point and is managed by the syncManager. It breaks into the interactive console when any thread has triggered the interactive console and starts in thread 0 initially. The user can navigate the object map, set watchpoints, etc. for components within the thread and switch between threads to access other components. * Support for user-defined commands in the interactive debug console which are a named sequence of commands and can be nested. * Updates to the parsing of --checkpoint-prefix and creation of the checkpoint directory. Ensure that the signal flags are handled before the checkpoint directory is created and fails immediately if the PREFIX is not valid.
1 parent 97193f5 commit 31535b6

File tree

16 files changed

+1014
-219
lines changed

16 files changed

+1014
-219
lines changed

src/sst/core/checkpointAction.cc

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,14 @@ initializeCheckpointInfrastructure(Config* cfg, bool rt_can_ckpt, int myRank)
331331
std::string checkpoint_dir_name = "";
332332

333333
if ( myRank == 0 ) {
334+
// Verify prefix format (no '/')
335+
const std::string prefix = cfg->checkpoint_prefix();
336+
size_t foundPos = prefix.find('/');
337+
if ( foundPos != std::string::npos ) {
338+
throw std::invalid_argument("Invalid checkpoint prefix: " + prefix);
339+
}
340+
341+
// Create checkpoint directory path
334342
SST::Util::Filesystem& fs = Simulation_impl::getSimulation()->filesystem;
335343
checkpoint_dir_name = fs.createUniqueDirectory(cfg->checkpoint_prefix());
336344
}

src/sst/core/impl/interactive/simpleDebug.cc

Lines changed: 496 additions & 49 deletions
Large diffs are not rendered by default.

src/sst/core/impl/interactive/simpleDebug.h

Lines changed: 144 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232

3333
namespace SST::IMPL::Interactive {
3434

35-
enum class ConsoleCommandGroup { GENERAL, NAVIGATION, STATE, WATCH, SIMULATION, LOGGING, MISC };
35+
enum class ConsoleCommandGroup { GENERAL, NAVIGATION, STATE, WATCH, SIMULATION, LOGGING, MISC, USER };
3636

3737
const std::map<ConsoleCommandGroup, std::string> GroupText {
3838
{ ConsoleCommandGroup::GENERAL, "General" },
@@ -42,16 +42,26 @@ const std::map<ConsoleCommandGroup, std::string> GroupText {
4242
{ ConsoleCommandGroup::SIMULATION, "Simulation" },
4343
{ ConsoleCommandGroup::LOGGING, "Logging" },
4444
{ ConsoleCommandGroup::MISC, "Misc" },
45+
{ ConsoleCommandGroup::USER, "User Defined" },
4546
};
4647

48+
// Each bit of mask enables verbosity for different debug features.
49+
// This is primarily for developers.
4750
enum class VERBOSITY_MASK : uint32_t {
4851
WATCHPOINTS = 0b0001'0000 // 0x10
4952
};
5053

54+
enum class LINE_ENTRY_MODE : int {
55+
NORMAL, // line is executed as a command
56+
DEFINE, // line is captured in user defined command sequence
57+
DOCUMENT, // documenting a user defined command
58+
};
59+
5160
// Encapsulate a console command.
5261
class ConsoleCommand
5362
{
5463
public:
64+
// Constructor for built-in commands has callback
5565
ConsoleCommand(std::string str_long, std::string str_short, std::string str_help, ConsoleCommandGroup group,
5666
std::function<void(std::vector<std::string>& tokens)> func) :
5767
str_long_(str_long),
@@ -60,17 +70,28 @@ class ConsoleCommand
6070
group_(group),
6171
func_(func)
6272
{}
63-
const std::string& str_long() const { return str_long_; }
64-
const std::string& str_short() const { return str_short_; }
65-
const std::string& str_help() const { return str_help_; }
73+
// Constructor for user-defined commands
74+
ConsoleCommand(std::string str_long) :
75+
str_long_(str_long),
76+
str_short_(str_long),
77+
str_help_("user defined command"),
78+
group_(ConsoleCommandGroup::USER)
79+
{}
80+
ConsoleCommand() {}; // default constructor
81+
const std::string& str_long() const { return str_long_; }
82+
const std::string& str_short() const { return str_short_; }
83+
const std::string& str_help() const { return str_help_; }
84+
void setUserHelp(std::string& help) { str_help_ = help; }
85+
86+
// Command Execution
87+
void exec(std::vector<std::string>& tokens) { return func_(tokens); }
88+
6689
const ConsoleCommandGroup& group() const { return group_; }
67-
void exec(std::vector<std::string>& tokens) { return func_(tokens); }
6890
bool match(const std::string& token)
6991
{
7092
std::string lctoken = toLower(token);
7193
if ( lctoken.size() == str_long_.size() && lctoken == toLower(str_long_) ) return true;
7294
if ( lctoken.size() == str_short_.size() && lctoken == toLower(str_short_) ) return true;
73-
7495
return false;
7596
}
7697
friend std::ostream& operator<<(std::ostream& os, const ConsoleCommand c)
@@ -84,13 +105,14 @@ class ConsoleCommand
84105
std::string str_short_;
85106
std::string str_help_;
86107
ConsoleCommandGroup group_;
87-
std::function<void(std::vector<std::string>& tokens)> func_;
108+
std::function<void(std::vector<std::string>& tokens)> func_ = {};
88109
std::string toLower(std::string s)
89110
{
90111
std::transform(s.begin(), s.end(), s.begin(), ::tolower);
91112
return s;
92113
}
93-
};
114+
115+
}; // class ConsoleCommand
94116

95117
class CommandHistoryBuffer
96118
{
@@ -102,8 +124,10 @@ class CommandHistoryBuffer
102124
std::vector<std::string>& getBuffer();
103125
enum BANG_RC { INVALID, ECHO_ONLY, EXEC, NOP };
104126
BANG_RC bang(const std::string& token, std::string& newcmd);
127+
void enable(bool en) { en_ = en; }
105128

106129
private:
130+
bool en_ = true;
107131
int cur_ = 0;
108132
int nxt_ = 0;
109133
int sz_ = 0;
@@ -117,6 +141,94 @@ class CommandHistoryBuffer
117141
bool searchAny(const std::string& s, std::string& newcmd);
118142
};
119143

144+
class CommandRegistry
145+
{
146+
147+
public:
148+
// Construction
149+
CommandRegistry() {}
150+
CommandRegistry(const std::vector<ConsoleCommand> in) :
151+
registry(in)
152+
{}
153+
// Access
154+
std::vector<ConsoleCommand>& getRegistryVector() { return registry; }
155+
std::vector<ConsoleCommand>& getUserRegistryVector() { return user_registry; }
156+
enum SEARCH_TYPE { ALL, BUILTIN, USER };
157+
std::pair<ConsoleCommand, bool> const seek(std::string token, SEARCH_TYPE search_type);
158+
// User defined command entry
159+
bool beginUserCommand(std::string name);
160+
void appendUserCommand(std::string token0, std::string line);
161+
void commitUserCommand();
162+
std::vector<std::string>* userCommandInsts(std::string key)
163+
{
164+
if ( user_defined_commands.find(key) == user_defined_commands.end() ) return nullptr;
165+
return &user_defined_commands[key];
166+
}
167+
// User defined command help doc entry
168+
bool beginDocCommand(std::string name);
169+
void appendDocCommand(std::string line);
170+
void commitDocCommand();
171+
bool commandIsEmpty(const std::string key)
172+
{
173+
if ( user_defined_commands.find(key) == user_defined_commands.end() ) return true;
174+
if ( user_defined_commands[key].size() == 0 ) return true;
175+
return false;
176+
};
177+
178+
// User defined command help from vector
179+
void addHelp(std::string key, std::vector<std::string>& vec);
180+
// Detailed Command Help (public for now)
181+
std::map<std::string, std::string> cmdHelp;
182+
183+
private:
184+
// built-in commands
185+
std::vector<ConsoleCommand> registry = {};
186+
// user defined commands
187+
std::vector<ConsoleCommand> user_registry = {};
188+
std::map<std::string, std::vector<std::string>> user_defined_commands = {};
189+
std::string user_command_wip = "";
190+
std::vector<std::string> user_doc_wip = {};
191+
192+
// Last searched command with valid indicator
193+
std::pair<ConsoleCommand, bool> last_seek_command = {};
194+
}; // class CommandRegistry
195+
196+
// Support for nesting user defined commands
197+
class ExecState
198+
{
199+
public:
200+
// Constructor for entering a new user command
201+
ExecState(ConsoleCommand cmd, std::vector<std::string> tokens, std::vector<std::string>* insts) :
202+
cmd_(cmd),
203+
tokens_(tokens),
204+
insts_(insts),
205+
index_(0),
206+
user_(true)
207+
{
208+
assert(insts_->size() > 0);
209+
};
210+
ExecState() {};
211+
bool ret() { return ret_; }
212+
// Advance state and return the next user instruction
213+
std::string next()
214+
{
215+
assert(user_);
216+
assert(!ret_);
217+
assert(insts_);
218+
assert(index_ < insts_->size());
219+
ret_ = (index_ + 1) == insts_->size();
220+
return insts_->at(index_++);
221+
}
222+
223+
private:
224+
ConsoleCommand cmd_ = {}; // user command in progress
225+
std::vector<std::string> tokens_ = {}; // command args
226+
std::vector<std::string>* insts_ = nullptr; // command sequence
227+
size_t index_ = 0; // command pointer
228+
bool user_ = false; // in user command
229+
bool ret_ = false; // user command complete, return to caller
230+
}; // class ExecState
231+
120232
class SimpleDebugger : public SST::InteractiveConsole
121233
{
122234

@@ -138,7 +250,8 @@ class SimpleDebugger : public SST::InteractiveConsole
138250
explicit SimpleDebugger(Params& params);
139251
~SimpleDebugger();
140252
141-
void execute(const std::string& msg) override;
253+
int execute(const std::string& msg) override;
254+
void summary() override;
142255
143256
// Callbacks from command line completions
144257
void get_listing_strings(std::list<std::string>&);
@@ -151,8 +264,9 @@ class SimpleDebugger : public SST::InteractiveConsole
151264
// directory as far as we can.
152265
std::vector<std::string> name_stack;
153266
154-
SST::Core::Serialization::ObjectMap* obj_ = nullptr;
155-
bool done = false;
267+
SST::Core::Serialization::ObjectMap* obj_ = nullptr;
268+
bool done = false;
269+
int retState = -1; // -1 DONE, -2 SUMAMRY, positive number is threadID
156270
157271
bool autoCompleteEnable = true;
158272
@@ -166,8 +280,12 @@ class SimpleDebugger : public SST::InteractiveConsole
166280
std::string replayFilePath = "sst-console.in";
167281
bool enLogging = false;
168282
169-
// command injection
170-
std::stringstream injectedCommand; // TODO use ConsoleCommand object
283+
// command injection (for sst --replay option)
284+
std::stringstream injectedCommand;
285+
286+
// execution state management for nested user commands
287+
ExecState eState = {};
288+
std::stack<ExecState> eStack = {};
171289
172290
// Keep a pointer to the ObjectMap for the top level Component
173291
SST::Core::Serialization::ObjectMapDeferred<BaseComponent>* base_comp_ = nullptr;
@@ -182,6 +300,8 @@ class SimpleDebugger : public SST::InteractiveConsole
182300
// Navigation
183301
void cmd_help(std::vector<std::string>& UNUSED(tokens));
184302
void cmd_verbose(std::vector<std::string>&(tokens));
303+
void cmd_info(std::vector<std::string>& UNUSED(tokens));
304+
void cmd_thread(std::vector<std::string>& tokens);
185305
void cmd_pwd(std::vector<std::string>& UNUSED(tokens));
186306
void cmd_ls(std::vector<std::string>& UNUSED(tokens));
187307
void cmd_cd(std::vector<std::string>& tokens);
@@ -192,6 +312,9 @@ class SimpleDebugger : public SST::InteractiveConsole
192312
void cmd_time(std::vector<std::string>& tokens);
193313
void cmd_watch(std::vector<std::string>& tokens);
194314
void cmd_unwatch(std::vector<std::string>& tokens);
315+
#ifdef __CT_RECURSE__
316+
void cmd_examine(std::vector<std::string>& tokens);
317+
#endif
195318
196319
// Simulation Control
197320
void cmd_run(std::vector<std::string>& tokens);
@@ -219,22 +342,25 @@ class SimpleDebugger : public SST::InteractiveConsole
219342
// Reset terminal
220343
void cmd_clear(std::vector<std::string>& UNUSED(tokens));
221344
345+
// User defined commands
346+
void cmd_define(std::vector<std::string>& tokens);
347+
void cmd_document(std::vector<std::string>& tokens);
348+
222349
// LLDB/GDB helper
223350
void cmd_spinThread(std::vector<std::string>& tokens);
224351
352+
// command entry point
225353
void dispatch_cmd(std::string& cmd);
226354
227355
// Command Registry
228-
std::vector<ConsoleCommand> cmdRegistry;
229-
230-
// Detailed Command Help
231-
std::map<std::string, std::string> cmdHelp;
356+
CommandRegistry cmdRegistry;
232357
233358
// Command History
234359
CommandHistoryBuffer cmdHistoryBuf;
235360
236361
// Command Line Editor
237-
CmdLineEditor cmdLineEditor;
362+
CmdLineEditor cmdLineEditor;
363+
LINE_ENTRY_MODE line_entry_mode = LINE_ENTRY_MODE::NORMAL;
238364
239365
// Verbosity controlled console printing
240366
uint32_t verbosity = 0;

src/sst/core/interactiveAction.h

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "sst/core/action.h"
1616
// Can include this because this header is not installed
17+
#include "sst/core/interactiveConsole.h"
1718
#include "sst/core/simulation_impl.h"
1819

1920
#include <string>
@@ -31,14 +32,33 @@ class InteractiveAction : public Action
3132
Create a new InteractiveAction object for the simulation core to initiate interactive mode
3233
*/
3334
InteractiveAction(Simulation_impl* sim, const std::string& msg) :
34-
Action(),
3535
sim_(sim),
3636
msg_(msg)
3737
{
3838
setPriority(INTERACTIVEPRIOIRTY);
3939
}
4040

4141
~InteractiveAction() {}
42+
#if 1
43+
/**
44+
Indicates InteractiveAction should be inserted into the
45+
TimeVortex. The insertion will only happen for serial runs, as
46+
InteractiveAction is managed by the SyncManager in parallel
47+
runs.
48+
*/
49+
void insertIntoTimeVortex(SimTime_t time)
50+
{
51+
// If this is a serial job, insert this into
52+
// the time TimeVortex. If it is parallel, then the
53+
// InteractiveAction is managed by the SyncManager.
54+
// std::cout << "skk: insertIntoTimeVortex called\n";
55+
RankInfo num_ranks = sim_->getNumRanks();
56+
// if (num_ranks.rank == 1 && num_ranks.thread == 1) {
57+
// std::cout << " skk: insertIntoTimeVortex insertActivity\n";
58+
sim_->insertActivity(time, this);
59+
//}
60+
}
61+
#endif
4262

4363
/** Called by TimeVortex to trigger interactive mode. */
4464
void execute() override
@@ -48,6 +68,7 @@ class InteractiveAction : public Action
4868
delete this;
4969
}
5070

71+
5172
private:
5273
Simulation_impl* sim_;
5374
std::string msg_;

src/sst/core/interactiveConsole.cc

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,9 @@ InteractiveConsole::getComponentObjectMap()
114114
void
115115
InteractiveConsole::simulationShutdown()
116116
{
117-
Simulation_impl::getSimulation()->endSimulation();
117+
// Simulation_impl::getSimulation()->endSimulation(); // Only works for single thread
118+
std::cout << "Simulation shutdown\n";
119+
Simulation_impl::getSimulation()->signalShutdown(false);
118120
}
119121

120122

src/sst/core/interactiveConsole.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,12 @@ class InteractiveConsole
5757
InteractiveConsole() = default;
5858
virtual ~InteractiveConsole() = default;
5959

60+
/** Interactive Console execute return codes: Positive number is thread ID to switch to, negative is other state */
61+
enum ICretcode { DONE = -1, SUMMARY = -2 };
6062
/** Called by TimeVortex to trigger checkpoint on simulation clock interval - not used in parallel simulation */
61-
virtual void execute(const std::string& msg) = 0;
63+
virtual int execute(const std::string& msg) = 0;
64+
/** Called by SyncManager to get summary info for each thread */
65+
virtual void summary() = 0;
6266

6367
protected:
6468
// Functions that can be called by child class

src/sst/core/main.cc

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,11 @@ start_simulation(uint32_t tid, SimThreadInfo_t& info, Core::ThreadSafe::Barrier&
468468
Simulation_impl::createSimulation(info.myRank, info.world_size, restart, currentSimCycle, currentPriority);
469469
double start_run = 0.0;
470470

471+
// Setup the real time actions (all of these have to be defined on
472+
// the command-line or SDL file, they will not be checkpointed and
473+
// restored
474+
sim->setupSimActions();
475+
471476
// Thread zero needs to initialize the checkpoint data structures
472477
// if any checkpointing options were turned on. This will return
473478
// an empty string if checkpointing was not enabled.
@@ -528,13 +533,6 @@ start_simulation(uint32_t tid, SimThreadInfo_t& info, Core::ThreadSafe::Barrier&
528533

529534
} // if ( restart )
530535

531-
532-
// Setup the real time actions (all of these have to be defined on
533-
// the command-line or SDL file, they will not be checkpointed and
534-
// restored
535-
sim->setupSimActions();
536-
537-
538536
if ( !restart ) {
539537

540538
// Prepare the links, which creates the ComponentInfo objects and

0 commit comments

Comments
 (0)