From 692431a89c2a6dbb91a88e3adba4d7358e46fc08 Mon Sep 17 00:00:00 2001 From: Gabe Black Date: Mon, 6 Apr 2020 22:21:43 -0700 Subject: [PATCH] util: Redistribute command code in the m5 utility. This division will make it easier to test both the common command code, and the individual commands. Change-Id: Ib7be2b93e40d07e9724443ba26784e45ad9d3b17 Reviewed-on: https://gem5-review.googlesource.com/c/public/gem5/+/27562 Reviewed-by: Gabe Black Reviewed-by: Giacomo Travaglini Maintainer: Gabe Black Tested-by: kokoro --- util/m5/src/SConscript | 5 +- util/m5/src/command.cc | 57 ++++++ util/m5/src/{commands.hh => command.hh} | 33 ++-- util/m5/src/commands.cc | 230 +++++++++++++----------- util/m5/src/m5.cc | 9 +- util/m5/src/usage.cc | 2 +- 6 files changed, 213 insertions(+), 123 deletions(-) create mode 100644 util/m5/src/command.cc rename util/m5/src/{commands.hh => command.hh} (76%) diff --git a/util/m5/src/SConscript b/util/m5/src/SConscript index 0082ebcb8..1f33caa1c 100644 --- a/util/m5/src/SConscript +++ b/util/m5/src/SConscript @@ -32,6 +32,7 @@ env.Append(CPPPATH=Dir('.')) # Raw source files. args = 'args.cc' call_type = 'call_type.cc' +command = 'command.cc' commands = 'commands.cc' m5 = 'm5.cc' m5_mmap = 'm5_mmap.c' @@ -68,8 +69,8 @@ for ct in call_types: is_default = 'true' if ct.default else 'false' ct_env.Append(CXXFLAGS=[ '-DCALL_TYPE_IS_DEFAULT=%s' % is_default ]) ct_support.extend(ct_env.StaticObject('call_type/%s.cc' % ct.name)) -m5_bin = static_env.Program('out/m5', - ct_support + [ args, call_type, commands, m5, m5_mmap, libm5, usage ]) +m5_bin = static_env.Program('out/m5', ct_support + + [ args, call_type, command, commands, m5, m5_mmap, libm5, usage ]) # The shared version of the m5 op call sights, used by mutliple targets below. diff --git a/util/m5/src/command.cc b/util/m5/src/command.cc new file mode 100644 index 000000000..d7dc03028 --- /dev/null +++ b/util/m5/src/command.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2003-2005 The Regents of The University of Michigan + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer; + * redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution; + * neither the name of the copyright holders nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "args.hh" +#include "command.hh" + +std::map & +Command::map() +{ + static std::map the_map; + return the_map; +} + +bool +Command::run(const DispatchTable &dt, Args &args) +{ + if (!args.size()) + return false; + + auto cmd_it = map().find(args.pop()); + if (cmd_it == map().end()) + return false; + + auto &cmd = cmd_it->second; + + const int num_args = args.size(); + if (num_args < cmd.minArgs || num_args > cmd.maxArgs) + return false; + + cmd.func(dt, args); + return true; +} diff --git a/util/m5/src/commands.hh b/util/m5/src/command.hh similarity index 76% rename from util/m5/src/commands.hh rename to util/m5/src/command.hh index cb361b4bb..8348d1116 100644 --- a/util/m5/src/commands.hh +++ b/util/m5/src/command.hh @@ -26,18 +26,21 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef __COMMANDS_HH__ -#define __COMMANDS_HH__ +#ifndef __COMMAND_HH__ +#define __COMMAND_HH__ #include #include +#include -#include "args.hh" -#include "dispatch_table.hh" +class Args; +class DispatchTable; class Command { private: + const std::string name; + // The minimum number of arguments the command expects. const int minArgs; // The maximum number of arguments the command can handle. @@ -51,24 +54,32 @@ class Command // Help text for this command. const std::string usageStr; + static std::map &map(); + public: - static std::map map; + Command(const std::string &_name, int _min, int _max, FuncType _func, + const std::string &_usage) : + name(_name), minArgs(_min), maxArgs(_max), func(_func), + usageStr(_usage) + { + map().emplace(std::piecewise_construct, + std::forward_as_tuple(std::string(_name)), + std::forward_as_tuple(*this)); + } - Command(int _min, int _max, FuncType _func, const std::string &_usage) : - minArgs(_min), maxArgs(_max), func(_func), usageStr(_usage) - {} + ~Command() { map().erase(name); } - void run(const DispatchTable &dt, Args &args); + static bool run(const DispatchTable &dt, Args &args); static std::string usageSummary() { std::string summary; - for (auto &p: Command::map) + for (auto &p: Command::map()) summary += " " + p.first + " " + p.second.usageStr + "\n"; return summary; } }; -#endif // __COMMANDS_HH__ +#endif // __COMMAND_HH__ diff --git a/util/m5/src/commands.cc b/util/m5/src/commands.cc index 2d71f9314..0dd971acf 100644 --- a/util/m5/src/commands.cc +++ b/util/m5/src/commands.cc @@ -31,21 +31,14 @@ #include #include "args.hh" -#include "commands.hh" +#include "command.hh" +#include "dispatch_table.hh" #include "usage.hh" -void -Command::run(const DispatchTable &dt, Args &args) +namespace { - const int num_args = args.size(); - if (num_args < minArgs || num_args > maxArgs) - usage(); - - func(dt, args); -} - -static int +int read_file(const DispatchTable &dt, std::ostream &os) { char buf[256 * 1024]; @@ -70,7 +63,7 @@ read_file(const DispatchTable &dt, std::ostream &os) return offset; } -static void +void write_file(const DispatchTable &dt, const std::string &filename, const std::string &host_filename) { @@ -107,50 +100,56 @@ write_file(const DispatchTable &dt, const std::string &filename, std::cerr << "Wrote " << offset << " bytes." << std::endl; } -static void -do_exit(const DispatchTable &dt, Args &args) +void +do_add_symbol(const DispatchTable &dt, Args &args) { - uint64_t ns_delay; - if (!args.pop(ns_delay, 0)) + uint64_t addr; + if (!args.pop(addr)) usage(); + const std::string &symbol = args.pop(); - (*dt.m5_exit)(ns_delay); + (*dt.m5_add_symbol)(addr, symbol.c_str()); } -// For testing purposes. -static void -do_sum(const DispatchTable &dt, Args &args) -{ - uint64_t a, b, c, d, e, f; - if (!args.pop(a) || !args.pop(b) || !args.pop(c, 0) || - !args.pop(d, 0) || !args.pop(e, 0) || !args.pop(f, 0)) - usage(); +Command add_symbol = { + "addsymbol", 2, 2, do_add_symbol, "
\n" + " Adds a symbol with address \"address\" to gem5's " + "symbol table" }; - unsigned sum = (*dt.m5_sum)(a, b, c, d, e, f); - std::cout << "Sum is " << sum << "." << std::endl; -} -static void -do_fail(const DispatchTable &dt, Args &args) +void +do_checkpoint(const DispatchTable &dt, Args &args) { - uint64_t ns_delay, code; - if (!args.pop(code) || !args.pop(ns_delay, 0)) + uint64_t ns_delay, ns_period; + if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); - (*dt.m5_fail)(ns_delay, code); + (*dt.m5_checkpoint)(ns_delay, ns_period); } -static void -do_reset_stats(const DispatchTable &dt, Args &args) +Command checkpoint = { + "checkpoint", 0, 2, do_checkpoint, "[delay [period]]\n" + " After delay (default 0) take a checkpoint, and then " + "optionally every period after" }; + + +void +do_dump_reset_stats(const DispatchTable &dt, Args &args) { uint64_t ns_delay, ns_period; if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) usage(); - (*dt.m5_reset_stats)(ns_delay, ns_period); + (*dt.m5_dump_reset_stats)(ns_delay, ns_period); } -static void +Command dump_reset_stats = { + "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" }; + + +void do_dump_stats(const DispatchTable &dt, Args &args) { uint64_t ns_delay, ns_period; @@ -160,102 +159,129 @@ do_dump_stats(const DispatchTable &dt, Args &args) (*dt.m5_dump_stats)(ns_delay, ns_period); } -static void -do_dump_reset_stats(const DispatchTable &dt, Args &args) +Command dump_stats = { + "dumpstats", 0, 2, do_dump_stats, "[delay [period]]\n" + " After delay (default 0) dump the stats, and then optionally " + "every period after" }; + + +void +do_exit(const DispatchTable &dt, Args &args) { - uint64_t ns_delay, ns_period; - if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) + uint64_t ns_delay; + if (!args.pop(ns_delay, 0)) usage(); - (*dt.m5_dump_reset_stats)(ns_delay, ns_period); + (*dt.m5_exit)(ns_delay); } -static void -do_read_file(const DispatchTable &dt, Args &args) +Command exit_cmd = { + "exit", 0, 1, do_exit, "[delay]\n" + " Exit after delay, or immediately" }; + + +void +do_fail(const DispatchTable &dt, Args &args) { - if (args.size() > 0) + uint64_t ns_delay, code; + if (!args.pop(code) || !args.pop(ns_delay, 0)) usage(); - read_file(dt, std::cout); + (*dt.m5_fail)(ns_delay, code); } -static void -do_write_file(const DispatchTable &dt, Args &args) -{ - const std::string &filename = args.pop(); - const std::string &host_filename = args.pop(filename); +Command fail_cmd = { + "fail", 1, 2, do_fail, " [delay]\n" + " Exit with failure code code after delay, or immediately" }; - write_file(dt, filename, host_filename); -} -static void -do_checkpoint(const DispatchTable &dt, Args &args) +// For testing purposes. +void +do_sum(const DispatchTable &dt, Args &args) { - uint64_t ns_delay, ns_period; - if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) + uint64_t a, b, c, d, e, f; + if (!args.pop(a) || !args.pop(b) || !args.pop(c, 0) || + !args.pop(d, 0) || !args.pop(e, 0) || !args.pop(f, 0)) usage(); - (*dt.m5_checkpoint)(ns_delay, ns_period); + unsigned sum = (*dt.m5_sum)(a, b, c, d, e, f); + std::cout << "Sum is " << sum << "." << std::endl; } -static void -do_addsymbol(const DispatchTable &dt, Args &args) +Command sum = { + "sum", 2, 6, do_sum, " [c [d [e [f]]]]\n" + " Sum a-f (defaults are 0), for testing purposes" }; + + +void +do_initparam(const DispatchTable &dt, Args &args) { - uint64_t addr; - if (!args.pop(addr)) + uint64_t key_str[2]; + if (!args.pop(key_str, 2)) usage(); - const std::string &symbol = args.pop(); - - (*dt.m5_add_symbol)(addr, symbol.c_str()); + uint64_t val = (*dt.m5_init_param)(key_str[0], key_str[1]); + std::cout << val; } +Command init_param = { + "initparam", 1, 1, do_initparam, "[key]\n" + " optional key may be at most 16 characters long" }; + -static void +void do_loadsymbol(const DispatchTable &dt, Args &args) { (*dt.m5_load_symbol)(); } -static void -do_initparam(const DispatchTable &dt, Args &args) +Command load_symbol = { + "loadsymbol", 0, 0, do_loadsymbol, "\n" + " load a preselected symbol file into gem5's symbol table" }; + + +void +do_read_file(const DispatchTable &dt, Args &args) { - uint64_t key_str[2]; - if (!args.pop(key_str, 2)) + if (args.size() > 0) usage(); - uint64_t val = (*dt.m5_init_param)(key_str[0], key_str[1]); - std::cout << val; + + read_file(dt, std::cout); } -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" }}, - { "sum", { 2, 6, do_sum, " [c [d [e [f]]]]\n" - " Sum a-f (defaults are 0), for testing purposes" }}, - { "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" +Command read_file_cmd = { + "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" + "stdout" }; + + +void +do_reset_stats(const DispatchTable &dt, Args &args) +{ + uint64_t ns_delay, ns_period; + if (!args.pop(ns_delay, 0) || !args.pop(ns_period, 0)) + usage(); + + (*dt.m5_reset_stats)(ns_delay, ns_period); +} + +Command reset_stats = { + "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" + "optionally every period after" }; + + +void +do_write_file(const DispatchTable &dt, Args &args) +{ + const std::string &filename = args.pop(); + const std::string &host_filename = args.pop(filename); + + write_file(dt, filename, host_filename); +} + +Command write_file_cmd = { + "writefile", 1, 2, do_write_file, " [host filename]\n" " Write a file to the host, optionally with a different " - "name" }}, -}; + "name" }; + +} // anonymous namespace diff --git a/util/m5/src/m5.cc b/util/m5/src/m5.cc index eebddd25c..f8c1101f0 100644 --- a/util/m5/src/m5.cc +++ b/util/m5/src/m5.cc @@ -40,7 +40,7 @@ #include "args.hh" #include "call_type.hh" -#include "commands.hh" +#include "command.hh" #include "usage.hh" int @@ -55,13 +55,8 @@ main(int argc, const char *argv[]) const DispatchTable &dt = CallType::detect(args).getDispatch(); - if (!args.size()) - usage(); - - auto cmd = Command::map.find(args.pop()); - if (cmd == Command::map.end()) + if (!Command::run(dt, args)) usage(); - cmd->second.run(dt, args); exit(0); } diff --git a/util/m5/src/usage.cc b/util/m5/src/usage.cc index bbcf36af3..78bfb4136 100644 --- a/util/m5/src/usage.cc +++ b/util/m5/src/usage.cc @@ -42,7 +42,7 @@ #include #include "call_type.hh" -#include "commands.hh" +#include "command.hh" #include "usage.hh" std::string progname; -- 2.30.2