From 35bdee72cbbced98bb93f9e5310c4dbd014dd911 Mon Sep 17 00:00:00 2001 From: Andreas Hansson Date: Mon, 7 Jan 2013 13:05:37 -0500 Subject: [PATCH] cpu: Encapsulate traffic generator input in a stream This patch encapsulates the traffic generator input in a stream class such that the parsing is not visible to the trace generator. The change takes us one step closer to using protobuf-based input traces for the trace replay. The functionality of the current input stream is identical to what it was, and the ASCII format remains the same for now. --- src/cpu/testers/traffic_gen/traffic_gen.cc | 122 +++++++++++++-------- src/cpu/testers/traffic_gen/traffic_gen.hh | 74 ++++++++----- 2 files changed, 122 insertions(+), 74 deletions(-) diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc index 59a2ae6d5..4617f5c81 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.cc +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc @@ -495,62 +495,91 @@ TrafficGen::StateGraph::RandomGen::nextExecuteTick() } } -Tick -TrafficGen::StateGraph::TraceGen::nextExecuteTick() { - // We need to look at the next line to calculate the next time an - // event occurs, or potentially return MaxTick to signal that - // nothing has to be done. - string buffer; - if (!traceComplete && trace.good()){ - getline(trace, buffer); - DPRINTF(TrafficGen, "Input trace: %s\n", buffer); - } else { - // We are at the end of the file, thus we have no more data in - // the trace Return MaxTick to signal that there will be no - // more transactions in this active period for the state. - return MaxTick; +TrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string& + filename) +{ + trace.rdbuf()->pubsetbuf(readBuffer, 4 * 1024 * 1024); + trace.open(filename.c_str(), ifstream::in); + + if (!trace.is_open()) { + fatal("Traffic generator trace file could not be" + " opened: %s\n", filename); } +} - //Reset the nextElement to the default values - currElement = nextElement; - nextElement.clear(); +void +TrafficGen::StateGraph::TraceGen::InputStream::reset() +{ + // seek to the start of the input trace file + trace.seekg(0, ifstream::beg); + trace.clear(); +} - // Check that we have something to process. This assume no EOF at +bool +TrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element) +{ + string buffer; + bool format_error = false; + assert(trace.good()); + getline(trace, buffer); + + // Check that we have something to process. This assumes no EOF at // the end of the line. if (buffer.size() > 0 && !trace.eof()) { - istringstream iss(buffer); + std::istringstream iss(buffer); char rOrW, ch; iss >> rOrW; - iss >> ch; assert(ch == ','); - iss >> nextElement.addr; - iss >> ch; assert(ch == ','); - iss >> nextElement.blocksize; - iss >> ch; assert(ch == ','); - iss >> nextElement.tick; - if (rOrW == 'r') { - nextElement.cmd = MemCmd::ReadReq; + element.cmd = MemCmd::ReadReq; } else if (rOrW == 'w') { - nextElement.cmd = MemCmd::WriteReq; + element.cmd = MemCmd::WriteReq; } else { - fatal("Incorrect trace file format!\n"); + format_error = true; } + + // eat a comma, then get the address + iss >> ch; + format_error |= ch != ','; + iss >> element.addr; + + // eat a comma, then get the blocksize + iss >> ch; + format_error |= ch != ','; + iss >> element.blocksize; + + // eat a comma, then get the tick + iss >> ch; + format_error |= ch != ','; + iss >> element.tick; + + if (format_error) + fatal("Trace format error in %s\n", buffer); + + return true; } - // Check that we have a valid request - if (!nextElement.isValid()) { - // If it is not valid, assume that we have reached the end of - // the trace. Even if this is not the case, we do not know - // what to do with the request as it makes no sense. - if (trace.good()) { - // Trace is good, therefore we are not at the end of the - // file. This means that the input trace cannot be read - // correctly or it contains data that makes no sense. - warn("Unable to read the trace file format\n"); - warn("%s", buffer); - } + // We have reached the end of the file + return false; +} + +Tick +TrafficGen::StateGraph::TraceGen::nextExecuteTick() { + if (traceComplete) + // We are at the end of the file, thus we have no more data in + // the trace Return MaxTick to signal that there will be no + // more transactions in this active period for the state. + return MaxTick; + + //Reset the nextElement to the default values + currElement = nextElement; + nextElement.clear(); + + // We need to look at the next line to calculate the next time an + // event occurs, or potentially return MaxTick to signal that + // nothing has to be done. + if (!trace.read(nextElement)) { traceComplete = true; return MaxTick; } @@ -577,10 +606,6 @@ TrafficGen::StateGraph::TraceGen::enter() { // update the trace offset to the time where the state was entered. tickOffset = curTick(); - // seek to the start of the input trace file - trace.seekg(0, ifstream::beg); - trace.clear(); - // clear everything nextElement.clear(); currElement.clear(); @@ -621,13 +646,14 @@ TrafficGen::StateGraph::TraceGen::exit() { // Check if we reached the end of the trace file. If we did not // then we want to generate a warning stating that not the entire // trace was played. - if (!trace.eof()) { + if (!traceComplete) { warn("Trace player %s was unable to replay the entire trace!\n", name()); } - // clear any previous error flags for the input trace file - trace.clear(); + // Clear any flags and start over again from the beginning of the + // file + trace.reset(); } bool diff --git a/src/cpu/testers/traffic_gen/traffic_gen.hh b/src/cpu/testers/traffic_gen/traffic_gen.hh index 4e94df548..be1cc0550 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.hh +++ b/src/cpu/testers/traffic_gen/traffic_gen.hh @@ -439,6 +439,52 @@ class TrafficGen : public MemObject } }; + /** + * The InputStream encapsulates a trace file and the + * internal buffers and populates TraceElements based on + * the input. + */ + class InputStream + { + + private: + + /// Input file stream for the ASCII trace + std::ifstream trace; + + /** + * Create a 4MB read buffer for the input trace + * file. This is to reduce the number of disk accesses + * and thereby speed up the execution. + */ + char readBuffer[4 * 1024 * 1024]; + + public: + + /** + * Create a trace input stream for a given file name. + * + * @param filename Path to the file to read from + */ + InputStream(const std::string& filename); + + /** + * Reset the stream such that it can be played once + * again. + */ + void reset(); + + /** + * Attempt to read a trace element from the stream, + * and also notify the caller if the end of the file + * was reached. + * + * @param element Trace element to populate + * @return True if an element could be read successfully + */ + bool read(TraceElement& element); + }; + public: /** @@ -454,28 +500,10 @@ class TrafficGen : public MemObject Tick _duration, const std::string& trace_file, Addr addr_offset) : BaseGen(_port, master_id, _duration), - traceFile(trace_file), + trace(trace_file), addrOffset(addr_offset), traceComplete(false) { - /** - * Create a 4MB read buffer for the input trace - * file. This is to reduce the number of disk accesses - * and thereby speed up the execution of the code. - */ - readBuffer = new char[4 * 1024 * 1024]; - trace.rdbuf()->pubsetbuf(readBuffer, 4 * 1024 * 1024); - trace.open(traceFile.c_str(), std::ifstream::in); - - if (!trace.is_open()) { - fatal("Traffic generator %s trace file could not be" - " opened: %s\n", name(), traceFile); - } - } - - ~TraceGen() { - // free the memory used by the readBuffer - delete[] readBuffer; } void enter(); @@ -494,14 +522,8 @@ class TrafficGen : public MemObject private: - /** Path to the trace file */ - std::string traceFile; - /** Input stream used for reading the input trace file */ - std::ifstream trace; - - /** Larger buffer used for reading from the stream */ - char* readBuffer; + InputStream trace; /** Store the current and next element in the trace */ TraceElement currElement; -- 2.30.2