Clean up/standardize handling of various output files.
No more non-intuitive behavior shifts depending on whether outputDirectory is set (at the expense of backwards compatibility). outputDirectory is now always valid, defaults to ".". dev/etherdump.cc: Use makeOutputStream() to create output file. New behavior: actually complain if dump file can't be opened, instead of quietly ignoring the problem. dev/etherdump.hh: dev/simconsole.cc: dev/simconsole.hh: Use makeOutputStream() to create output file. sim/builder.cc: sim/builder.hh: sim/main.cc: builderStream() is now *configStream. sim/serialize.cc: outputDirectory is now always valid, no need to check. sim/universe.cc: Clean up/standardize handling of various output files. No more non-intuitive behavior shifts depending on whether outputDirectory is set (at the expense of backwards compatibility). outputDirectory is now always valid, defaults to ".". New function makeOutputStream() does "the right thing" to associate a stream with a filename. --HG-- extra : convert_revision : a03c58c547221b3906e0d6f55e4a569843f2d646
This commit is contained in:
parent
f0aed43b93
commit
f267dc4a87
9 changed files with 86 additions and 110 deletions
|
@ -42,11 +42,9 @@
|
|||
|
||||
using std::string;
|
||||
|
||||
EtherDump::EtherDump(const string &name, const string &file, int max)
|
||||
: SimObject(name), maxlen(max)
|
||||
EtherDump::EtherDump(const string &name, std::ostream *_stream, int max)
|
||||
: SimObject(name), stream(_stream), maxlen(max)
|
||||
{
|
||||
if (!file.empty())
|
||||
stream.open(file.c_str());
|
||||
}
|
||||
|
||||
#define DLT_EN10MB 1 // Ethernet (10Mb)
|
||||
|
@ -74,9 +72,6 @@ struct pcap_pkthdr {
|
|||
void
|
||||
EtherDump::init()
|
||||
{
|
||||
if (!stream.is_open())
|
||||
return;
|
||||
|
||||
curtime = time(NULL);
|
||||
s_freq = ticksPerSecond;
|
||||
us_freq = ticksPerSecond / ULL(1000000);
|
||||
|
@ -91,7 +86,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
|
||||
|
@ -103,9 +98,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
|
||||
|
@ -116,9 +111,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)
|
||||
|
@ -130,28 +125,14 @@ END_DECLARE_SIM_OBJECT_PARAMS(EtherDump)
|
|||
|
||||
BEGIN_INIT_SIM_OBJECT_PARAMS(EtherDump)
|
||||
|
||||
INIT_PARAM(file, "file to dump packets to"),
|
||||
INIT_PARAM_DFLT(file, "file to dump packets to", "etherdump"),
|
||||
INIT_PARAM_DFLT(maxlen, "max portion of packet data to dump", 96)
|
||||
|
||||
END_INIT_SIM_OBJECT_PARAMS(EtherDump)
|
||||
|
||||
CREATE_SIM_OBJECT(EtherDump)
|
||||
{
|
||||
string filename;
|
||||
if (file.isValid()) {
|
||||
filename = file;
|
||||
|
||||
if (filename[0] != '/' && !outputDirectory.empty())
|
||||
filename = outputDirectory + filename;
|
||||
} else {
|
||||
if (outputDirectory.empty()) {
|
||||
filename = "etherdump";
|
||||
} else {
|
||||
filename = outputDirectory + "etherdump";
|
||||
}
|
||||
}
|
||||
|
||||
return new EtherDump(getInstanceName(), filename, maxlen);
|
||||
return new EtherDump(getInstanceName(), makeOutputStream(file), maxlen);
|
||||
}
|
||||
|
||||
REGISTER_SIM_OBJECT("EtherDump", EtherDump)
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
class EtherDump : public SimObject
|
||||
{
|
||||
private:
|
||||
std::ofstream stream;
|
||||
std::ostream *stream;
|
||||
const int maxlen;
|
||||
void dumpPacket(PacketPtr &packet);
|
||||
void init();
|
||||
|
@ -53,9 +53,9 @@ class EtherDump : public SimObject
|
|||
Tick us_freq;
|
||||
|
||||
public:
|
||||
EtherDump(const std::string &name, const std::string &file, int max);
|
||||
EtherDump(const std::string &name, std::ostream *_stream, int max);
|
||||
|
||||
inline void dump(PacketPtr &pkt) { if (stream.is_open()) dumpPacket(pkt); }
|
||||
inline void dump(PacketPtr &pkt) { dumpPacket(pkt); }
|
||||
};
|
||||
|
||||
#endif // __ETHERDUMP_H__
|
||||
|
|
|
@ -72,27 +72,22 @@ SimConsole::Event::process(int revent)
|
|||
cons->detach();
|
||||
}
|
||||
|
||||
SimConsole::SimConsole(const string &name, const string &file, int num)
|
||||
SimConsole::SimConsole(const string &name, std::ostream *os, int num)
|
||||
: SimObject(name), event(NULL), number(num), in_fd(-1), out_fd(-1),
|
||||
listener(NULL), txbuf(16384), rxbuf(16384), outfile(NULL)
|
||||
listener(NULL), txbuf(16384), rxbuf(16384), outfile(os)
|
||||
#if TRACING_ON == 1
|
||||
, linebuf(16384)
|
||||
#endif
|
||||
{
|
||||
if (!file.empty())
|
||||
outfile = new ofstream(file.c_str());
|
||||
|
||||
if (outfile)
|
||||
outfile->setf(ios::unitbuf);
|
||||
|
||||
}
|
||||
|
||||
SimConsole::~SimConsole()
|
||||
{
|
||||
close();
|
||||
|
||||
if (outfile)
|
||||
delete outfile;
|
||||
closeOutputStream(outfile);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -311,7 +306,7 @@ BEGIN_INIT_SIM_OBJECT_PARAMS(SimConsole)
|
|||
|
||||
INIT_PARAM(listener, "console listener"),
|
||||
INIT_PARAM(intr_control, "interrupt controller"),
|
||||
INIT_PARAM_DFLT(output, "file to dump output to", ""),
|
||||
INIT_PARAM(output, "file to dump output to"),
|
||||
INIT_PARAM_DFLT(append_name, "append name() to filename", true),
|
||||
INIT_PARAM_DFLT(number, "console number", 0)
|
||||
|
||||
|
@ -319,18 +314,18 @@ END_INIT_SIM_OBJECT_PARAMS(SimConsole)
|
|||
|
||||
CREATE_SIM_OBJECT(SimConsole)
|
||||
{
|
||||
string filename = output;
|
||||
if (filename.empty()) {
|
||||
if (!outputDirectory.empty())
|
||||
filename = outputDirectory + getInstanceName();
|
||||
string filename;
|
||||
|
||||
if (!output.isValid()) {
|
||||
filename = getInstanceName();
|
||||
} else if (append_name) {
|
||||
filename = (string)output + "." + getInstanceName();
|
||||
} else {
|
||||
if (append_name)
|
||||
filename += "." + getInstanceName();
|
||||
if (!outputDirectory.empty())
|
||||
filename = outputDirectory + filename;
|
||||
filename = output;
|
||||
}
|
||||
|
||||
SimConsole *console = new SimConsole(getInstanceName(), filename, number);
|
||||
SimConsole *console = new SimConsole(getInstanceName(),
|
||||
makeOutputStream(filename), number);
|
||||
((ConsoleListener *)listener)->add(console);
|
||||
|
||||
return console;
|
||||
|
|
|
@ -70,7 +70,7 @@ class SimConsole : public SimObject
|
|||
ConsoleListener *listener;
|
||||
|
||||
public:
|
||||
SimConsole(const std::string &name, const std::string &file, int num);
|
||||
SimConsole(const std::string &name, std::ostream *os, int num);
|
||||
~SimConsole();
|
||||
|
||||
protected:
|
||||
|
|
|
@ -39,26 +39,6 @@
|
|||
|
||||
using namespace std;
|
||||
|
||||
|
||||
ostream &
|
||||
builderStream()
|
||||
{
|
||||
static ofstream file;
|
||||
static ostream *stream = NULL;
|
||||
|
||||
if (!stream) {
|
||||
if (!outputDirectory.empty()) {
|
||||
string filename = outputDirectory + "builder.txt";
|
||||
file.open(filename.c_str());
|
||||
stream = &file;
|
||||
} else {
|
||||
stream = outputStream;
|
||||
}
|
||||
}
|
||||
|
||||
return *stream;
|
||||
}
|
||||
|
||||
SimObjectBuilder::SimObjectBuilder(const string &_configClass,
|
||||
const string &_instanceName,
|
||||
ConfigNode *_configNode,
|
||||
|
@ -187,10 +167,10 @@ SimObjectClass::createObject(IniFile &configDB,
|
|||
|
||||
// echo object parameters to stats file (for documenting the
|
||||
// config used to generate the associated stats)
|
||||
builderStream() << "[" << object->name() << "]" << endl;
|
||||
builderStream() << "type=" << simObjClassName << endl;
|
||||
objectBuilder->showParams(builderStream());
|
||||
builderStream() << endl;
|
||||
*configStream << "[" << object->name() << "]" << endl;
|
||||
*configStream << "type=" << simObjClassName << endl;
|
||||
objectBuilder->showParams(*configStream);
|
||||
*configStream << endl;
|
||||
|
||||
// done with the SimObjectBuilder now
|
||||
delete objectBuilder;
|
||||
|
|
|
@ -38,9 +38,6 @@
|
|||
|
||||
class SimObject;
|
||||
|
||||
std::ostream &
|
||||
builderStream();
|
||||
|
||||
//
|
||||
// A SimObjectBuilder serves as an evaluation context for a set of
|
||||
// parameters that describe a specific instance of a SimObject. This
|
||||
|
|
|
@ -396,7 +396,7 @@ main(int argc, char **argv)
|
|||
|
||||
// Echo command line and all parameter settings to stats file as well.
|
||||
echoCommandLine(argc, argv, *outputStream);
|
||||
ParamContext::showAllContexts(builderStream());
|
||||
ParamContext::showAllContexts(*configStream);
|
||||
|
||||
// Now process the configuration hierarchy and create the SimObjects.
|
||||
ConfigHierarchy configHierarchy(simConfigDB);
|
||||
|
|
|
@ -335,9 +335,6 @@ SerializeParamContext::checkParams()
|
|||
if (serialize_dir.isValid()) {
|
||||
checkpointDirBase = serialize_dir;
|
||||
} else {
|
||||
if (outputDirectory.empty())
|
||||
checkpointDirBase = "m5.%012d";
|
||||
else
|
||||
checkpointDirBase = outputDirectory + "cpt.%012d";
|
||||
}
|
||||
|
||||
|
|
|
@ -51,12 +51,10 @@ double __ticksPerPS;
|
|||
|
||||
string outputDirectory;
|
||||
ostream *outputStream;
|
||||
ostream *configStream;
|
||||
|
||||
class UniverseParamContext : public ParamContext
|
||||
{
|
||||
private:
|
||||
ofstream outputFile;
|
||||
|
||||
public:
|
||||
UniverseParamContext(const string &is) : ParamContext(is) {}
|
||||
void checkParams();
|
||||
|
@ -68,9 +66,14 @@ Param<Tick> universe_freq(&universe, "frequency", "tick frequency",
|
|||
200000000);
|
||||
|
||||
Param<string> universe_output_dir(&universe, "output_dir",
|
||||
"directory to output data to");
|
||||
"directory to output data to",
|
||||
".");
|
||||
Param<string> universe_output_file(&universe, "output_file",
|
||||
"file to dump simulator output to");
|
||||
"file to dump simulator output to",
|
||||
"cout");
|
||||
Param<string> universe_config_output_file(&universe, "config_output_file",
|
||||
"file to dump simulator config to",
|
||||
"m5config.out");
|
||||
|
||||
void
|
||||
UniverseParamContext::checkParams()
|
||||
|
@ -97,26 +100,49 @@ UniverseParamContext::checkParams()
|
|||
}
|
||||
}
|
||||
|
||||
string filename;
|
||||
if (universe_output_file.isValid()) {
|
||||
string f = universe_output_file;
|
||||
if (f != "stdout" && f != "cout" && f != "stderr" && f != "cerr")
|
||||
filename = outputDirectory + f;
|
||||
else
|
||||
filename = f;
|
||||
} else {
|
||||
if (outputDirectory.empty())
|
||||
filename = "stdout";
|
||||
else
|
||||
filename = outputDirectory + "output.txt";
|
||||
outputStream = makeOutputStream(universe_output_file);
|
||||
configStream = universe_config_output_file.isValid()
|
||||
? makeOutputStream(universe_config_output_file)
|
||||
: outputStream;
|
||||
}
|
||||
|
||||
if (filename == "stdout" || filename == "cout")
|
||||
outputStream = &cout;
|
||||
else if (filename == "stderr" || filename == "cerr")
|
||||
outputStream = &cerr;
|
||||
else {
|
||||
outputFile.open(filename.c_str(), ios::trunc);
|
||||
outputStream = &outputFile;
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue