if env['HAVE_PROTOBUF']:
SimObject('TrafficGen.py')
+ Source('generators.cc')
Source('traffic_gen.cc')
DebugFlag('TrafficGen')
--- /dev/null
+/*
+ * Copyright (c) 2012-2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Thomas Grass
+ * Andreas Hansson
+ * Sascha Bischoff
+ */
+
+#include "base/random.hh"
+#include "cpu/testers/traffic_gen/generators.hh"
+#include "debug/TrafficGen.hh"
+#include "proto/packet.pb.h"
+
+BaseGen::BaseGen(QueuedMasterPort& _port, MasterID master_id, Tick _duration)
+ : port(_port), masterID(master_id), duration(_duration)
+{
+}
+
+void
+BaseGen::send(Addr addr, unsigned size, const MemCmd& cmd)
+{
+ // Create new request
+ Request::Flags flags;
+ Request *req = new Request(addr, size, flags, masterID);
+
+ // Embed it in a packet
+ PacketPtr pkt = new Packet(req, cmd);
+
+ uint8_t* pkt_data = new uint8_t[req->getSize()];
+ pkt->dataDynamicArray(pkt_data);
+
+ if (cmd.isWrite()) {
+ memset(pkt_data, 0xA, req->getSize());
+ }
+
+ port.schedTimingReq(pkt, curTick());
+}
+
+void
+LinearGen::enter()
+{
+ // reset the address and the data counter
+ nextAddr = startAddr;
+ dataManipulated = 0;
+
+ // this test only needs to happen once, but cannot be performed
+ // before init() is called and the ports are connected
+ if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
+ fatal("TrafficGen %s block size (%d) is larger than port"
+ " block size (%d)\n", blocksize, port.deviceBlockSize());
+}
+
+void
+LinearGen::execute()
+{
+ // choose if we generate a read or a write here
+ bool isRead = readPercent != 0 &&
+ (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
+
+ assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
+ readPercent != 100);
+
+ DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
+ isRead ? 'r' : 'w', nextAddr, blocksize);
+
+ send(nextAddr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
+
+ // increment the address
+ nextAddr += blocksize;
+
+ // Add the amount of data manipulated to the total
+ dataManipulated += blocksize;
+}
+
+Tick
+LinearGen::nextExecuteTick()
+{
+ // If we have reached the end of the address space, reset the
+ // address to the start of the range
+ if (nextAddr + blocksize > endAddr) {
+ DPRINTF(TrafficGen, "Wrapping address to the start of "
+ "the range\n");
+ nextAddr = startAddr;
+ }
+
+ // Check to see if we have reached the data limit. If dataLimit is
+ // zero we do not have a data limit and therefore we will keep
+ // generating requests for the entire residency in this state.
+ if (dataLimit && dataManipulated >= dataLimit) {
+ DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
+ // there are no more requests, therefore return MaxTick
+ return MaxTick;
+ } else {
+ // return the time when the next request should take place
+ return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
+ }
+}
+
+void
+RandomGen::enter()
+{
+ // reset the counter to zero
+ dataManipulated = 0;
+
+ // this test only needs to happen once, but cannot be performed
+ // before init() is called and the ports are connected
+ if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
+ fatal("TrafficGen %s block size (%d) is larger than port"
+ " block size (%d)\n", blocksize, port.deviceBlockSize());
+}
+
+void
+RandomGen::execute()
+{
+ // choose if we generate a read or a write here
+ bool isRead = readPercent != 0 &&
+ (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
+
+ assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
+ readPercent != 100);
+
+ // address of the request
+ Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
+
+ // round down to start address of block
+ addr -= addr % blocksize;
+
+ DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
+ isRead ? 'r' : 'w', addr, blocksize);
+
+ // send a new request packet
+ send(addr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
+
+ // Add the amount of data manipulated to the total
+ dataManipulated += blocksize;
+}
+
+Tick
+RandomGen::nextExecuteTick()
+{
+ // Check to see if we have reached the data limit. If dataLimit is
+ // zero we do not have a data limit and therefore we will keep
+ // generating requests for the entire residency in this state.
+ if (dataLimit && dataManipulated >= dataLimit)
+ {
+ DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
+ // No more requests. Return MaxTick.
+ return MaxTick;
+ } else {
+ // Return the time when the next request should take place.
+ return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
+ }
+}
+
+TraceGen::InputStream::InputStream(const std::string& filename)
+ : trace(filename)
+{
+ // Create a protobuf message for the header and read it from the stream
+ Message::PacketHeader header_msg;
+ if (!trace.read(header_msg)) {
+ panic("Failed to read packet header from %s\n", filename);
+
+ if (header_msg.tick_freq() != SimClock::Frequency) {
+ panic("Trace %s was recorded with a different tick frequency %d\n",
+ header_msg.tick_freq());
+ }
+ }
+}
+
+void
+TraceGen::InputStream::reset()
+{
+ trace.reset();
+}
+
+bool
+TraceGen::InputStream::read(TraceElement& element)
+{
+ Message::Packet pkt_msg;
+ if (trace.read(pkt_msg)) {
+ element.cmd = pkt_msg.cmd();
+ element.addr = pkt_msg.addr();
+ element.blocksize = pkt_msg.size();
+ element.tick = pkt_msg.tick();
+ return true;
+ }
+
+ // We have reached the end of the file
+ return false;
+}
+
+Tick
+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;
+ }
+
+ DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
+ currElement.cmd.isRead() ? 'r' : 'w',
+ currElement.addr,
+ currElement.blocksize,
+ currElement.tick + tickOffset,
+ currElement.tick);
+
+ DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
+ nextElement.cmd.isRead() ? 'r' : 'w',
+ nextElement.addr,
+ nextElement.blocksize,
+ nextElement.tick + tickOffset,
+ nextElement.tick);
+
+ return tickOffset + nextElement.tick;
+}
+
+void
+TraceGen::enter()
+{
+ // update the trace offset to the time where the state was entered.
+ tickOffset = curTick();
+
+ // clear everything
+ nextElement.clear();
+ currElement.clear();
+
+ traceComplete = false;
+}
+
+void
+TraceGen::execute()
+{
+ // it is the responsibility of nextExecuteTick to prevent the
+ // state graph from executing the state if it should not
+ assert(currElement.isValid());
+
+ DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
+ currElement.cmd.isRead() ? 'r' : 'w',
+ currElement.addr,
+ currElement.blocksize,
+ currElement.tick);
+
+ send(currElement.addr + addrOffset, currElement.blocksize,
+ currElement.cmd);
+}
+
+void
+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 (!traceComplete) {
+ warn("Trace player %s was unable to replay the entire trace!\n",
+ name());
+ }
+
+ // Clear any flags and start over again from the beginning of the
+ // file
+ trace.reset();
+}
--- /dev/null
+/*
+ * Copyright (c) 2012-2013 ARM Limited
+ * All rights reserved
+ *
+ * The license below extends only to copyright in the software and shall
+ * not be construed as granting a license to any other intellectual
+ * property including but not limited to intellectual property relating
+ * to a hardware implementation of the functionality of the software
+ * licensed hereunder. You may use the software subject to the license
+ * terms below provided that you ensure that this notice is replicated
+ * unmodified and in its entirety in all distributions of the software,
+ * modified or unmodified, in source code or in binary form.
+ *
+ * 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.
+ *
+ * Authors: Thomas Grass
+ * Andreas Hansson
+ * Sascha Bischoff
+ */
+
+/**
+ * @file
+ * Declaration of a set of generator behaviours that are used by the
+ * stand-alone traffic generator, but can also be instantiated
+ * elsewhere.
+ */
+
+#ifndef __CPU_TRAFFIC_GEN_GENERATORS_HH__
+#define __CPU_TRAFFIC_GEN_GENERATORS_HH__
+
+#include "mem/qport.hh"
+#include "proto/protoio.hh"
+
+/**
+ * Base class for all generators, with the shared functionality and
+ * virtual functions for entering, executing and leaving the
+ * generator.
+ */
+class BaseGen
+{
+
+ protected:
+
+ /** Port used to send requests */
+ QueuedMasterPort& port;
+
+ /** The MasterID used for generating requests */
+ const MasterID masterID;
+
+ /**
+ * Create a new request and associated packet and schedule
+ * it to be sent in the current tick.
+ *
+ * @param addr Physical address to use
+ * @param size Size of the request
+ * @param cmd Memory command to send
+ */
+ void send(Addr addr, unsigned size, const MemCmd& cmd);
+
+ public:
+
+ /** Time to spend in this state */
+ const Tick duration;
+
+ /**
+ * Create a base generator.
+ *
+ * @param _port port used to send requests
+ * @param master_id MasterID set on each request
+ * @param _duration duration of this state before transitioning
+ */
+ BaseGen(QueuedMasterPort& _port, MasterID master_id,
+ Tick _duration);
+
+ virtual ~BaseGen() { }
+
+ /**
+ * Get the name, useful for DPRINTFs.
+ *
+ * @return the port name
+ */
+ std::string name() const { return port.name(); }
+
+ /**
+ * Enter this generator state.
+ */
+ virtual void enter() = 0;
+
+ /**
+ * Execute this generator state.
+ */
+ virtual void execute() = 0;
+
+ /**
+ * Exit this generator state. By default do nothing.
+ */
+ virtual void exit() { };
+
+ /**
+ * Determine the next execute tick. MaxTick means that
+ * there will not be any further event in the current
+ * activation cycle of the state.
+ *
+ * @return next tick when the state should be executed
+ */
+ virtual Tick nextExecuteTick() = 0;
+
+};
+
+/**
+ * The idle generator does nothing.
+ */
+class IdleGen : public BaseGen
+{
+
+ public:
+
+ IdleGen(QueuedMasterPort& _port, MasterID master_id,
+ Tick _duration)
+ : BaseGen(_port, master_id, _duration)
+ { }
+
+ void enter() { }
+
+ void execute() { }
+
+ Tick nextExecuteTick() { return MaxTick; }
+};
+
+/**
+ * The linear generator generates sequential requests from a
+ * start to an end address, with a fixed block size. A
+ * fraction of the requests are reads, as determined by the
+ * read percent. There is an optional data limit for when to
+ * stop generating new requests.
+ */
+class LinearGen : public BaseGen
+{
+
+ public:
+
+ /**
+ * Create a linear address sequence generator. Set
+ * min_period == max_period for a fixed inter-transaction
+ * time.
+ *
+ * @param _port port used to send requests
+ * @param master_id MasterID set on each request
+ * @param _duration duration of this state before transitioning
+ * @param start_addr Start address
+ * @param end_addr End address
+ * @param _blocksize Size used for transactions injected
+ * @param min_period Lower limit of random inter-transaction time
+ * @param max_period Upper limit of random inter-transaction time
+ * @param read_percent Percent of transactions that are reads
+ * @param data_limit Upper limit on how much data to read/write
+ */
+ LinearGen(QueuedMasterPort& _port, MasterID master_id,
+ Tick _duration, Addr start_addr, Addr end_addr,
+ Addr _blocksize, Tick min_period, Tick max_period,
+ uint8_t read_percent, Addr data_limit)
+ : BaseGen(_port, master_id, _duration),
+ startAddr(start_addr), endAddr(end_addr),
+ blocksize(_blocksize), minPeriod(min_period),
+ maxPeriod(max_period), readPercent(read_percent),
+ dataLimit(data_limit)
+ { }
+
+ void enter();
+
+ void execute();
+
+ Tick nextExecuteTick();
+
+ private:
+
+ /** Start of address range */
+ const Addr startAddr;
+
+ /** End of address range */
+ const Addr endAddr;
+
+ /** Blocksize and address increment */
+ const Addr blocksize;
+
+ /** Request generation period */
+ const Tick minPeriod;
+ const Tick maxPeriod;
+
+ /**
+ * Percent of generated transactions that should be reads
+ */
+ const uint8_t readPercent;
+
+ /** Maximum amount of data to manipulate */
+ const Addr dataLimit;
+
+ /** Address of next request */
+ Addr nextAddr;
+
+ /**
+ * Counter to determine the amount of data
+ * manipulated. Used to determine if we should continue
+ * generating requests.
+ */
+ Addr dataManipulated;
+};
+
+/**
+ * The random generator is similar to the linear one, but does
+ * not generate sequential addresses. Instead it randomly
+ * picks an address in the range, aligned to the block size.
+ */
+class RandomGen : public BaseGen
+{
+
+ public:
+
+ /**
+ * Create a random address sequence generator. Set
+ * min_period == max_period for a fixed inter-transaction
+ * time.
+ *
+ * @param _port port used to send requests
+ * @param master_id MasterID set on each request
+ * @param _duration duration of this state before transitioning
+ * @param start_addr Start address
+ * @param end_addr End address
+ * @param _blocksize Size used for transactions injected
+ * @param min_period Lower limit of random inter-transaction time
+ * @param max_period Upper limit of random inter-transaction time
+ * @param read_percent Percent of transactions that are reads
+ * @param data_limit Upper limit on how much data to read/write
+ */
+ RandomGen(QueuedMasterPort& _port, MasterID master_id,
+ Tick _duration, Addr start_addr, Addr end_addr,
+ Addr _blocksize, Tick min_period, Tick max_period,
+ uint8_t read_percent, Addr data_limit)
+ : BaseGen(_port, master_id, _duration),
+ startAddr(start_addr), endAddr(end_addr),
+ blocksize(_blocksize), minPeriod(min_period),
+ maxPeriod(max_period), readPercent(read_percent),
+ dataLimit(data_limit)
+ { }
+
+ void enter();
+
+ void execute();
+
+ Tick nextExecuteTick();
+
+ private:
+
+ /** Start of address range */
+ const Addr startAddr;
+
+ /** End of address range */
+ const Addr endAddr;
+
+ /** Block size */
+ const Addr blocksize;
+
+ /** Request generation period */
+ const Tick minPeriod;
+ const Tick maxPeriod;
+
+ /**
+ * Percent of generated transactions that should be reads
+ */
+ const uint8_t readPercent;
+
+ /** Maximum amount of data to manipulate */
+ const Addr dataLimit;
+
+ /**
+ * Counter to determine the amount of data
+ * manipulated. Used to determine if we should continue
+ * generating requests.
+ */
+ Addr dataManipulated;
+};
+
+/**
+ * The trace replay generator reads a trace file and plays
+ * back the transactions. The trace is offset with respect to
+ * the time when the state was entered.
+ */
+class TraceGen : public BaseGen
+{
+
+ private:
+
+ /**
+ * This struct stores a line in the trace file.
+ */
+ struct TraceElement {
+
+ /** Specifies if the request is to be a read or a write */
+ MemCmd cmd;
+
+ /** The address for the request */
+ Addr addr;
+
+ /** The size of the access for the request */
+ Addr blocksize;
+
+ /** The time at which the request should be sent */
+ Tick tick;
+
+ /**
+ * Check validity of this element.
+ *
+ * @return if this element is valid
+ */
+ bool isValid() const {
+ return cmd != MemCmd::InvalidCmd;
+ }
+
+ /**
+ * Make this element invalid.
+ */
+ void clear() {
+ cmd = MemCmd::InvalidCmd;
+ }
+ };
+
+ /**
+ * 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 protobuf trace
+ ProtoInputStream trace;
+
+ 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:
+
+ /**
+ * Create a trace generator.
+ *
+ * @param _port port used to send requests
+ * @param master_id MasterID set on each request
+ * @param _duration duration of this state before transitioning
+ * @param trace_file File to read the transactions from
+ * @param addr_offset Positive offset to add to trace address
+ */
+ TraceGen(QueuedMasterPort& _port, MasterID master_id,
+ Tick _duration, const std::string& trace_file,
+ Addr addr_offset)
+ : BaseGen(_port, master_id, _duration),
+ trace(trace_file),
+ addrOffset(addr_offset),
+ traceComplete(false)
+ {
+ }
+
+ void enter();
+
+ void execute();
+
+ void exit();
+
+ /**
+ * Read a line of the trace file. Returns the raw tick
+ * when the next request should be generated. If the end
+ * of the file has been reached, it returns MaxTick to
+ * indicate that there will be no more requests.
+ */
+ Tick nextExecuteTick();
+
+ private:
+
+ /** Input stream used for reading the input trace file */
+ InputStream trace;
+
+ /** Store the current and next element in the trace */
+ TraceElement currElement;
+ TraceElement nextElement;
+
+ /**
+ * Stores the time when the state was entered. This is to add an
+ * offset to the times stored in the trace file.
+ */
+ Tick tickOffset;
+
+ /**
+ * Offset for memory requests. Used to shift the trace
+ * away from the CPU address space.
+ */
+ Addr addrOffset;
+
+ /**
+ * Set to true when the trace replay for one instance of
+ * state is complete.
+ */
+ bool traceComplete;
+};
+
+#endif
#include "cpu/testers/traffic_gen/traffic_gen.hh"
#include "debug/Checkpoint.hh"
#include "debug/TrafficGen.hh"
-#include "proto/packet.pb.h"
#include "sim/stats.hh"
#include "sim/system.hh"
states[currState]->enter();
}
-TrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
- MasterID master_id,
- Tick _duration)
- : port(_port), masterID(master_id), duration(_duration)
-{
-}
-
-void
-TrafficGen::StateGraph::BaseGen::send(Addr addr, unsigned size,
- const MemCmd& cmd)
-{
- // Create new request
- Request::Flags flags;
- Request *req = new Request(addr, size, flags, masterID);
-
- // Embed it in a packet
- PacketPtr pkt = new Packet(req, cmd);
-
- uint8_t* pkt_data = new uint8_t[req->getSize()];
- pkt->dataDynamicArray(pkt_data);
-
- if (cmd.isWrite()) {
- memset(pkt_data, 0xA, req->getSize());
- }
-
- port.schedTimingReq(pkt, curTick());
-}
-
-void
-TrafficGen::StateGraph::LinearGen::enter()
-{
- // reset the address and the data counter
- nextAddr = startAddr;
- dataManipulated = 0;
-
- // this test only needs to happen once, but cannot be performed
- // before init() is called and the ports are connected
- if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
- fatal("TrafficGen %s block size (%d) is larger than port"
- " block size (%d)\n", blocksize, port.deviceBlockSize());
-
-}
-
-void
-TrafficGen::StateGraph::LinearGen::execute()
-{
- // choose if we generate a read or a write here
- bool isRead = readPercent != 0 &&
- (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
-
- assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
- readPercent != 100);
-
- DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
- isRead ? 'r' : 'w', nextAddr, blocksize);
-
- send(nextAddr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
-
- // increment the address
- nextAddr += blocksize;
-
- // Add the amount of data manipulated to the total
- dataManipulated += blocksize;
-}
-
-Tick
-TrafficGen::StateGraph::LinearGen::nextExecuteTick()
-{
- // If we have reached the end of the address space, reset the
- // address to the start of the range
- if (nextAddr + blocksize > endAddr) {
- DPRINTF(TrafficGen, "Wrapping address to the start of "
- "the range\n");
- nextAddr = startAddr;
- }
-
- // Check to see if we have reached the data limit. If dataLimit is
- // zero we do not have a data limit and therefore we will keep
- // generating requests for the entire residency in this state.
- if (dataLimit && dataManipulated >= dataLimit) {
- DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
- // there are no more requests, therefore return MaxTick
- return MaxTick;
- } else {
- // return the time when the next request should take place
- return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
- }
-}
-
-void
-TrafficGen::StateGraph::RandomGen::enter()
-{
- // reset the counter to zero
- dataManipulated = 0;
-
- // this test only needs to happen once, but cannot be performed
- // before init() is called and the ports are connected
- if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
- fatal("TrafficGen %s block size (%d) is larger than port"
- " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
-}
-
-void
-TrafficGen::StateGraph::RandomGen::execute()
-{
- // choose if we generate a read or a write here
- bool isRead = readPercent != 0 &&
- (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
-
- assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
- readPercent != 100);
-
- // address of the request
- Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
-
- // round down to start address of block
- addr -= addr % blocksize;
-
- DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
- isRead ? 'r' : 'w', addr, blocksize);
-
- // send a new request packet
- send(addr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
-
- // Add the amount of data manipulated to the total
- dataManipulated += blocksize;
-}
-
-Tick
-TrafficGen::StateGraph::RandomGen::nextExecuteTick()
-{
- // Check to see if we have reached the data limit. If dataLimit is
- // zero we do not have a data limit and therefore we will keep
- // generating requests for the entire residency in this state.
- if (dataLimit && dataManipulated >= dataLimit)
- {
- DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
- // No more requests. Return MaxTick.
- return MaxTick;
- } else {
- // Return the time when the next request should take place.
- return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
- }
-}
-
-TrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string&
- filename)
- : trace(filename)
-{
- // Create a protobuf message for the header and read it from the stream
- Message::PacketHeader header_msg;
- if (!trace.read(header_msg)) {
- panic("Failed to read packet header from %s\n", filename);
-
- if (header_msg.tick_freq() != SimClock::Frequency) {
- panic("Trace %s was recorded with a different tick frequency %d\n",
- header_msg.tick_freq());
- }
- }
-}
-
-void
-TrafficGen::StateGraph::TraceGen::InputStream::reset()
-{
- trace.reset();
-}
-
-bool
-TrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element)
-{
- Message::Packet pkt_msg;
- if (trace.read(pkt_msg)) {
- element.cmd = pkt_msg.cmd();
- element.addr = pkt_msg.addr();
- element.blocksize = pkt_msg.size();
- element.tick = pkt_msg.tick();
- return true;
- }
-
- // 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;
- }
-
- DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
- currElement.cmd.isRead() ? 'r' : 'w',
- currElement.addr,
- currElement.blocksize,
- currElement.tick + tickOffset,
- currElement.tick);
-
- DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
- nextElement.cmd.isRead() ? 'r' : 'w',
- nextElement.addr,
- nextElement.blocksize,
- nextElement.tick + tickOffset,
- nextElement.tick);
-
- return tickOffset + nextElement.tick;
-}
-
-void
-TrafficGen::StateGraph::TraceGen::enter() {
- // update the trace offset to the time where the state was entered.
- tickOffset = curTick();
-
- // clear everything
- nextElement.clear();
- currElement.clear();
-
- traceComplete = false;
-}
-
-void
-TrafficGen::StateGraph::TraceGen::execute() {
- // it is the responsibility of nextExecuteTick to prevent the
- // state graph from executing the state if it should not
- assert(currElement.isValid());
-
- DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
- currElement.cmd.isRead() ? 'r' : 'w',
- currElement.addr,
- currElement.blocksize,
- currElement.tick);
-
- send(currElement.addr + addrOffset, currElement.blocksize,
- currElement.cmd);
-}
-
-void
-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 (!traceComplete) {
- warn("Trace player %s was unable to replay the entire trace!\n",
- name());
- }
-
- // Clear any flags and start over again from the beginning of the
- // file
- trace.reset();
-}
-
bool
TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
{
* Andreas Hansson
* Sascha Bischoff
*/
-#ifndef __MEM_TRAFFIC_GEN_HH__
-#define __MEM_TRAFFIC_GEN_HH__
+#ifndef __CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__
+#define __CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__
#include "base/hashmap.hh"
+#include "cpu/testers/traffic_gen/generators.hh"
#include "mem/mem_object.hh"
#include "mem/qport.hh"
#include "params/TrafficGen.hh"
-#include "proto/protoio.hh"
/**
* The traffic generator is a master module that generates stimuli for
double p;
};
- /** Base class for all generator states */
- class BaseGen
- {
-
- protected:
-
- /** Port used to send requests */
- QueuedMasterPort& port;
-
- /** The MasterID used for generating requests */
- const MasterID masterID;
-
- /**
- * Create a new request and associated packet and schedule
- * it to be sent in the current tick.
- *
- * @param addr Physical address to use
- * @param size Size of the request
- * @param cmd Memory command to send
- */
- void send(Addr addr, unsigned size, const MemCmd& cmd);
-
- public:
-
- /** Time to spend in this state */
- const Tick duration;
-
- /**
- * Create a base generator.
- *
- * @param _port port used to send requests
- * @param master_id MasterID set on each request
- * @param _duration duration of this state before transitioning
- */
- BaseGen(QueuedMasterPort& _port, MasterID master_id,
- Tick _duration);
-
- virtual ~BaseGen() { }
-
- /**
- * Get the name, useful for DPRINTFs.
- *
- * @return the port name
- */
- std::string name() const { return port.name(); }
-
- /**
- * Enter this generator state.
- */
- virtual void enter() = 0;
-
- /**
- * Execute this generator state.
- */
- virtual void execute() = 0;
-
- /**
- * Exit this generator state. By default do nothing.
- */
- virtual void exit() { };
-
- /**
- * Determine the next execute tick. MaxTick means that
- * there will not be any further event in the current
- * activation cycle of the state.
- *
- * @return next tick when the state should be executed
- */
- virtual Tick nextExecuteTick() = 0;
-
- };
-
- /**
- * The idle generator does nothing.
- */
- class IdleGen : public BaseGen
- {
-
- public:
-
- IdleGen(QueuedMasterPort& _port, MasterID master_id,
- Tick _duration)
- : BaseGen(_port, master_id, _duration)
- { }
-
- void enter() { }
-
- void execute() { }
-
- Tick nextExecuteTick() { return MaxTick; }
- };
-
- /**
- * The linear generator generates sequential requests from a
- * start to an end address, with a fixed block size. A
- * fraction of the requests are reads, as determined by the
- * read percent. There is an optional data limit for when to
- * stop generating new requests.
- */
- class LinearGen : public BaseGen
- {
-
- public:
-
- /**
- * Create a linear address sequence generator. Set
- * min_period == max_period for a fixed inter-transaction
- * time.
- *
- * @param _port port used to send requests
- * @param master_id MasterID set on each request
- * @param _duration duration of this state before transitioning
- * @param start_addr Start address
- * @param end_addr End address
- * @param _blocksize Size used for transactions injected
- * @param min_period Lower limit of random inter-transaction time
- * @param max_period Upper limit of random inter-transaction time
- * @param read_percent Percent of transactions that are reads
- * @param data_limit Upper limit on how much data to read/write
- */
- LinearGen(QueuedMasterPort& _port, MasterID master_id,
- Tick _duration, Addr start_addr, Addr end_addr,
- Addr _blocksize, Tick min_period, Tick max_period,
- uint8_t read_percent, Addr data_limit)
- : BaseGen(_port, master_id, _duration),
- startAddr(start_addr), endAddr(end_addr),
- blocksize(_blocksize), minPeriod(min_period),
- maxPeriod(max_period), readPercent(read_percent),
- dataLimit(data_limit)
- { }
-
- void enter();
-
- void execute();
-
- Tick nextExecuteTick();
-
- private:
-
- /** Start of address range */
- const Addr startAddr;
-
- /** End of address range */
- const Addr endAddr;
-
- /** Blocksize and address increment */
- const Addr blocksize;
-
- /** Request generation period */
- const Tick minPeriod;
- const Tick maxPeriod;
-
- /**
- * Percent of generated transactions that should be reads
- */
- const uint8_t readPercent;
-
- /** Maximum amount of data to manipulate */
- const Addr dataLimit;
-
- /** Address of next request */
- Addr nextAddr;
-
- /**
- * Counter to determine the amount of data
- * manipulated. Used to determine if we should continue
- * generating requests.
- */
- Addr dataManipulated;
- };
-
- /**
- * The random generator is similar to the linear one, but does
- * not generate sequential addresses. Instead it randomly
- * picks an address in the range, aligned to the block size.
- */
- class RandomGen : public BaseGen
- {
-
- public:
-
- /**
- * Create a random address sequence generator. Set
- * min_period == max_period for a fixed inter-transaction
- * time.
- *
- * @param _port port used to send requests
- * @param master_id MasterID set on each request
- * @param _duration duration of this state before transitioning
- * @param start_addr Start address
- * @param end_addr End address
- * @param _blocksize Size used for transactions injected
- * @param min_period Lower limit of random inter-transaction time
- * @param max_period Upper limit of random inter-transaction time
- * @param read_percent Percent of transactions that are reads
- * @param data_limit Upper limit on how much data to read/write
- */
- RandomGen(QueuedMasterPort& _port, MasterID master_id,
- Tick _duration, Addr start_addr, Addr end_addr,
- Addr _blocksize, Tick min_period, Tick max_period,
- uint8_t read_percent, Addr data_limit)
- : BaseGen(_port, master_id, _duration),
- startAddr(start_addr), endAddr(end_addr),
- blocksize(_blocksize), minPeriod(min_period),
- maxPeriod(max_period), readPercent(read_percent),
- dataLimit(data_limit)
- { }
-
- void enter();
-
- void execute();
-
- Tick nextExecuteTick();
-
- private:
-
- /** Start of address range */
- const Addr startAddr;
-
- /** End of address range */
- const Addr endAddr;
-
- /** Block size */
- const Addr blocksize;
-
- /** Request generation period */
- const Tick minPeriod;
- const Tick maxPeriod;
-
- /**
- * Percent of generated transactions that should be reads
- */
- const uint8_t readPercent;
-
- /** Maximum amount of data to manipulate */
- const Addr dataLimit;
-
- /**
- * Counter to determine the amount of data
- * manipulated. Used to determine if we should continue
- * generating requests.
- */
- Addr dataManipulated;
- };
-
- /**
- * The trace replay generator reads a trace file and plays
- * back the transactions. The trace is offset with respect to
- * the time when the state was entered.
- */
- class TraceGen : public BaseGen
- {
-
- private:
-
- /**
- * This struct stores a line in the trace file.
- */
- struct TraceElement {
-
- /** Specifies if the request is to be a read or a write */
- MemCmd cmd;
-
- /** The address for the request */
- Addr addr;
-
- /** The size of the access for the request */
- Addr blocksize;
-
- /** The time at which the request should be sent */
- Tick tick;
-
- /**
- * Check validity of this element.
- *
- * @return if this element is valid
- */
- bool isValid() const {
- return cmd != MemCmd::InvalidCmd;
- }
-
- /**
- * Make this element invalid.
- */
- void clear() {
- cmd = MemCmd::InvalidCmd;
- }
- };
-
- /**
- * 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 protobuf trace
- ProtoInputStream trace;
-
- 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:
-
- /**
- * Create a trace generator.
- *
- * @param _port port used to send requests
- * @param master_id MasterID set on each request
- * @param _duration duration of this state before transitioning
- * @param trace_file File to read the transactions from
- * @param addr_offset Positive offset to add to trace address
- */
- TraceGen(QueuedMasterPort& _port, MasterID master_id,
- Tick _duration, const std::string& trace_file,
- Addr addr_offset)
- : BaseGen(_port, master_id, _duration),
- trace(trace_file),
- addrOffset(addr_offset),
- traceComplete(false)
- {
- }
-
- void enter();
-
- void execute();
-
- void exit();
-
- /**
- * Read a line of the trace file. Returns the raw tick
- * when the next request should be generated. If the end
- * of the file has been reached, it returns MaxTick to
- * indicate that there will be no more requests.
- */
- Tick nextExecuteTick();
-
- private:
-
- /** Input stream used for reading the input trace file */
- InputStream trace;
-
- /** Store the current and next element in the trace */
- TraceElement currElement;
- TraceElement nextElement;
-
- /**
- * Stores the time when the state was entered. This is to add an
- * offset to the times stored in the trace file.
- */
- Tick tickOffset;
-
- /**
- * Offset for memory requests. Used to shift the trace
- * away from the CPU address space.
- */
- Addr addrOffset;
-
- /**
- * Set to true when the trace replay for one instance of
- * state is complete.
- */
- bool traceComplete;
- };
-
/** Pointer to owner of request handler */
TrafficGen& owner;
};
-#endif //__MEM_TRAFFIC_GEN_HH__
+#endif //__CPU_TRAFFIC_GEN_TRAFFIC_GEN_HH__