From 9d222570b895e4f6fd04e3194a83ff1f31f3d433 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Sun, 5 Apr 2020 01:15:32 -0700 Subject: [PATCH] util: c++-ify the commands in the m5 utility. Change-Id: I6755892c42aa418aed64f1aafcdb8c1290b2e8d5 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27554 Reviewed-by: Gabe Black Maintainer: Gabe Black Tested-by: kokoro --- util/m5/src/commands.cc | 189 +++++++++++++++++----------------------- util/m5/src/commands.hh | 42 ++++++--- util/m5/src/m5.cc | 22 ++--- util/m5/src/usage.cc | 5 +- 4 files changed, 118 insertions(+), 140 deletions(-) diff --git a/util/m5/src/commands.cc b/util/m5/src/commands.cc index b59633b23..c779e8083 100644 --- a/util/m5/src/commands.cc +++ b/util/m5/src/commands.cc @@ -26,88 +26,90 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include -#include - -#include -#include -#include #include +#include #include #include "args.hh" #include "commands.hh" #include "usage.hh" +void +Command::run(const DispatchTable &dt, Args &args) +{ + const int num_args = args.size(); + if (num_args < minArgs || num_args > maxArgs) + usage(); + + func(dt, args); +} + + static int -read_file(const DispatchTable &dt, int dest_fid) +read_file(const DispatchTable &dt, std::ostream &os) { - uint8_t buf[256*1024]; - int offset = 0; - int len, ret; + char buf[256 * 1024]; // Touch all buffer pages to ensure they are mapped in the // page table. This is required in the case of X86_FS, where // Linux does demand paging. memset(buf, 0, sizeof(buf)); + int len; + int offset = 0; while ((len = (*dt.m5_read_file)(buf, sizeof(buf), offset)) > 0) { - uint8_t *base = buf; + os.write(buf, len); + os.flush(); + if (!os) { + std::cerr << "Failed to write file" << std::endl; + exit(2); + } offset += len; - do { - ret = write(dest_fid, base, len); - if (ret < 0) { - perror("Failed to write file"); - exit(2); - } else if (ret == 0) { - fprintf(stderr, "Failed to write file: " - "Unhandled short write\n"); - exit(2); - } - - base += ret; - len -= ret; - } while (len); } return offset; } static void -write_file(const DispatchTable &dt, const char *filename, - const char *host_filename) +write_file(const DispatchTable &dt, const std::string &filename, + const std::string &host_filename) { - fprintf(stderr, "opening %s\n", filename); - int src_fid = open(filename, O_RDONLY); + std::cerr << "opening " << filename << std::endl; + std::ifstream src(filename, std::ios_base::in | std::ios_base::binary); - if (src_fid < 0) { - fprintf(stderr, "error opening %s\n", filename); + if (!src) { + std::cerr << "error opening " << filename << std::endl; return; } - char buf[256*1024]; + char buf[256 * 1024]; int offset = 0; - int len; - int bytes = 0; memset(buf, 0, sizeof(buf)); - while ((len = read(src_fid, buf, sizeof(buf))) > 0) { - bytes += (*dt.m5_write_file)(buf, len, offset, host_filename); - offset += len; + while (true) { + src.seekg(offset); + src.read(buf, sizeof(buf)); + int len = src.gcount(); + if (!src && !src.eof()) + break; + char *wbuf = buf; + while (len) { + int bytes = (*dt.m5_write_file)( + wbuf, len, offset, host_filename.c_str()); + len -= bytes; + offset += bytes; + wbuf += bytes; + } + if (src.eof()) + break; } - fprintf(stderr, "written %d bytes\n", bytes); - - close(src_fid); + std::cerr << "Wrote " << offset << " bytes." << std::endl; } static void do_exit(const DispatchTable &dt, Args &args) { - if (args.size() > 1) - usage(); - uint64_t ns_delay; if (!args.pop(ns_delay, 0)) usage(); @@ -118,9 +120,6 @@ do_exit(const DispatchTable &dt, Args &args) static void do_fail(const DispatchTable &dt, Args &args) { - if (args.size() > 2) - usage(); - uint64_t ns_delay, code; if (!args.pop(code) || !args.pop(ns_delay, 0)) usage(); @@ -131,9 +130,6 @@ do_fail(const DispatchTable &dt, Args &args) static void do_reset_stats(const DispatchTable &dt, Args &args) { - if (args.size() > 2) - usage(); - uint64_t ns_delay, ns_period; if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); @@ -144,9 +140,6 @@ do_reset_stats(const DispatchTable &dt, Args &args) static void do_dump_stats(const DispatchTable &dt, Args &args) { - if (args.size() > 2) - usage(); - uint64_t ns_delay, ns_period; if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); @@ -157,9 +150,6 @@ do_dump_stats(const DispatchTable &dt, Args &args) static void do_dump_reset_stats(const DispatchTable &dt, Args &args) { - if (args.size() > 2) - usage(); - uint64_t ns_delay, ns_period; if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); @@ -173,27 +163,21 @@ do_read_file(const DispatchTable &dt, Args &args) if (args.size() > 0) usage(); - read_file(dt, STDOUT_FILENO); + read_file(dt, std::cout); } static void do_write_file(const DispatchTable &dt, Args &args) { - if (args.size() < 1 || args.size() > 2) - usage(); - const std::string &filename = args.pop(); const std::string &host_filename = args.pop(filename); - write_file(dt, filename.c_str(), host_filename.c_str()); + write_file(dt, filename, host_filename); } static void do_checkpoint(const DispatchTable &dt, Args &args) { - if (args.size() > 2) - usage(); - uint64_t ns_delay, ns_period; if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); @@ -204,9 +188,6 @@ do_checkpoint(const DispatchTable &dt, Args &args) static void do_addsymbol(const DispatchTable &dt, Args &args) { - if (args.size() != 2) - usage(); - uint64_t addr; if (!args.pop(addr)) usage(); @@ -219,18 +200,12 @@ do_addsymbol(const DispatchTable &dt, Args &args) static void do_loadsymbol(const DispatchTable &dt, Args &args) { - if (args.size() > 0) - usage(); - (*dt.m5_load_symbol)(); } static void do_initparam(const DispatchTable &dt, Args &args) { - if (args.size() != 1) - usage(); - uint64_t key_str[2]; if (!args.pop(key_str, 2)) usage(); @@ -238,42 +213,34 @@ do_initparam(const DispatchTable &dt, Args &args) std::cout << val; } -CommandInfo command_table[] = { - { "addsymbol", do_addsymbol, "
// Adds a " - "symbol with address \"address\" " - "to gem5's symbol table" }, - { "checkpoint", do_checkpoint, "[delay [period]] // After " - "delay (default 0) take a " - "checkpoint, and then optionally " - "every period after" }, - { "dumpresetstats", do_dump_reset_stats, "[delay [period]] // After " - "delay (default 0) dump and " - "reset the stats, and then " - "optionally every period after" }, - { "dumpstats", do_dump_stats, "[delay [period]] // After " - "delay (default 0) dump the " - "stats, and then optionally " - "every period after" }, - { "exit", do_exit, "[delay] // Exit after delay, " - "or immediately" }, - { "fail", do_fail, " [delay] // Exit with " - "failure code code after delay, " - "or immediately" }, - { "initparam", do_initparam, "[key] // optional key may be at " - "most 16 characters long" }, - { "loadsymbol", do_loadsymbol, "load a preselected symbol file " - "into gem5's symbol table" }, - { "readfile", do_read_file, "read a preselected file from " - "the host and write it to " - "stdout" }, - { "resetstats", do_reset_stats, "[delay [period]] // After " - "delay (default 0) reset the " - "stats, and then optionally " - "every period after" }, - { "writefile", do_write_file, " [host filename] // " - "Write a file to the host, " - "optionally with a different " - "name" }, +std::map Command::map = { + { "addsymbol", { 2, 2, do_addsymbol, "
\n" + " Adds a symbol with address \"address\" to gem5's " + "symbol table" }}, + { "checkpoint", { 0, 2, do_checkpoint, "[delay [period]]\n" + " After delay (default 0) take a checkpoint, and then " + "optionally every period after" }}, + { "dumpresetstats", { 0, 2, do_dump_reset_stats, "[delay [period]]\n" + " After delay (default 0) dump and reset the stats, and then " + "optionally every period after" }}, + { "dumpstats", { 0, 2, do_dump_stats, "[delay [period]]\n" + " After delay (default 0) dump the stats, and then optionally " + "every period after" }}, + { "exit", { 0, 1, do_exit, "[delay]\n" + " Exit after delay, or immediately" }}, + { "fail", { 1, 2, do_fail, " [delay]\n" + " Exit with failure code code after delay, or immediately" }}, + { "initparam", { 1, 1, do_initparam, "[key]\n" + " optional key may be at most 16 characters long" }}, + { "loadsymbol", { 0, 0, do_loadsymbol, "\n" + " load a preselected symbol file into gem5's symbol table" }}, + { "readfile", { 0, 0, do_read_file, "\n" + " read a preselected file from the host and write it to " + "stdout" }}, + { "resetstats", { 0, 2, do_reset_stats, "[delay [period]]\n" + " After delay (default 0) reset the stats, and then " + "optionally every period after" }}, + { "writefile", { 1, 2, do_write_file, " [host filename]\n" + " Write a file to the host, optionally with a different " + "name" }}, }; - -int num_commands = sizeof(command_table) / sizeof(CommandInfo); diff --git a/util/m5/src/commands.hh b/util/m5/src/commands.hh index 013e20d4e..cb361b4bb 100644 --- a/util/m5/src/commands.hh +++ b/util/m5/src/commands.hh @@ -29,24 +29,46 @@ #ifndef __COMMANDS_HH__ #define __COMMANDS_HH__ +#include +#include + #include "args.hh" #include "dispatch_table.hh" -struct CommandInfo +class Command { - // The name of the command. - const char *name; + private: + // The minimum number of arguments the command expects. + const int minArgs; + // The maximum number of arguments the command can handle. + const int maxArgs; + + using FuncType = void (*)(const DispatchTable &dt, Args &args); // A function which processes command line arguments and passes them to // the underlying function through the dispatch table. - void (*func)(const DispatchTable &dt, Args &args); + FuncType func; + // Help text for this command. - const char *usage; -}; + const std::string usageStr; -// The commands themselves. -extern CommandInfo command_table[]; + public: -// The number of commands. -extern int num_commands; + static std::map map; + + Command(int _min, int _max, FuncType _func, const std::string &_usage) : + minArgs(_min), maxArgs(_max), func(_func), usageStr(_usage) + {} + + void run(const DispatchTable &dt, Args &args); + + static std::string + usageSummary() + { + std::string summary; + for (auto &p: Command::map) + summary += " " + p.first + " " + p.second.usageStr + "\n"; + return summary; + } +}; #endif // __COMMANDS_HH__ diff --git a/util/m5/src/m5.cc b/util/m5/src/m5.cc index 59930e30c..eebddd25c 100644 --- a/util/m5/src/m5.cc +++ b/util/m5/src/m5.cc @@ -38,9 +38,6 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#include -#include - #include "args.hh" #include "call_type.hh" #include "commands.hh" @@ -51,25 +48,20 @@ main(int argc, const char *argv[]) { Args args(argc, argv); + progname = args.pop("{progname}"); + if (!args.size()) usage(); - progname = args.pop("{progname}"); - const DispatchTable &dt = CallType::detect(args).getDispatch(); if (!args.size()) usage(); - const std::string &command = args.pop(); - - for (int i = 0; i < num_commands; ++i) { - if (command != command_table[i].name) - continue; - - command_table[i].func(dt, args); - exit(0); - } + auto cmd = Command::map.find(args.pop()); + if (cmd == Command::map.end()) + usage(); - usage(); + cmd->second.run(dt, args); + exit(0); } diff --git a/util/m5/src/usage.cc b/util/m5/src/usage.cc index a0546cd52..60ceedf2f 100644 --- a/util/m5/src/usage.cc +++ b/util/m5/src/usage.cc @@ -58,10 +58,7 @@ usage() fprintf(stderr, CallType::usageSummary().c_str()); fprintf(stderr, "\n"); fprintf(stderr, "Commands:\n"); - for (int i = 0; i < num_commands; ++i) { - fprintf(stderr, " %s %s\n", - command_table[i].name, command_table[i].usage); - } + fprintf(stderr, Command::usageSummary().c_str()); fprintf(stderr, "\n"); fprintf(stderr, "All times in nanoseconds!\n"); -- 2.30.2