From 0793a1bbdc190a7bd41b7ed81ef8291ceaeb722e Mon Sep 17 00:00:00 2001 From: Andreas Sandberg Date: Thu, 26 Apr 2018 18:16:53 +0100 Subject: cpu: Split the traffic generator into two classes The traffic generator currently assumes that it is always driven from a configuration file. Split it into a base class (BaseTrafficGen) that handles basic packet generation and a derived class that implements the config handling (TrafficGen). Change-Id: I9407f04c40ad7e40a263c8d1ef29d37ff8e6f1b4 Signed-off-by: Andreas Sandberg Reviewed-by: Nikos Nikoleris Reviewed-on: https://gem5-review.googlesource.com/11515 --- src/cpu/testers/traffic_gen/traffic_gen.cc | 275 +++++------------------------ 1 file changed, 43 insertions(+), 232 deletions(-) (limited to 'src/cpu/testers/traffic_gen/traffic_gen.cc') diff --git a/src/cpu/testers/traffic_gen/traffic_gen.cc b/src/cpu/testers/traffic_gen/traffic_gen.cc index d262fd9f7..b3f73e2e5 100644 --- a/src/cpu/testers/traffic_gen/traffic_gen.cc +++ b/src/cpu/testers/traffic_gen/traffic_gen.cc @@ -1,5 +1,5 @@ /* - * Copyright (c) 2012-2013, 2016-2017 ARM Limited + * Copyright (c) 2012-2013, 2016-2018 ARM Limited * All rights reserved * * The license below extends only to copyright in the software and shall @@ -47,29 +47,24 @@ #include "base/intmath.hh" #include "base/random.hh" -#include "debug/Checkpoint.hh" +#include "cpu/testers/traffic_gen/dram_gen.hh" +#include "cpu/testers/traffic_gen/dram_rot_gen.hh" +#include "cpu/testers/traffic_gen/exit_gen.hh" +#include "cpu/testers/traffic_gen/idle_gen.hh" +#include "cpu/testers/traffic_gen/linear_gen.hh" +#include "cpu/testers/traffic_gen/random_gen.hh" +#include "cpu/testers/traffic_gen/trace_gen.hh" #include "debug/TrafficGen.hh" +#include "params/TrafficGen.hh" #include "sim/stats.hh" #include "sim/system.hh" using namespace std; TrafficGen::TrafficGen(const TrafficGenParams* p) - : MemObject(p), - system(p->system), - masterID(system->getMasterId(this)), + : BaseTrafficGen(p), configFile(p->config_file), - elasticReq(p->elastic_req), - progressCheck(p->progress_check), - noProgressEvent([this]{ noProgress(); }, name()), - nextTransitionTick(0), - nextPacketTick(0), - currState(0), - port(name() + ".port", *this), - retryPkt(NULL), - retryPktTick(0), - updateEvent([this]{ update(); }, name()), - numSuppressed(0) + currState(0) { } @@ -79,156 +74,46 @@ TrafficGenParams::create() return new TrafficGen(this); } -BaseMasterPort& -TrafficGen::getMasterPort(const string& if_name, PortID idx) -{ - if (if_name == "port") { - return port; - } else { - return MemObject::getMasterPort(if_name, idx); - } -} - void TrafficGen::init() { - if (!port.isConnected()) - fatal("The port of %s is not connected!\n", name()); - - // if the system is in timing mode active the request generator - if (system->isTimingMode()) { - DPRINTF(TrafficGen, "Timing mode, activating request generator\n"); - - parseConfig(); + BaseTrafficGen::init(); - // enter initial state - enterState(currState); - } else { - DPRINTF(TrafficGen, - "Traffic generator is only active in timing mode\n"); - } + parseConfig(); } void TrafficGen::initState() { + BaseTrafficGen::initState(); + // when not restoring from a checkpoint, make sure we kick things off if (system->isTimingMode()) { - // call nextPacketTick on the state to advance it - nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); - schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick)); + DPRINTF(TrafficGen, "Timing mode, activating request generator\n"); + start(); } else { DPRINTF(TrafficGen, "Traffic generator is only active in timing mode\n"); } } -DrainState -TrafficGen::drain() -{ - if (!updateEvent.scheduled()) { - // no event has been scheduled yet (e.g. switched from atomic mode) - return DrainState::Drained; - } - - if (retryPkt == NULL) { - // shut things down - nextPacketTick = MaxTick; - nextTransitionTick = MaxTick; - deschedule(updateEvent); - return DrainState::Drained; - } else { - return DrainState::Draining; - } -} - void TrafficGen::serialize(CheckpointOut &cp) const { - DPRINTF(Checkpoint, "Serializing TrafficGen\n"); - - // save ticks of the graph event if it is scheduled - Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0; - - DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent); - - SERIALIZE_SCALAR(nextEvent); - - SERIALIZE_SCALAR(nextTransitionTick); - - SERIALIZE_SCALAR(nextPacketTick); - SERIALIZE_SCALAR(currState); + + BaseTrafficGen::serialize(cp); } void TrafficGen::unserialize(CheckpointIn &cp) { - // restore scheduled events - Tick nextEvent; - UNSERIALIZE_SCALAR(nextEvent); - if (nextEvent != 0) { - schedule(updateEvent, nextEvent); - } - - UNSERIALIZE_SCALAR(nextTransitionTick); - - UNSERIALIZE_SCALAR(nextPacketTick); - // @todo In the case of a stateful generator state such as the // trace player we would also have to restore the position in the // trace playback and the tick offset UNSERIALIZE_SCALAR(currState); -} -void -TrafficGen::update() -{ - // shift our progress-tracking event forward - reschedule(noProgressEvent, curTick() + progressCheck, true); - - // if we have reached the time for the next state transition, then - // perform the transition - if (curTick() >= nextTransitionTick) { - transition(); - } else { - assert(curTick() >= nextPacketTick); - // get the next packet and try to send it - PacketPtr pkt = states[currState]->getNextPacket(); - - // suppress packets that are not destined for a memory, such as - // device accesses that could be part of a trace - if (system->isMemAddr(pkt->getAddr())) { - numPackets++; - if (!port.sendTimingReq(pkt)) { - retryPkt = pkt; - retryPktTick = curTick(); - } - } else { - DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n", - pkt->cmdString(), pkt->getAddr()); - - ++numSuppressed; - if (numSuppressed % 10000) - warn("%s suppressed %d packets with non-memory addresses\n", - name(), numSuppressed); - - delete pkt; - pkt = nullptr; - } - } - - // if we are waiting for a retry, do not schedule any further - // events, in the case of a transition or a successful send, go - // ahead and determine when the next update should take place - if (retryPkt == NULL) { - // schedule next update event based on either the next execute - // tick or the next transition, which ever comes first - nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); - Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); - DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick); - schedule(updateEvent, nextEventTick); - } + BaseTrafficGen::unserialize(cp); } std::string @@ -298,14 +183,14 @@ TrafficGen::parseConfig() is >> traceFile >> addrOffset; traceFile = resolveFile(traceFile); - states[id] = new TraceGen(name(), masterID, duration, - traceFile, addrOffset); + states[id].reset(new TraceGen(name(), masterID, duration, + traceFile, addrOffset)); DPRINTF(TrafficGen, "State: %d TraceGen\n", id); } else if (mode == "IDLE") { - states[id] = new IdleGen(name(), masterID, duration); + states[id].reset(new IdleGen(name(), masterID, duration)); DPRINTF(TrafficGen, "State: %d IdleGen\n", id); } else if (mode == "EXIT") { - states[id] = new ExitGen(name(), masterID, duration); + states[id].reset(new ExitGen(name(), masterID, duration)); DPRINTF(TrafficGen, "State: %d ExitGen\n", id); } else if (mode == "LINEAR" || mode == "RANDOM" || mode == "DRAM" || mode == "DRAM_ROTATE") { @@ -338,18 +223,18 @@ TrafficGen::parseConfig() fatal("%s cannot have min_period > max_period", name()); if (mode == "LINEAR") { - states[id] = new LinearGen(name(), masterID, + states[id].reset(new LinearGen(name(), masterID, duration, start_addr, end_addr, blocksize, min_period, max_period, - read_percent, data_limit); + read_percent, data_limit)); DPRINTF(TrafficGen, "State: %d LinearGen\n", id); } else if (mode == "RANDOM") { - states[id] = new RandomGen(name(), masterID, + states[id].reset(new RandomGen(name(), masterID, duration, start_addr, end_addr, blocksize, min_period, max_period, - read_percent, data_limit); + read_percent, data_limit)); DPRINTF(TrafficGen, "State: %d RandomGen\n", id); } else if (mode == "DRAM" || mode == "DRAM_ROTATE") { // stride size (bytes) of the request for achieving @@ -387,7 +272,7 @@ TrafficGen::parseConfig() } if (mode == "DRAM") { - states[id] = new DramGen(name(), masterID, + states[id].reset(new DramGen(name(), masterID, duration, start_addr, end_addr, blocksize, min_period, max_period, @@ -396,7 +281,7 @@ TrafficGen::parseConfig() nbr_of_banks_DRAM, nbr_of_banks_util, addr_mapping, - nbr_of_ranks); + nbr_of_ranks)); DPRINTF(TrafficGen, "State: %d DramGen\n", id); } else { // Will rotate to the next rank after rotating @@ -407,7 +292,7 @@ TrafficGen::parseConfig() (read_percent == 50) ? nbr_of_banks_util * 2 : nbr_of_banks_util; - states[id] = new DramRotGen(name(), masterID, + states[id].reset(new DramRotGen(name(), masterID, duration, start_addr, end_addr, blocksize, min_period, max_period, @@ -417,7 +302,7 @@ TrafficGen::parseConfig() nbr_of_banks_util, addr_mapping, nbr_of_ranks, - max_seq_count_per_rank); + max_seq_count_per_rank)); DPRINTF(TrafficGen, "State: %d DramRotGen\n", id); } } @@ -478,13 +363,9 @@ TrafficGen::parseConfig() infile.close(); } -void -TrafficGen::transition() +size_t +TrafficGen::nextState() { - // exit the current state - states[currState]->exit(); - - // determine next state double p = random_mt.random(); assert(currState < transitionMatrix.size()); double cumulative = 0.0; @@ -494,87 +375,17 @@ TrafficGen::transition() ++i; } while (cumulative < p && i < transitionMatrix[currState].size()); - enterState(i - 1); -} - -void -TrafficGen::enterState(uint32_t newState) -{ - DPRINTF(TrafficGen, "Transition to state %d\n", newState); - - currState = newState; - // we could have been delayed and not transitioned on the exact - // tick when we were supposed to (due to back pressure when - // sending a packet) - nextTransitionTick = curTick() + states[currState]->duration; - states[currState]->enter(); -} - -void -TrafficGen::recvReqRetry() -{ - assert(retryPkt != NULL); - - DPRINTF(TrafficGen, "Received retry\n"); - numRetries++; - // attempt to send the packet, and if we are successful start up - // the machinery again - if (port.sendTimingReq(retryPkt)) { - retryPkt = NULL; - // remember how much delay was incurred due to back-pressure - // when sending the request, we also use this to derive - // the tick for the next packet - Tick delay = curTick() - retryPktTick; - retryPktTick = 0; - retryTicks += delay; - - if (drainState() != DrainState::Draining) { - // packet is sent, so find out when the next one is due - nextPacketTick = states[currState]->nextPacketTick(elasticReq, - delay); - Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); - schedule(updateEvent, std::max(curTick(), nextEventTick)); - } else { - // shut things down - nextPacketTick = MaxTick; - nextTransitionTick = MaxTick; - signalDrainDone(); - } - } -} - -void -TrafficGen::noProgress() -{ - fatal("TrafficGen %s spent %llu ticks without making progress", - name(), progressCheck); -} - -void -TrafficGen::regStats() -{ - ClockedObject::regStats(); - - // Initialise all the stats - using namespace Stats; - - numPackets - .name(name() + ".numPackets") - .desc("Number of packets generated"); - - numRetries - .name(name() + ".numRetries") - .desc("Number of retries"); - - retryTicks - .name(name() + ".retryTicks") - .desc("Time spent waiting due to back-pressure (ticks)"); + return i - 1; } -bool -TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) +std::shared_ptr +TrafficGen::nextGenerator() { - delete pkt; + // Return the initial state if there isn't an active generator, + // otherwise perform a state transition. + if (activeGenerator) + currState = nextState(); - return true; + DPRINTF(TrafficGen, "Transition to state %d\n", currState); + return states[currState]; } -- cgit v1.2.3