Gabe Black has uploaded this change for review. (
https://gem5-review.googlesource.com/c/public/gem5/+/27554 )
Change subject: util: c++-ify the commands in the m5 utility.
......................................................................
util: c++-ify the commands in the m5 utility.
Change-Id: I6755892c42aa418aed64f1aafcdb8c1290b2e8d5
---
M util/m5/src/commands.cc
M util/m5/src/commands.hh
M util/m5/src/m5.cc
M util/m5/src/usage.cc
4 files changed, 111 insertions(+), 140 deletions(-)
diff --git a/util/m5/src/commands.cc b/util/m5/src/commands.cc
index 5a1667e..1190598 100644
--- a/util/m5/src/commands.cc
+++ b/util/m5/src/commands.cc
@@ -26,87 +26,82 @@
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#include <err.h>
-#include <fcntl.h>
-#include <unistd.h>
-
-#include <cinttypes>
-#include <cstdio>
-#include <cstdlib>
#include <cstring>
+#include <fstream>
+#include <iostream>
#include "args.hh"
#include "commands.hh"
#include "usage.hh"
-static int
-read_file(const DispatchTable &dt, int dest_fid)
+void
+Command::run(const DispatchTable &dt, Args &args)
{
- uint8_t buf[256*1024];
- int offset = 0;
- int len, ret;
+ const int num_args = args.size();
+ if (num_args < minArgs || num_args > maxArgs)
+ usage();
+
+ func(dt, args);
+}
+
+
+static int
+read_file(const DispatchTable &dt, std::ostream &os)
+{
+ 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);
+ while (true) {
+ src.read(buf, sizeof(buf));
+ int len = src.gcount();
+ if (!src || !len)
+ break;
+ bytes += (*dt.m5_write_file)(buf, len, offset,
host_filename.c_str());
offset += len;
}
- fprintf(stderr, "written %d bytes\n", bytes);
-
- close(src_fid);
+ std::cerr << "written " << bytes << " 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();
@@ -117,9 +112,6 @@
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, 1))
usage();
@@ -130,9 +122,6 @@
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();
@@ -143,9 +132,6 @@
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();
@@ -156,9 +142,6 @@
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();
@@ -172,27 +155,21 @@
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();
@@ -203,9 +180,6 @@
static void
do_addsymbol(const DispatchTable &dt, Args &args)
{
- if (args.size() != 2)
- usage();
-
uint64_t addr;
if (!args.pop(addr))
usage();
@@ -218,18 +192,12 @@
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();
@@ -237,42 +205,34 @@
std::cout << val;
}
-CommandInfo command_table[] = {
- { "addsymbol", do_addsymbol, "<address> <symbol> // 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, "<code> [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, "<filename> [host filename]
// "
- "Write a file to the host, "
- "optionally with a different "
- "name" },
+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"
}},
+ { "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, "<filename> [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 013e20d..cb361b4 100644
--- a/util/m5/src/commands.hh
+++ b/util/m5/src/commands.hh
@@ -29,24 +29,46 @@
#ifndef __COMMANDS_HH__
#define __COMMANDS_HH__
+#include <map>
+#include <string>
+
#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;
+
+ 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;
+ }
};
-// The commands themselves.
-extern CommandInfo command_table[];
-
-// The number of commands.
-extern int num_commands;
-
#endif // __COMMANDS_HH__
diff --git a/util/m5/src/m5.cc b/util/m5/src/m5.cc
index 59930e3..eebddd2 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 <cstdlib>
-#include <cstring>
-
#include "args.hh"
#include "call_type.hh"
#include "commands.hh"
@@ -51,25 +48,20 @@
{
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();
+ auto cmd = Command::map.find(args.pop());
+ if (cmd == Command::map.end())
+ usage();
- for (int i = 0; i < num_commands; ++i) {
- if (command != command_table[i].name)
- continue;
-
- command_table[i].func(dt, args);
- exit(0);
- }
-
- usage();
+ cmd->second.run(dt, args);
+ exit(0);
}
diff --git a/util/m5/src/usage.cc b/util/m5/src/usage.cc
index a0546cd..60ceedf 100644
--- a/util/m5/src/usage.cc
+++ b/util/m5/src/usage.cc
@@ -58,10 +58,7 @@
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");
--
To view, visit https://gem5-review.googlesource.com/c/public/gem5/+/27554
To unsubscribe, or for help writing mail filters, visit
https://gem5-review.googlesource.com/settings
Gerrit-Project: public/gem5
Gerrit-Branch: develop
Gerrit-Change-Id: I6755892c42aa418aed64f1aafcdb8c1290b2e8d5
Gerrit-Change-Number: 27554
Gerrit-PatchSet: 1
Gerrit-Owner: Gabe Black <[email protected]>
Gerrit-MessageType: newchange
_______________________________________________
gem5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/gem5-dev