Rework the command line paramters for python output and how
authorNathan Binkert <binkertn@umich.edu>
Fri, 11 Feb 2005 14:47:41 +0000 (09:47 -0500)
committerNathan Binkert <binkertn@umich.edu>
Fri, 11 Feb 2005 14:47:41 +0000 (09:47 -0500)
output files and the output directory are are handled.  Make
the output directory configuration via a command line parameter,
or an environment variable.

SConscript:
    Add new output file stuff
base/misc.cc:
dev/simconsole.cc:
    use new output file code
cpu/base_cpu.cc:
    use new output file code to generate output streams
dev/etherdump.cc:
    use the output file code to find the output directory
    use a real stream instead of a pointer
dev/etherdump.hh:
    use a real stream instead of a pointer
objects/Root.mpy:
    output_dir and config_output_file are not longer configured here.
sim/main.cc:
    - Completely rework the command line argument passing to deal with
    changes in python and output files.
    - Update help output to reflect changes.
    - Remove all direct support for .ini files.  They are strictly
    for intermediate representation.
    - Remove the --foo:bar=blah syntax for .ini files and add --foo.bar=blah
    syntax for python.  This will generate: foo.bar = 'blah' in the python
    script.
    - Add '-d' to set the output directory.
    - Use new output file code to access the output stream.
sim/serialize.cc:
    use the new code to find the output directory
sim/universe.cc:
    Get rid of makeOutputStream.  Use the new output file code.
    Remove output_dir and config_output_file as parameters.

--HG--
extra : convert_revision : df2f0e13d401c3a60cae1239aa1ec3511721544d

12 files changed:
SConscript
base/misc.cc
base/output.cc [new file with mode: 0644]
base/output.hh [new file with mode: 0644]
cpu/base_cpu.cc
dev/etherdump.cc
dev/etherdump.hh
dev/simconsole.cc
objects/Root.mpy
sim/main.cc
sim/serialize.cc
sim/universe.cc

index 187edadff7bb1c02065c99beea120b613b8cda9f..19f84f91311d6661a0024d0fd98b9c9ac2da1d66 100644 (file)
@@ -63,6 +63,7 @@ base_sources = Split('''
        base/intmath.cc
        base/match.cc
        base/misc.cc
+       base/output.cc
        base/pollevent.cc
        base/python.cc
        base/range.cc
index 0c459352fe418da61b78dc2c272b290c5f670abb..4b7c3632a5de57f4c65abb9e9389eaec424f8383 100644 (file)
 #include <string>
 
 #include "base/cprintf.hh"
-#include "sim/host.hh"
 #include "base/hostinfo.hh"
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "base/trace.hh"
+#include "sim/host.hh"
 #include "sim/universe.hh"
 
 using namespace std;
@@ -116,7 +117,7 @@ __warn(const string &format, cp::ArgList &args, const char *func,
 #endif
 
     args.dump(cerr, fmt);
-    if (outputStream != &cerr && outputStream != &cout)
+    if (simout.isFile(*outputStream))
         args.dump(*outputStream, fmt);
 
     delete &args;
diff --git a/base/output.cc b/base/output.cc
new file mode 100644 (file)
index 0000000..2b1733f
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 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 <errno.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <fstream>
+
+#include "base/misc.hh"
+#include "base/output.hh"
+
+using namespace std;
+
+OutputDirectory simout;
+
+/**
+ *
+ */
+OutputDirectory::OutputDirectory()
+{}
+
+OutputDirectory::~OutputDirectory()
+{}
+
+void
+OutputDirectory::setDirectory(const string &d)
+{
+    if (!dir.empty())
+        panic("Output directory already set!\n");
+
+    dir = d;
+
+    if (dir != ".") {
+        if (mkdir(dir.c_str(), 0777) < 0 && errno != EEXIST)
+            panic("couldn't make output dir %s: %s\n",
+                  dir, strerror(errno));
+    }
+
+    // guarantee that directory ends with a '/'
+    if (dir[dir.size() - 1] != '/')
+        dir += "/";
+}
+
+const string &
+OutputDirectory::directory()
+{
+    if (dir.empty())
+        panic("Output directory not set!");
+
+    return dir;
+}
+
+string
+OutputDirectory::resolve(const string &name)
+{
+    return (name[0] != '/') ? dir + name : name;
+}
+
+ostream *
+OutputDirectory::create(const string &name)
+{
+    if (name == "cerr" || name == "stderr")
+        return &cerr;
+
+    if (name == "cout" || name == "stdout")
+        return &cout;
+
+    ofstream *file = new ofstream(resolve(name).c_str(), ios::trunc);
+    if (!file->is_open())
+        panic("Cannot open file %s", name);
+
+    return file;
+}
+
+ostream *
+OutputDirectory::find(const string &name)
+{
+    if (name == "cerr" || name == "stderr")
+        return &cerr;
+
+    if (name == "cout" || name == "stdout")
+        return &cout;
+
+    string filename = resolve(name);
+    map_t::iterator i = files.find(filename);
+    if (i != files.end())
+        return (*i).second;
+
+    ofstream *file = new ofstream(filename.c_str(), ios::trunc);
+    if (!file->is_open())
+        panic("Cannot open file %s", filename);
+
+    files[filename] = file;
+    return file;
+}
+
+bool
+OutputDirectory::isFile(const std::ostream *os)
+{
+    return os && os != &cerr && os != &cout;
+}
diff --git a/base/output.hh b/base/output.hh
new file mode 100644 (file)
index 0000000..3bbe73e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 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 __BASE_OUTPUT_HH__
+#define __BASE_OUTPUT_HH__
+
+#include <iosfwd>
+#include <map>
+#include <string>
+
+class OutputDirectory
+{
+  private:
+    typedef std::map<std::string, std::ostream *> map_t;
+
+    map_t files;
+    std::string dir;
+
+  public:
+    OutputDirectory();
+    ~OutputDirectory();
+
+    void setDirectory(const std::string &dir);
+    const std::string &directory();
+
+    std::string resolve(const std::string &name);
+    std::ostream *create(const std::string &name);
+    std::ostream *find(const std::string &name);
+
+    static bool isFile(const std::ostream *os);
+    static inline bool isFile(const std::ostream &os) { return isFile(&os); }
+};
+
+extern OutputDirectory simout;
+
+#endif // __BASE_OUTPUT_HH__
index c4bb97ff87b5f375927cec66ff89489df9d74ecc..425ac8877a918b5ac58d4fbedcdfa2d1da19caa6 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+#include <iostream>
 #include <string>
 #include <sstream>
-#include <iostream>
 
 #include "base/cprintf.hh"
 #include "base/loader/symtab.hh"
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "cpu/base_cpu.hh"
 #include "cpu/exec_context.hh"
 #include "sim/param.hh"
@@ -132,8 +133,7 @@ BaseCPU::BaseCPU(const string &_name, int _number_of_threads, bool _def_reg,
 
     functionTracingEnabled = false;
     if (_function_trace) {
-        std::string filename = csprintf("ftrace.%s", name());
-        functionTraceStream = makeOutputStream(filename);
+        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));
         currentFunctionStart = currentFunctionEnd = 0;
         functionEntryTick = _function_trace_start;
 
@@ -157,11 +157,8 @@ BaseCPU::enableFunctionTrace()
 
 BaseCPU::~BaseCPU()
 {
-    if (functionTracingEnabled)
-        closeOutputStream(functionTraceStream);
 }
 
-
 void
 BaseCPU::init()
 {
index 485d5599cba77f946c0d6e9c399497394f895322..3de417bdc2200d9210aa3788d3f7818172f21b1b 100644 (file)
 #include <string>
 
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "dev/etherdump.hh"
 #include "sim/builder.hh"
 #include "sim/universe.hh"
 
 using std::string;
 
-EtherDump::EtherDump(const string &name, std::ostream *_stream, int max)
-    : SimObject(name), stream(_stream), maxlen(max)
+EtherDump::EtherDump(const string &name, const string &file, int max)
+    : SimObject(name), stream(file.c_str()), maxlen(max)
 {
 }
 
@@ -86,7 +87,7 @@ EtherDump::init()
     hdr.sigfigs = 0;
     hdr.linktype = DLT_EN10MB;
 
-    stream->write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
+    stream.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
 
     /*
      * output an empty packet with the current time so that we know
@@ -98,9 +99,9 @@ EtherDump::init()
     pkthdr.microseconds = 0;
     pkthdr.caplen = 0;
     pkthdr.len = 0;
-    stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+    stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
 
-    stream->flush();
+    stream.flush();
 }
 
 void
@@ -111,9 +112,9 @@ EtherDump::dumpPacket(PacketPtr &packet)
     pkthdr.microseconds = (curTick / us_freq) % ULL(1000000);
     pkthdr.caplen = std::min(packet->length, maxlen);
     pkthdr.len = packet->length;
-    stream->write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
-    stream->write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
-    stream->flush();
+    stream.write(reinterpret_cast<char *>(&pkthdr), sizeof(pkthdr));
+    stream.write(reinterpret_cast<char *>(packet->data), pkthdr.caplen);
+    stream.flush();
 }
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
@@ -132,7 +133,7 @@ END_INIT_SIM_OBJECT_PARAMS(EtherDump)
 
 CREATE_SIM_OBJECT(EtherDump)
 {
-    return new EtherDump(getInstanceName(), makeOutputStream(file), maxlen);
+    return new EtherDump(getInstanceName(), simout.resolve(file), maxlen);
 }
 
 REGISTER_SIM_OBJECT("EtherDump", EtherDump)
index b127d05e2f4a31273b084551641118e17452a2ea..ba15796c836a930d327255f3002dddea30cec99e 100644 (file)
@@ -43,7 +43,7 @@
 class EtherDump : public SimObject
 {
   private:
-    std::ostream *stream;
+    std::ofstream stream;
     const int maxlen;
     void dumpPacket(PacketPtr &packet);
     void init();
@@ -53,7 +53,7 @@ class EtherDump : public SimObject
     Tick us_freq;
 
   public:
-    EtherDump(const std::string &name, std::ostream *_stream, int max);
+    EtherDump(const std::string &name, const std::string &file, int max);
 
     inline void dump(PacketPtr &pkt) { dumpPacket(pkt); }
 };
index 48e5d0201f92f1438683e673386b8a36e046d457..94fd9ec1fc3adfcba93312d2a3d84c6ddeac58d4 100644 (file)
@@ -43,6 +43,7 @@
 #include <string>
 
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "base/socket.hh"
 #include "base/trace.hh"
 #include "dev/platform.hh"
@@ -71,7 +72,7 @@ SimConsole::Event::process(int revent)
         cons->detach();
 }
 
-SimConsole::SimConsole(const string &name, std::ostream *os, int num)
+SimConsole::SimConsole(const string &name, ostream *os, int num)
     : SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
       listener(NULL), txbuf(16384), rxbuf(16384), outfile(os)
 #if TRACING_ON == 1
@@ -85,8 +86,6 @@ SimConsole::SimConsole(const string &name, std::ostream *os, int num)
 SimConsole::~SimConsole()
 {
     close();
-    if (outfile)
-        closeOutputStream(outfile);
 }
 
 void
@@ -313,18 +312,16 @@ END_INIT_SIM_OBJECT_PARAMS(SimConsole)
 
 CREATE_SIM_OBJECT(SimConsole)
 {
-    string filename;
+    string filename = output;
+    ostream *stream = NULL;
 
-    if (filename.empty()) {
-        filename = getInstanceName();
-    } else if (append_name) {
-        filename = (string)output + "." + getInstanceName();
-    } else {
-        filename = output;
+    if (!filename.empty()) {
+        if (append_name)
+            filename += "." + getInstanceName();
+        stream = simout.find(filename);
     }
 
-    SimConsole *console = new SimConsole(getInstanceName(),
-                                         makeOutputStream(filename), number);
+    SimConsole *console = new SimConsole(getInstanceName(), stream, number);
     ((ConsoleListener *)listener)->add(console);
 
     return console;
index dd485ac73b86ef5a4a772da962c94a8c4b387646..0e531054b08041312011fd424db86ce2e7b5fb14 100644 (file)
@@ -6,10 +6,7 @@ from Trace import Trace
 simobj Root(SimObject):
     type = 'Root'
     frequency = Param.Tick(200000000, "tick frequency")
-    output_dir = Param.String('.', "directory to output data to")
     output_file = Param.String('cout', "file to dump simulator output to")
-    config_output_file = Param.String('m5config.out',
-                                      "file to dump simulator config to")
     full_system = Param.Bool("Full system simulation?")
     hier = HierParams(do_data = False, do_events = True)
     checkpoint = Param.String('', "Checkpoint file")
index 163c835ee82f62497c0de8232551e2024c484c59..1748294af9cdfcd814f604cbe1125c81099b92af 100644 (file)
@@ -42,6 +42,7 @@
 #include "base/embedfile.hh"
 #include "base/inifile.hh"
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "base/pollevent.hh"
 #include "base/statistics.hh"
 #include "base/str.hh"
@@ -109,25 +110,32 @@ abortHandler(int sigtype)
 const char *myProgName = "";
 
 /// Show brief help message.
-static void
+void
 showBriefHelp(ostream &out)
 {
-    out << "Usage: " << myProgName
-        << " [-hnu] [-Dname[=def]] [-Uname] [-I[dir]] "
-        << "<config-spec> [<config-spec> ...]\n"
-        << "[] [<config file> ...]\n"
-        << "   -h: print long help (including parameter listing)\n"
-        << "   -u: don't quit on unreferenced parameters\n"
-        << "   -D,-U,-I: passed to cpp for preprocessing .ini files\n"
-        << "   <config-spec>: config file name (.ini or .py) or\n"
-        << "                  single param (--<section>:<param>=<value>)"
-        << endl;
+    char *prog = basename(myProgName);
+
+    ccprintf(out, "Usage:\n");
+    ccprintf(out,
+"%s [-d <dir>] [-E <var>[=<val>]] [-I <dir>] [-P <python>]\n"
+"        [--<var>=<val>] <config file>\n"
+"\n"
+"   -d            set the output directory to <dir>\n"
+"   -E            set the environment variable <var> to <val> (or 'True')\n"
+"   -I            add the directory <dir> to python's path\n"
+"   -P            execute <python> directly in the configuration\n"
+"   --var=val     set the python variable <var> to '<val>'\n"
+"   <configfile>  config file name (.py or .mpy)\n",
+             prog);
+
+    ccprintf(out, "%s -X\n    -X            extract embedded files\n", prog);
+    ccprintf(out, "%s -h\n    -h            print long help\n", prog);
 }
 
 /// Show verbose help message.  Includes parameter listing from
 /// showBriefHelp(), plus an exhaustive list of ini-file parameters
 /// and SimObjects (with their parameters).
-static void
+void
 showLongHelp(ostream &out)
 {
     showBriefHelp(out);
@@ -152,7 +160,7 @@ showLongHelp(ostream &out)
 }
 
 /// Print welcome message.
-static void
+void
 sayHello(ostream &out)
 {
     extern const char *compileDate;    // from date.cc
@@ -176,7 +184,7 @@ sayHello(ostream &out)
 /// Echo the command line for posterity in such a way that it can be
 /// used to rerun the same simulation (given the same .ini files).
 ///
-static void
+void
 echoCommandLine(int argc, char **argv, ostream &out)
 {
     out << "command line: " << argv[0];
@@ -208,16 +216,20 @@ echoCommandLine(int argc, char **argv, ostream &out)
     out << endl << endl;
 }
 
+char *
+getOptionString(int &index, int argc, char **argv)
+{
+    char *option = argv[index] + 2;
+    if (*option != '\0')
+        return option;
 
-///
-/// The simulator configuration database.  This is the union of all
-/// specified .ini files.  This shouldn't need to be visible outside
-/// this file, as it is passed as a parameter to all the param-parsing
-/// routines.
-///
-static IniFile simConfigDB;
+    // We didn't find an argument, it must be in the next variable.
+    if (++index >= argc)
+        panic("option string for option '%s' not found", argv[index - 1]);
+
+    return argv[index];
+}
 
-/// M5 entry point.
 int
 main(int argc, char **argv)
 {
@@ -233,18 +245,9 @@ main(int argc, char **argv)
 
     sayHello(cerr);
 
-    // Initialize statistics database
-    Stats::InitSimStats();
-
-    vector<char *> cppArgs;
-
-    // Should we quit if there are unreferenced parameters?  By
-    // default, yes... it's a good way of catching typos in
-    // section/parameter names (which otherwise go by silently).  Use
-    // -u to override.
-    bool quitOnUnreferenced = true;
-
-    bool python_initialized = false;
+    bool configfile_found = false;
+    PythonConfig pyconfig;
+    string outdir;
 
     // Parse command-line options.
     // Since most of the complex options are handled through the
@@ -253,12 +256,53 @@ main(int argc, char **argv)
     for (int i = 1; i < argc; ++i) {
         char *arg_str = argv[i];
 
-        // if arg starts with '-', parse as option,
-        // else treat it as a configuration file name and load it
-        if (arg_str[0] == '-') {
+        // if arg starts with '--', parse as a special python option
+        // of the format --<python var>=<string value>, if the arg
+        // starts with '-', it should be a simulator option with a
+        // format similar to getopt.  In any other case, treat the
+        // option as a configuration file name and load it.
+        if (arg_str[0] == '-' && arg_str[1] == '-') {
+            string str = &arg_str[2];
+            string var, val;
+
+            if (!split_first(str, var, val, '='))
+                panic("Could not parse configuration argument '%s'\n"
+                      "Expecting --<variable>=<value>\n", arg_str);
+
+            pyconfig.setVariable(var, val);
+        } else if (arg_str[0] == '-') {
+            char *option;
+            string var, val;
 
             // switch on second char
             switch (arg_str[1]) {
+              case 'd':
+                outdir = getOptionString(i, argc, argv);
+                break;
+
+              case 'h':
+                showLongHelp(cerr);
+                exit(1);
+
+              case 'E':
+                option = getOptionString(i, argc, argv);
+                if (!split_first(option, var, val, '='))
+                    val = "True";
+
+                if (setenv(var.c_str(), val.c_str(), true) == -1)
+                    panic("setenv: %s\n", strerror(errno));
+                break;
+
+              case 'I':
+                option = getOptionString(i, argc, argv);
+                pyconfig.addPath(option);
+                break;
+
+              case 'P':
+                option = getOptionString(i, argc, argv);
+                pyconfig.writeLine(option);
+                break;
+
               case 'X': {
                   list<EmbedFile> lst;
                   EmbedMap::all(lst);
@@ -274,124 +318,58 @@ main(int argc, char **argv)
                   return 0;
               }
 
-              case 'h':
-                // -h: show help
-                showLongHelp(cerr);
-                exit(1);
-
-              case 'u':
-                // -u: don't quit on unreferenced parameters
-                quitOnUnreferenced = false;
-                break;
-
-              case 'D':
-              case 'U':
-                // cpp options: record & pass to cpp.  Note that these
-                // cannot have spaces, i.e., '-Dname=val' is OK, but
-                // '-D name=val' is not.  I don't consider this a
-                // problem, since even though gnu cpp accepts the
-                // latter, other cpp implementations do not (Tru64,
-                // for one).
-                cppArgs.push_back(arg_str);
-                break;
-
-              case 'I': {
-                  // We push -I as an argument to cpp
-                  cppArgs.push_back(arg_str);
-
-                  string arg = arg_str + 2;
-                  eat_white(arg);
-
-                  // Send this as the python path
-                  addPythonPath(arg);
-              } break;
-
-              case 'P':
-                if (!python_initialized) {
-                    initPythonConfig();
-                    python_initialized = true;
-                }
-                writePythonString(arg_str + 2);
-                writePythonString("\n");
-
-              case 'E':
-                if (putenv(arg_str + 2) == -1)
-                    panic("putenv: %s\n", strerror(errno));
-                break;
-
-              case '-':
-                // command-line configuration parameter:
-                // '--<section>:<parameter>=<value>'
-                if (!simConfigDB.add(arg_str + 2)) {
-                    // parse error
-                    ccprintf(cerr,
-                             "Could not parse configuration argument '%s'\n"
-                             "Expecting --<section>:<parameter>=<value>\n",
-                             arg_str);
-                    exit(0);
-                }
-                break;
-
               default:
                 showBriefHelp(cerr);
-                ccprintf(cerr, "Fatal: invalid argument '%s'\n", arg_str);
-                exit(0);
-            }
-        }
-        else {
-            // no '-', treat as config file name
-
-            // make STL string out of file name
-            string filename(arg_str);
-
-            int ext_loc = filename.rfind(".");
-
-            string ext =
-                (ext_loc != string::npos) ? filename.substr(ext_loc) : "";
-
-            if (ext == ".ini") {
-                if (!simConfigDB.loadCPP(filename, cppArgs)) {
-                    cprintf("Error processing file %s\n", filename);
-                    exit(1);
-                }
-            } else if (ext == ".py" || ext == ".mpy") {
-                if (!python_initialized) {
-                    initPythonConfig();
-                    python_initialized = true;
-                }
-                loadPythonConfig(filename);
-            }
-            else {
-                cprintf("Config file name '%s' must end in '.py' or '.ini'.\n",
-                        filename);
-                exit(1);
+                panic("invalid argument '%s'\n", arg_str);
             }
+        } else {
+            string file(arg_str);
+            string base, ext;
+
+            if (!split_last(file, base, ext, '.') ||
+                ext != "py" && ext != "mpy")
+                panic("Config file '%s' must end in '.py' or '.mpy'\n", file);
+
+            pyconfig.load(file);
+            configfile_found = true;
         }
     }
 
-    if (python_initialized && !finishPythonConfig(simConfigDB)) {
-        cprintf("Error processing python code\n");
-        exit(1);
+    if (outdir.empty()) {
+        char *env = getenv("OUTPUT_DIR");
+        outdir = env ? env : ".";
     }
 
-    // The configuration database is now complete; start processing it.
+    simout.setDirectory(outdir);
 
-    // Parse and check all non-config-hierarchy parameters.
-    ParamContext::parseAllContexts(simConfigDB);
-    ParamContext::checkAllContexts();
+    char *env = getenv("CONFIG_OUTPUT");
+    if (!env)
+        env = "config.out";
+    configStream = simout.find(env);
 
-    // Print header info into stats file.  Can't do this sooner since
-    // the stat file name is set via a .ini param... thus it just got
-    // opened above during ParamContext::checkAllContexts().
+    if (!configfile_found)
+        panic("no configuration file specified!");
+
+    // The configuration database is now complete; start processing it.
+    IniFile inifile;
+    if (!pyconfig.output(inifile))
+        panic("Error processing python code");
+
+    // Initialize statistics database
+    Stats::InitSimStats();
 
     // Now process the configuration hierarchy and create the SimObjects.
-    ConfigHierarchy configHierarchy(simConfigDB);
+    ConfigHierarchy configHierarchy(inifile);
     configHierarchy.build();
     configHierarchy.createSimObjects();
 
+    // Parse and check all non-config-hierarchy parameters.
+    ParamContext::parseAllContexts(inifile);
+    ParamContext::checkAllContexts();
+
     // Print hello message to stats file if it's actually a file.  If
     // it's not (i.e. it's cout or cerr) then we already did it above.
-    if (outputStream != &cout && outputStream != &cerr)
+    if (simout.isFile(*outputStream))
         sayHello(*outputStream);
 
     // Echo command line and all parameter settings to stats file as well.
@@ -406,13 +384,8 @@ main(int argc, char **argv)
 
     // Done processing the configuration database.
     // Check for unreferenced entries.
-    if (simConfigDB.printUnreferenced() && quitOnUnreferenced) {
-        cerr << "Fatal: unreferenced .ini sections/entries." << endl
-             << "If this is not an error, add 'unref_section_ok=y' or "
-             << "'unref_entries_ok=y' to the appropriate sections "
-             << "to suppress this message." << endl;
-        exit(1);
-    }
+    if (inifile.printUnreferenced())
+        panic("unreferenced sections/entries in the intermediate ini file");
 
     SimObject::regAllStats();
 
index d5f217e551cb6c24ba56204268d55f9e8e431a9e..846d191e0a6fad539b078e14fa4fa9c63dc099b8 100644 (file)
@@ -38,6 +38,7 @@
 
 #include "base/inifile.hh"
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "base/str.hh"
 #include "base/trace.hh"
 #include "sim/config_node.hh"
@@ -333,7 +334,7 @@ SerializeParamContext::~SerializeParamContext()
 void
 SerializeParamContext::checkParams()
 {
-    checkpointDirBase = outputDirectory + (string)serialize_dir;
+    checkpointDirBase = simout.resolve(serialize_dir);
 
     // guarantee that directory ends with a '/'
     if (checkpointDirBase[checkpointDirBase.size() - 1] != '/')
index 115f6f790ed3badfb05d4c58320768dc6e9a7edf..9137baaf0959b25a1f696635203717f8163d5c6a 100644 (file)
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <errno.h>
-
 #include <cstring>
 #include <fstream>
 #include <list>
@@ -37,6 +33,7 @@
 #include <vector>
 
 #include "base/misc.hh"
+#include "base/output.hh"
 #include "sim/builder.hh"
 #include "sim/host.hh"
 #include "sim/sim_object.hh"
@@ -51,7 +48,7 @@ double __ticksPerUS;
 double __ticksPerNS;
 double __ticksPerPS;
 
-string outputDirectory;
+bool fullSystem;
 ostream *outputStream;
 ostream *configStream;
 
@@ -61,81 +58,40 @@ class Root : public SimObject
   public:
     Root(const std::string &name) : SimObject(name) {}
 };
-Root *root = NULL;
-
-std::ostream *
-makeOutputStream(std::string &name)
-{
-    if (name == "cerr" || name == "stderr")
-        return &std::cerr;
-
-    if (name == "cout" || name == "stdout")
-        return &std::cout;
-
-    string path = (name[0] != '/') ? outputDirectory + name : name;
-
-    // have to dynamically allocate a stream since we're going to
-    // return it... though the caller can't easily free it since it
-    // may be cerr or cout.  need GC!
-    ofstream *s = new ofstream(path.c_str(), ios::trunc);
-
-    if (!s->is_open())
-        fatal("Cannot open file %s", path);
-
-    return s;
-}
-
-
-void
-closeOutputStream(std::ostream *os)
-{
-    // can't close cerr or cout
-    if (os == &std::cerr || os == &std::cout)
-        return;
-
-    // can only close ofstreams, not generic ostreams, so try to
-    // downcast and close only if the downcast succeeds
-    std::ofstream *ofs = dynamic_cast<std::ofstream *>(os);
-    if (ofs)
-        ofs->close();
-}
-
 
 BEGIN_DECLARE_SIM_OBJECT_PARAMS(Root)
 
     Param<bool> full_system;
     Param<Tick> frequency;
-    Param<string> output_dir;
     Param<string> output_file;
-    Param<string> config_output_file;
 
 END_DECLARE_SIM_OBJECT_PARAMS(Root)
 
 BEGIN_INIT_SIM_OBJECT_PARAMS(Root)
 
-    INIT_PARAM_DFLT(full_system, "full system simulation", true),
-    INIT_PARAM_DFLT(frequency, "tick frequency", 200000000),
-    INIT_PARAM_DFLT(output_dir, "directory to output data to", "."),
-    INIT_PARAM_DFLT(output_file, "file to dump simulator output to", "cout"),
-    INIT_PARAM_DFLT(config_output_file, "file to dump simulator config to",
-                    "m5config.out")
+    INIT_PARAM(full_system, "full system simulation"),
+    INIT_PARAM(frequency, "tick frequency"),
+    INIT_PARAM(output_file, "file to dump simulator output to")
 
 END_INIT_SIM_OBJECT_PARAMS(Root)
 
 CREATE_SIM_OBJECT(Root)
 {
+    static bool created = false;
+    if (created)
+        panic("only one root object allowed!");
+
+    created = true;
+    fullSystem = full_system;
+
 #ifdef FULL_SYSTEM
-    if (!bool(full_system))
+    if (!fullSystem)
         panic("FULL_SYSTEM compiled and configuration not full_system");
 #else
-    if (bool(full_system))
+    if (fullSystem)
         panic("FULL_SYSTEM not compiled but configuration is full_system");
 #endif
 
-    if (root)
-        panic("only one root object allowed!");
-    root = new Root(getInstanceName());
-
     ticksPerSecond = frequency;
     double freq = double(ticksPerSecond);
     __ticksPerMS = freq / 1.0e3;
@@ -143,29 +99,9 @@ CREATE_SIM_OBJECT(Root)
     __ticksPerNS = freq / 1.0e9;
     __ticksPerPS = freq / 1.0e12;
 
-    outputDirectory = output_dir;
-    if (!outputDirectory.empty()) {
-        outputDirectory = output_dir;
-
-        // guarantee that directory ends with a '/'
-        if (outputDirectory[outputDirectory.size() - 1] != '/')
-            outputDirectory += "/";
-
-        if (mkdir(outputDirectory.c_str(), 0777) < 0) {
-            if (errno != EEXIST) {
-                panic("%s\ncould not make output directory: %s\n",
-                      strerror(errno), outputDirectory);
-            }
-        }
-    }
-
-    outputStream = makeOutputStream(output_file);
-    configStream = outputStream;
-    string cof = config_output_file;
-    if (!cof.empty())
-        configStream = makeOutputStream(cof);
-
-    return root;
+    outputStream = simout.find(output_file);
+
+    return new Root(getInstanceName());
 }
 
 REGISTER_SIM_OBJECT("Root", Root)