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.
This commit is contained in:
parent
4afa6c4c3e
commit
35bdee72cb
2 changed files with 126 additions and 78 deletions
|
@ -495,62 +495,91 @@ TrafficGen::StateGraph::RandomGen::nextExecuteTick()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
TrafficGen::StateGraph::TraceGen::InputStream::reset()
|
||||||
|
{
|
||||||
|
// seek to the start of the input trace file
|
||||||
|
trace.seekg(0, ifstream::beg);
|
||||||
|
trace.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
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()) {
|
||||||
|
std::istringstream iss(buffer);
|
||||||
|
|
||||||
|
char rOrW, ch;
|
||||||
|
iss >> rOrW;
|
||||||
|
if (rOrW == 'r') {
|
||||||
|
element.cmd = MemCmd::ReadReq;
|
||||||
|
} else if (rOrW == 'w') {
|
||||||
|
element.cmd = MemCmd::WriteReq;
|
||||||
|
} else {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We have reached the end of the file
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
Tick
|
Tick
|
||||||
TrafficGen::StateGraph::TraceGen::nextExecuteTick() {
|
TrafficGen::StateGraph::TraceGen::nextExecuteTick() {
|
||||||
// We need to look at the next line to calculate the next time an
|
if (traceComplete)
|
||||||
// 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
|
// 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
|
// the trace Return MaxTick to signal that there will be no
|
||||||
// more transactions in this active period for the state.
|
// more transactions in this active period for the state.
|
||||||
return MaxTick;
|
return MaxTick;
|
||||||
}
|
|
||||||
|
|
||||||
//Reset the nextElement to the default values
|
//Reset the nextElement to the default values
|
||||||
currElement = nextElement;
|
currElement = nextElement;
|
||||||
nextElement.clear();
|
nextElement.clear();
|
||||||
|
|
||||||
// Check that we have something to process. This assume no EOF at
|
// We need to look at the next line to calculate the next time an
|
||||||
// the end of the line.
|
// event occurs, or potentially return MaxTick to signal that
|
||||||
if (buffer.size() > 0 && !trace.eof()) {
|
// nothing has to be done.
|
||||||
istringstream iss(buffer);
|
if (!trace.read(nextElement)) {
|
||||||
|
|
||||||
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;
|
|
||||||
} else if (rOrW == 'w') {
|
|
||||||
nextElement.cmd = MemCmd::WriteReq;
|
|
||||||
} else {
|
|
||||||
fatal("Incorrect trace file format!\n");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
traceComplete = true;
|
traceComplete = true;
|
||||||
return MaxTick;
|
return MaxTick;
|
||||||
}
|
}
|
||||||
|
@ -577,10 +606,6 @@ TrafficGen::StateGraph::TraceGen::enter() {
|
||||||
// update the trace offset to the time where the state was entered.
|
// update the trace offset to the time where the state was entered.
|
||||||
tickOffset = curTick();
|
tickOffset = curTick();
|
||||||
|
|
||||||
// seek to the start of the input trace file
|
|
||||||
trace.seekg(0, ifstream::beg);
|
|
||||||
trace.clear();
|
|
||||||
|
|
||||||
// clear everything
|
// clear everything
|
||||||
nextElement.clear();
|
nextElement.clear();
|
||||||
currElement.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
|
// 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
|
// then we want to generate a warning stating that not the entire
|
||||||
// trace was played.
|
// trace was played.
|
||||||
if (!trace.eof()) {
|
if (!traceComplete) {
|
||||||
warn("Trace player %s was unable to replay the entire trace!\n",
|
warn("Trace player %s was unable to replay the entire trace!\n",
|
||||||
name());
|
name());
|
||||||
}
|
}
|
||||||
|
|
||||||
// clear any previous error flags for the input trace file
|
// Clear any flags and start over again from the beginning of the
|
||||||
trace.clear();
|
// file
|
||||||
|
trace.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -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:
|
public:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -454,28 +500,10 @@ class TrafficGen : public MemObject
|
||||||
Tick _duration, const std::string& trace_file,
|
Tick _duration, const std::string& trace_file,
|
||||||
Addr addr_offset)
|
Addr addr_offset)
|
||||||
: BaseGen(_port, master_id, _duration),
|
: BaseGen(_port, master_id, _duration),
|
||||||
traceFile(trace_file),
|
trace(trace_file),
|
||||||
addrOffset(addr_offset),
|
addrOffset(addr_offset),
|
||||||
traceComplete(false)
|
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();
|
void enter();
|
||||||
|
@ -494,14 +522,8 @@ class TrafficGen : public MemObject
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/** Path to the trace file */
|
|
||||||
std::string traceFile;
|
|
||||||
|
|
||||||
/** Input stream used for reading the input trace file */
|
/** Input stream used for reading the input trace file */
|
||||||
std::ifstream trace;
|
InputStream trace;
|
||||||
|
|
||||||
/** Larger buffer used for reading from the stream */
|
|
||||||
char* readBuffer;
|
|
||||||
|
|
||||||
/** Store the current and next element in the trace */
|
/** Store the current and next element in the trace */
|
||||||
TraceElement currElement;
|
TraceElement currElement;
|
||||||
|
|
Loading…
Reference in a new issue