cpu: Encapsulate traffic generator input in a stream
authorAndreas Hansson <andreas.hansson@arm.com>
Mon, 7 Jan 2013 18:05:37 +0000 (13:05 -0500)
committerAndreas Hansson <andreas.hansson@arm.com>
Mon, 7 Jan 2013 18:05:37 +0000 (13:05 -0500)
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
src/cpu/testers/traffic_gen/traffic_gen.hh

index 59a2ae6d5686656f5ea3f256040760864b7e48eb..4617f5c819733cbdda43842ac208bd8541440c38 100644 (file)
@@ -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
index 4e94df548a11f8d3907074fc9e52001f8913906a..be1cc05500cec3e8b614c01626f05e06464c8f15 100644 (file)
@@ -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;