util: Redistribute command code in the m5 utility.
authorGabe Black <gabeblack@google.com>
Tue, 7 Apr 2020 05:21:43 +0000 (22:21 -0700)
committerGabe Black <gabeblack@google.com>
Mon, 27 Jul 2020 08:27:41 +0000 (08:27 +0000)
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 <gabeblack@google.com>
Reviewed-by: Giacomo Travaglini <giacomo.travaglini@arm.com>
Maintainer: Gabe Black <gabeblack@google.com>
Tested-by: kokoro <noreply+kokoro@google.com>
util/m5/src/SConscript
util/m5/src/command.cc [new file with mode: 0644]
util/m5/src/command.hh [new file with mode: 0644]
util/m5/src/commands.cc
util/m5/src/commands.hh [deleted file]
util/m5/src/m5.cc
util/m5/src/usage.cc

index 0082ebcb8dd8c2ff47a6baaa1c266716b14e6237..1f33caa1ccdfcce7c2731297922c3f710f8fe7a8 100644 (file)
@@ -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 (file)
index 0000000..d7dc030
--- /dev/null
@@ -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<std::string, Command &> &
+Command::map()
+{
+    static std::map<std::string, Command &> 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/command.hh b/util/m5/src/command.hh
new file mode 100644 (file)
index 0000000..8348d11
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * 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.
+ */
+
+#ifndef __COMMAND_HH__
+#define __COMMAND_HH__
+
+#include <map>
+#include <string>
+#include <utility>
+
+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.
+    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.
+    FuncType func;
+
+    // Help text for this command.
+    const std::string usageStr;
+
+    static std::map<std::string, Command &> &map();
+
+  public:
+
+    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() { map().erase(name); }
+
+    static bool 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 // __COMMAND_HH__
index 2d71f93148652f0098871488dc5d5268e1a538e6..0dd971acf8fa71e3b1f195d8a6c2d42b9b140a36 100644 (file)
 #include <iostream>
 
 #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, "<address> <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, "<code> [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, "<a> <b> [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<std::string, Command> Command::map = {
-    { "addsymbol", { 2, 2, do_addsymbol, "<address> <symbol>\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, "<code> [delay]\n"
-        "        Exit with failure code code after delay, or immediately" }},
-    { "sum", { 2, 6, do_sum, "<a> <b> [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, "<filename> [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, "<filename> [host filename]\n"
         "        Write a file to the host, optionally with a different "
-            "name" }},
-};
+            "name" };
+
+} // anonymous namespace
diff --git a/util/m5/src/commands.hh b/util/m5/src/commands.hh
deleted file mode 100644 (file)
index cb361b4..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef __COMMANDS_HH__
-#define __COMMANDS_HH__
-
-#include <map>
-#include <string>
-
-#include "args.hh"
-#include "dispatch_table.hh"
-
-class Command
-{
-  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.
-    FuncType func;
-
-    // Help text for this command.
-    const std::string usageStr;
-
-  public:
-
-    static std::map<std::string, Command> 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__
index eebddd25c3f04ef865b813fb4292bb7a6e8782e7..f8c1101f09b91e163bbe5a94b86e57d858e36cdd 100644 (file)
@@ -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);
 }
index bbcf36af364b68452496d9f6a66ad7594c8a0a81..78bfb413638b06e8b0ab706b0a7e2eb914e9da46 100644 (file)
@@ -42,7 +42,7 @@
 #include <iostream>
 
 #include "call_type.hh"
-#include "commands.hh"
+#include "command.hh"
 #include "usage.hh"
 
 std::string progname;