traffic_gen.cc revision 9584
19241Sandreas.hansson@arm.com/*
29241Sandreas.hansson@arm.com * Copyright (c) 2012 ARM Limited
39241Sandreas.hansson@arm.com * All rights reserved
49241Sandreas.hansson@arm.com *
59241Sandreas.hansson@arm.com * The license below extends only to copyright in the software and shall
69241Sandreas.hansson@arm.com * not be construed as granting a license to any other intellectual
79241Sandreas.hansson@arm.com * property including but not limited to intellectual property relating
89241Sandreas.hansson@arm.com * to a hardware implementation of the functionality of the software
99241Sandreas.hansson@arm.com * licensed hereunder.  You may use the software subject to the license
109241Sandreas.hansson@arm.com * terms below provided that you ensure that this notice is replicated
119241Sandreas.hansson@arm.com * unmodified and in its entirety in all distributions of the software,
129241Sandreas.hansson@arm.com * modified or unmodified, in source code or in binary form.
139241Sandreas.hansson@arm.com *
149241Sandreas.hansson@arm.com * Redistribution and use in source and binary forms, with or without
159241Sandreas.hansson@arm.com * modification, are permitted provided that the following conditions are
169241Sandreas.hansson@arm.com * met: redistributions of source code must retain the above copyright
179241Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer;
189241Sandreas.hansson@arm.com * redistributions in binary form must reproduce the above copyright
199241Sandreas.hansson@arm.com * notice, this list of conditions and the following disclaimer in the
209241Sandreas.hansson@arm.com * documentation and/or other materials provided with the distribution;
219241Sandreas.hansson@arm.com * neither the name of the copyright holders nor the names of its
229241Sandreas.hansson@arm.com * contributors may be used to endorse or promote products derived from
239241Sandreas.hansson@arm.com * this software without specific prior written permission.
249241Sandreas.hansson@arm.com *
259241Sandreas.hansson@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
269241Sandreas.hansson@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
279241Sandreas.hansson@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
289241Sandreas.hansson@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
299241Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
309241Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
319241Sandreas.hansson@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
329241Sandreas.hansson@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
339241Sandreas.hansson@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
349241Sandreas.hansson@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
359241Sandreas.hansson@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
369241Sandreas.hansson@arm.com *
379241Sandreas.hansson@arm.com * Authors: Thomas Grass
389241Sandreas.hansson@arm.com *          Andreas Hansson
399241Sandreas.hansson@arm.com *          Sascha Bischoff
409241Sandreas.hansson@arm.com */
419241Sandreas.hansson@arm.com
429241Sandreas.hansson@arm.com#include <sstream>
439241Sandreas.hansson@arm.com
449241Sandreas.hansson@arm.com#include "base/random.hh"
459241Sandreas.hansson@arm.com#include "cpu/testers/traffic_gen/traffic_gen.hh"
469241Sandreas.hansson@arm.com#include "debug/Checkpoint.hh"
479241Sandreas.hansson@arm.com#include "debug/TrafficGen.hh"
489402Sandreas.hansson@arm.com#include "proto/packet.pb.h"
499241Sandreas.hansson@arm.com#include "sim/stats.hh"
509241Sandreas.hansson@arm.com#include "sim/system.hh"
519241Sandreas.hansson@arm.com
529241Sandreas.hansson@arm.comusing namespace std;
539241Sandreas.hansson@arm.com
549241Sandreas.hansson@arm.comTrafficGen::TrafficGen(const TrafficGenParams* p)
559241Sandreas.hansson@arm.com    : MemObject(p),
569241Sandreas.hansson@arm.com      system(p->system),
579241Sandreas.hansson@arm.com      masterID(system->getMasterId(name())),
589241Sandreas.hansson@arm.com      port(name() + ".port", *this),
599241Sandreas.hansson@arm.com      stateGraph(*this, port, p->config_file, masterID),
609241Sandreas.hansson@arm.com      updateStateGraphEvent(this)
619241Sandreas.hansson@arm.com{
629241Sandreas.hansson@arm.com}
639241Sandreas.hansson@arm.com
649241Sandreas.hansson@arm.comTrafficGen*
659241Sandreas.hansson@arm.comTrafficGenParams::create()
669241Sandreas.hansson@arm.com{
679241Sandreas.hansson@arm.com    return new TrafficGen(this);
689241Sandreas.hansson@arm.com}
699241Sandreas.hansson@arm.com
709294Sandreas.hansson@arm.comBaseMasterPort&
719294Sandreas.hansson@arm.comTrafficGen::getMasterPort(const string& if_name, PortID idx)
729241Sandreas.hansson@arm.com{
739241Sandreas.hansson@arm.com    if (if_name == "port") {
749241Sandreas.hansson@arm.com        return port;
759241Sandreas.hansson@arm.com    } else {
769241Sandreas.hansson@arm.com        return MemObject::getMasterPort(if_name, idx);
779241Sandreas.hansson@arm.com    }
789241Sandreas.hansson@arm.com}
799241Sandreas.hansson@arm.com
809241Sandreas.hansson@arm.comvoid
819241Sandreas.hansson@arm.comTrafficGen::init()
829241Sandreas.hansson@arm.com{
839241Sandreas.hansson@arm.com    if (!port.isConnected())
849241Sandreas.hansson@arm.com        fatal("The port of %s is not connected!\n", name());
859241Sandreas.hansson@arm.com
869241Sandreas.hansson@arm.com    // if the system is in timing mode active the request generator
879524SAndreas.Sandberg@ARM.com    if (system->isTimingMode()) {
889241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
899241Sandreas.hansson@arm.com
909241Sandreas.hansson@arm.com        // enter initial state
919241Sandreas.hansson@arm.com        stateGraph.enterState(stateGraph.currState);
929241Sandreas.hansson@arm.com    } else {
939241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
949241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
959241Sandreas.hansson@arm.com    }
969241Sandreas.hansson@arm.com}
979241Sandreas.hansson@arm.com
989241Sandreas.hansson@arm.comvoid
999241Sandreas.hansson@arm.comTrafficGen::initState()
1009241Sandreas.hansson@arm.com{
1019241Sandreas.hansson@arm.com    // when not restoring from a checkpoint, make sure we kick things off
1029524SAndreas.Sandberg@ARM.com    if (system->isTimingMode()) {
1039241Sandreas.hansson@arm.com        Tick nextStateGraphEvent = stateGraph.nextEventTick();
1049241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1059241Sandreas.hansson@arm.com    } else {
1069241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
1079241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
1089241Sandreas.hansson@arm.com    }
1099241Sandreas.hansson@arm.com}
1109241Sandreas.hansson@arm.com
1119241Sandreas.hansson@arm.comunsigned int
1129342SAndreas.Sandberg@arm.comTrafficGen::drain(DrainManager *dm)
1139241Sandreas.hansson@arm.com{
1149241Sandreas.hansson@arm.com    // @todo we should also stop putting new requests in the queue and
1159241Sandreas.hansson@arm.com    // either interrupt the current state or wait for a transition
1169342SAndreas.Sandberg@arm.com    return port.drain(dm);
1179241Sandreas.hansson@arm.com}
1189241Sandreas.hansson@arm.com
1199241Sandreas.hansson@arm.comvoid
1209241Sandreas.hansson@arm.comTrafficGen::serialize(ostream &os)
1219241Sandreas.hansson@arm.com{
1229241Sandreas.hansson@arm.com    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
1239241Sandreas.hansson@arm.com
1249241Sandreas.hansson@arm.com    // save ticks of the graph event if it is scheduled
1259241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
1269241Sandreas.hansson@arm.com        updateStateGraphEvent.when() : 0;
1279241Sandreas.hansson@arm.com
1289241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
1299241Sandreas.hansson@arm.com            nextStateGraphEvent);
1309241Sandreas.hansson@arm.com
1319241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextStateGraphEvent);
1329241Sandreas.hansson@arm.com
1339241Sandreas.hansson@arm.com    Tick nextTransitionTick = stateGraph.nextTransitionTick;
1349241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextTransitionTick);
1359241Sandreas.hansson@arm.com
1369241Sandreas.hansson@arm.com    // @todo: also serialise the current state, figure out the best
1379241Sandreas.hansson@arm.com    // way to drain and restore
1389241Sandreas.hansson@arm.com}
1399241Sandreas.hansson@arm.com
1409241Sandreas.hansson@arm.comvoid
1419241Sandreas.hansson@arm.comTrafficGen::unserialize(Checkpoint* cp, const string& section)
1429241Sandreas.hansson@arm.com{
1439241Sandreas.hansson@arm.com    // restore scheduled events
1449241Sandreas.hansson@arm.com    Tick nextStateGraphEvent;
1459241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextStateGraphEvent);
1469241Sandreas.hansson@arm.com    if (nextStateGraphEvent != 0) {
1479241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1489241Sandreas.hansson@arm.com    }
1499241Sandreas.hansson@arm.com
1509241Sandreas.hansson@arm.com    Tick nextTransitionTick;
1519241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextTransitionTick);
1529241Sandreas.hansson@arm.com    stateGraph.nextTransitionTick = nextTransitionTick;
1539241Sandreas.hansson@arm.com}
1549241Sandreas.hansson@arm.com
1559241Sandreas.hansson@arm.comvoid
1569241Sandreas.hansson@arm.comTrafficGen::updateStateGraph()
1579241Sandreas.hansson@arm.com{
1589241Sandreas.hansson@arm.com    // schedule next update event based on either the next execute
1599241Sandreas.hansson@arm.com    // tick or the next transition, which ever comes first
1609241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = stateGraph.nextEventTick();
1619241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
1629241Sandreas.hansson@arm.com            nextStateGraphEvent);
1639241Sandreas.hansson@arm.com    schedule(updateStateGraphEvent, nextStateGraphEvent);
1649241Sandreas.hansson@arm.com
1659241Sandreas.hansson@arm.com    // perform the update associated with the current update event
1669241Sandreas.hansson@arm.com    stateGraph.update();
1679241Sandreas.hansson@arm.com}
1689241Sandreas.hansson@arm.com
1699241Sandreas.hansson@arm.comvoid
1709241Sandreas.hansson@arm.comTrafficGen::StateGraph::parseConfig(const string& file_name,
1719241Sandreas.hansson@arm.com                                    MasterID master_id)
1729241Sandreas.hansson@arm.com{
1739241Sandreas.hansson@arm.com    // keep track of the transitions parsed to create the matrix when
1749241Sandreas.hansson@arm.com    // done
1759241Sandreas.hansson@arm.com    vector<Transition> transitions;
1769241Sandreas.hansson@arm.com
1779241Sandreas.hansson@arm.com    // open input file
1789241Sandreas.hansson@arm.com    ifstream infile;
1799241Sandreas.hansson@arm.com    infile.open(file_name.c_str(), ifstream::in);
1809241Sandreas.hansson@arm.com    if (!infile.is_open()) {
1819241Sandreas.hansson@arm.com        fatal("Traffic generator %s config file not found at %s\n",
1829241Sandreas.hansson@arm.com              owner.name(), file_name);
1839241Sandreas.hansson@arm.com    }
1849241Sandreas.hansson@arm.com
1859241Sandreas.hansson@arm.com    // read line by line and determine the action based on the first
1869241Sandreas.hansson@arm.com    // keyword
1879241Sandreas.hansson@arm.com    string keyword;
1889241Sandreas.hansson@arm.com    string line;
1899241Sandreas.hansson@arm.com
1909241Sandreas.hansson@arm.com    while (getline(infile, line).good()) {
1919241Sandreas.hansson@arm.com        // see if this line is a comment line, and if so skip it
1929241Sandreas.hansson@arm.com        if (line.find('#') != 1) {
1939241Sandreas.hansson@arm.com            // create an input stream for the tokenization
1949241Sandreas.hansson@arm.com            istringstream is(line);
1959241Sandreas.hansson@arm.com
1969241Sandreas.hansson@arm.com            // determine the keyword
1979241Sandreas.hansson@arm.com            is >> keyword;
1989241Sandreas.hansson@arm.com
1999241Sandreas.hansson@arm.com            if (keyword == "STATE") {
2009241Sandreas.hansson@arm.com                // parse the behaviour of this state
2019241Sandreas.hansson@arm.com                uint32_t id;
2029241Sandreas.hansson@arm.com                Tick duration;
2039241Sandreas.hansson@arm.com                string mode;
2049241Sandreas.hansson@arm.com
2059241Sandreas.hansson@arm.com                is >> id >> duration >> mode;
2069241Sandreas.hansson@arm.com
2079241Sandreas.hansson@arm.com                if (mode == "TRACE") {
2089241Sandreas.hansson@arm.com                    string traceFile;
2099241Sandreas.hansson@arm.com                    Addr addrOffset;
2109241Sandreas.hansson@arm.com
2119241Sandreas.hansson@arm.com                    is >> traceFile >> addrOffset;
2129241Sandreas.hansson@arm.com
2139241Sandreas.hansson@arm.com                    states[id] = new TraceGen(port, master_id, duration,
2149241Sandreas.hansson@arm.com                                              traceFile, addrOffset);
2159241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
2169241Sandreas.hansson@arm.com                } else if (mode == "IDLE") {
2179241Sandreas.hansson@arm.com                    states[id] = new IdleGen(port, master_id, duration);
2189241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
2199241Sandreas.hansson@arm.com                } else if (mode == "LINEAR" || mode == "RANDOM") {
2209241Sandreas.hansson@arm.com                    uint32_t read_percent;
2219241Sandreas.hansson@arm.com                    Addr start_addr;
2229241Sandreas.hansson@arm.com                    Addr end_addr;
2239241Sandreas.hansson@arm.com                    Addr blocksize;
2249241Sandreas.hansson@arm.com                    Tick min_period;
2259241Sandreas.hansson@arm.com                    Tick max_period;
2269241Sandreas.hansson@arm.com                    Addr data_limit;
2279241Sandreas.hansson@arm.com
2289241Sandreas.hansson@arm.com                    is >> read_percent >> start_addr >> end_addr >>
2299241Sandreas.hansson@arm.com                        blocksize >> min_period >> max_period >> data_limit;
2309241Sandreas.hansson@arm.com
2319241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
2329241Sandreas.hansson@arm.com                            " period %d to %d, %d%% reads\n",
2339241Sandreas.hansson@arm.com                            mode, start_addr, end_addr, blocksize, min_period,
2349241Sandreas.hansson@arm.com                            max_period, read_percent);
2359241Sandreas.hansson@arm.com
2369241Sandreas.hansson@arm.com                    if (read_percent > 100)
2379241Sandreas.hansson@arm.com                        panic("%s cannot have more than 100% reads", name());
2389241Sandreas.hansson@arm.com
2399241Sandreas.hansson@arm.com                    if (mode == "LINEAR") {
2409241Sandreas.hansson@arm.com                        states[id] = new LinearGen(port, master_id,
2419241Sandreas.hansson@arm.com                                                   duration, start_addr,
2429241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2439241Sandreas.hansson@arm.com                                                   min_period, max_period,
2449241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2459241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
2469241Sandreas.hansson@arm.com                    } else if (mode == "RANDOM") {
2479241Sandreas.hansson@arm.com                        states[id] = new RandomGen(port, master_id,
2489241Sandreas.hansson@arm.com                                                   duration, start_addr,
2499241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2509241Sandreas.hansson@arm.com                                                   min_period, max_period,
2519241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2529241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
2539241Sandreas.hansson@arm.com                    }
2549241Sandreas.hansson@arm.com                } else {
2559241Sandreas.hansson@arm.com                    fatal("%s: Unknown traffic generator mode: %s",
2569241Sandreas.hansson@arm.com                          name(), mode);
2579241Sandreas.hansson@arm.com                }
2589241Sandreas.hansson@arm.com            } else if (keyword == "TRANSITION") {
2599241Sandreas.hansson@arm.com                Transition transition;
2609241Sandreas.hansson@arm.com
2619241Sandreas.hansson@arm.com                is >> transition.from >> transition.to >> transition.p;
2629241Sandreas.hansson@arm.com
2639241Sandreas.hansson@arm.com                transitions.push_back(transition);
2649241Sandreas.hansson@arm.com
2659241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
2669241Sandreas.hansson@arm.com                        transition.to);
2679241Sandreas.hansson@arm.com            } else if (keyword == "INIT") {
2689241Sandreas.hansson@arm.com                // set the initial state as the active state
2699241Sandreas.hansson@arm.com                is >> currState;
2709241Sandreas.hansson@arm.com
2719241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
2729241Sandreas.hansson@arm.com            }
2739241Sandreas.hansson@arm.com        }
2749241Sandreas.hansson@arm.com    }
2759241Sandreas.hansson@arm.com
2769241Sandreas.hansson@arm.com    // resize and populate state transition matrix
2779241Sandreas.hansson@arm.com    transitionMatrix.resize(transitions.size());
2789241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2799241Sandreas.hansson@arm.com        transitionMatrix[i].resize(transitions.size());
2809241Sandreas.hansson@arm.com    }
2819241Sandreas.hansson@arm.com
2829241Sandreas.hansson@arm.com    for (vector<Transition>::iterator t = transitions.begin();
2839241Sandreas.hansson@arm.com         t != transitions.end(); ++t) {
2849241Sandreas.hansson@arm.com        transitionMatrix[t->from][t->to] = t->p;
2859241Sandreas.hansson@arm.com    }
2869241Sandreas.hansson@arm.com
2879241Sandreas.hansson@arm.com    // ensure the egress edges do not have a probability larger than
2889241Sandreas.hansson@arm.com    // one
2899241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2909241Sandreas.hansson@arm.com        double sum = 0;
2919241Sandreas.hansson@arm.com        for (size_t j = 0; j < transitions.size(); j++) {
2929241Sandreas.hansson@arm.com            sum += transitionMatrix[i][j];
2939241Sandreas.hansson@arm.com        }
2949241Sandreas.hansson@arm.com
2959241Sandreas.hansson@arm.com        // avoid comparing floating point numbers
2969241Sandreas.hansson@arm.com        if (abs(sum - 1.0) > 0.001)
2979241Sandreas.hansson@arm.com            fatal("%s has transition probability != 1 for state %d\n",
2989241Sandreas.hansson@arm.com                  name(), i);
2999241Sandreas.hansson@arm.com    }
3009241Sandreas.hansson@arm.com
3019241Sandreas.hansson@arm.com    // close input file
3029241Sandreas.hansson@arm.com    infile.close();
3039241Sandreas.hansson@arm.com}
3049241Sandreas.hansson@arm.com
3059241Sandreas.hansson@arm.comvoid
3069241Sandreas.hansson@arm.comTrafficGen::StateGraph::update()
3079241Sandreas.hansson@arm.com{
3089241Sandreas.hansson@arm.com    // if we have reached the time for the next state transition, then
3099241Sandreas.hansson@arm.com    // perform the transition
3109241Sandreas.hansson@arm.com    if (curTick() >= nextTransitionTick) {
3119241Sandreas.hansson@arm.com        transition();
3129241Sandreas.hansson@arm.com    } else {
3139241Sandreas.hansson@arm.com        // we are still in the current state and should execute it
3149241Sandreas.hansson@arm.com        states[currState]->execute();
3159241Sandreas.hansson@arm.com    }
3169241Sandreas.hansson@arm.com}
3179241Sandreas.hansson@arm.com
3189241Sandreas.hansson@arm.comvoid
3199241Sandreas.hansson@arm.comTrafficGen::StateGraph::transition()
3209241Sandreas.hansson@arm.com{
3219241Sandreas.hansson@arm.com    // exit the current state
3229241Sandreas.hansson@arm.com    states[currState]->exit();
3239241Sandreas.hansson@arm.com
3249241Sandreas.hansson@arm.com    // determine next state
3259241Sandreas.hansson@arm.com    double p = random_mt.gen_real1();
3269241Sandreas.hansson@arm.com    assert(currState < transitionMatrix.size());
3279584Sandreas@sandberg.pp.se    double cumulative = 0.0;
3289584Sandreas@sandberg.pp.se    size_t i = 0;
3299584Sandreas@sandberg.pp.se    do {
3309241Sandreas.hansson@arm.com        cumulative += transitionMatrix[currState][i];
3319241Sandreas.hansson@arm.com        ++i;
3329584Sandreas@sandberg.pp.se    } while (cumulative < p && i < transitionMatrix[currState].size());
3339584Sandreas@sandberg.pp.se
3349584Sandreas@sandberg.pp.se    enterState(i - 1);
3359241Sandreas.hansson@arm.com}
3369241Sandreas.hansson@arm.com
3379241Sandreas.hansson@arm.comvoid
3389241Sandreas.hansson@arm.comTrafficGen::StateGraph::enterState(uint32_t newState)
3399241Sandreas.hansson@arm.com{
3409241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
3419241Sandreas.hansson@arm.com
3429241Sandreas.hansson@arm.com    currState = newState;
3439241Sandreas.hansson@arm.com    nextTransitionTick += states[currState]->duration;
3449241Sandreas.hansson@arm.com    states[currState]->enter();
3459241Sandreas.hansson@arm.com}
3469241Sandreas.hansson@arm.com
3479241Sandreas.hansson@arm.comTrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
3489241Sandreas.hansson@arm.com                                         MasterID master_id,
3499241Sandreas.hansson@arm.com                                         Tick _duration)
3509241Sandreas.hansson@arm.com    : port(_port), masterID(master_id), duration(_duration)
3519241Sandreas.hansson@arm.com{
3529241Sandreas.hansson@arm.com}
3539241Sandreas.hansson@arm.com
3549241Sandreas.hansson@arm.comvoid
3559403Sandreas.hansson@arm.comTrafficGen::StateGraph::BaseGen::send(Addr addr, unsigned size,
3569403Sandreas.hansson@arm.com                                      const MemCmd& cmd)
3579403Sandreas.hansson@arm.com{
3589403Sandreas.hansson@arm.com    // Create new request
3599403Sandreas.hansson@arm.com    Request::Flags flags;
3609403Sandreas.hansson@arm.com    Request *req = new Request(addr, size, flags, masterID);
3619403Sandreas.hansson@arm.com
3629403Sandreas.hansson@arm.com    // Embed it in a packet
3639403Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, cmd);
3649403Sandreas.hansson@arm.com
3659403Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
3669403Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
3679403Sandreas.hansson@arm.com
3689403Sandreas.hansson@arm.com    if (cmd.isWrite()) {
3699403Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
3709403Sandreas.hansson@arm.com    }
3719403Sandreas.hansson@arm.com
3729403Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
3739403Sandreas.hansson@arm.com}
3749403Sandreas.hansson@arm.com
3759403Sandreas.hansson@arm.comvoid
3769241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::enter()
3779241Sandreas.hansson@arm.com{
3789241Sandreas.hansson@arm.com    // reset the address and the data counter
3799241Sandreas.hansson@arm.com    nextAddr = startAddr;
3809241Sandreas.hansson@arm.com    dataManipulated = 0;
3819241Sandreas.hansson@arm.com
3829241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
3839241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
3849241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
3859241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
3869241Sandreas.hansson@arm.com              " block size (%d)\n", blocksize, port.deviceBlockSize());
3879241Sandreas.hansson@arm.com
3889241Sandreas.hansson@arm.com}
3899241Sandreas.hansson@arm.com
3909241Sandreas.hansson@arm.comvoid
3919241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::execute()
3929241Sandreas.hansson@arm.com{
3939241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
3949391Sandreas.hansson@arm.com    bool isRead = readPercent != 0 &&
3959391Sandreas.hansson@arm.com        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
3969241Sandreas.hansson@arm.com
3979391Sandreas.hansson@arm.com    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
3989391Sandreas.hansson@arm.com           readPercent != 100);
3999241Sandreas.hansson@arm.com
4009241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
4019241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', nextAddr, blocksize);
4029241Sandreas.hansson@arm.com
4039403Sandreas.hansson@arm.com    send(nextAddr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
4049241Sandreas.hansson@arm.com
4059241Sandreas.hansson@arm.com    // increment the address
4069241Sandreas.hansson@arm.com    nextAddr += blocksize;
4079241Sandreas.hansson@arm.com
4089241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4099241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4109241Sandreas.hansson@arm.com}
4119241Sandreas.hansson@arm.com
4129241Sandreas.hansson@arm.comTick
4139241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::nextExecuteTick()
4149241Sandreas.hansson@arm.com{
4159241Sandreas.hansson@arm.com    // If we have reached the end of the address space, reset the
4169241Sandreas.hansson@arm.com    // address to the start of the range
4179241Sandreas.hansson@arm.com    if (nextAddr + blocksize > endAddr) {
4189241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Wrapping address to the start of "
4199241Sandreas.hansson@arm.com                "the range\n");
4209241Sandreas.hansson@arm.com        nextAddr = startAddr;
4219241Sandreas.hansson@arm.com    }
4229241Sandreas.hansson@arm.com
4239241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4249241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4259241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4269241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit) {
4279241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
4289241Sandreas.hansson@arm.com        // there are no more requests, therefore return MaxTick
4299241Sandreas.hansson@arm.com        return MaxTick;
4309241Sandreas.hansson@arm.com    } else {
4319241Sandreas.hansson@arm.com        // return the time when the next request should take place
4329241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4339241Sandreas.hansson@arm.com    }
4349241Sandreas.hansson@arm.com}
4359241Sandreas.hansson@arm.com
4369241Sandreas.hansson@arm.comvoid
4379241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::enter()
4389241Sandreas.hansson@arm.com{
4399241Sandreas.hansson@arm.com    // reset the counter to zero
4409241Sandreas.hansson@arm.com    dataManipulated = 0;
4419241Sandreas.hansson@arm.com
4429241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
4439241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
4449241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
4459241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
4469241Sandreas.hansson@arm.com              " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
4479241Sandreas.hansson@arm.com}
4489241Sandreas.hansson@arm.com
4499241Sandreas.hansson@arm.comvoid
4509241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::execute()
4519241Sandreas.hansson@arm.com{
4529241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
4539391Sandreas.hansson@arm.com    bool isRead = readPercent != 0 &&
4549391Sandreas.hansson@arm.com        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
4559241Sandreas.hansson@arm.com
4569391Sandreas.hansson@arm.com    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
4579391Sandreas.hansson@arm.com           readPercent != 100);
4589241Sandreas.hansson@arm.com
4599241Sandreas.hansson@arm.com    // address of the request
4609241Sandreas.hansson@arm.com    Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
4619241Sandreas.hansson@arm.com
4629241Sandreas.hansson@arm.com    // round down to start address of block
4639241Sandreas.hansson@arm.com    addr -= addr % blocksize;
4649241Sandreas.hansson@arm.com
4659241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
4669241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', addr, blocksize);
4679241Sandreas.hansson@arm.com
4689403Sandreas.hansson@arm.com    // send a new request packet
4699403Sandreas.hansson@arm.com    send(addr, blocksize, isRead ? MemCmd::ReadReq : MemCmd::WriteReq);
4709241Sandreas.hansson@arm.com
4719241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4729241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4739241Sandreas.hansson@arm.com}
4749241Sandreas.hansson@arm.com
4759241Sandreas.hansson@arm.comTick
4769241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::nextExecuteTick()
4779241Sandreas.hansson@arm.com{
4789241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4799241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4809241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4819241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit)
4829241Sandreas.hansson@arm.com    {
4839241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
4849241Sandreas.hansson@arm.com        // No more requests. Return MaxTick.
4859241Sandreas.hansson@arm.com        return MaxTick;
4869241Sandreas.hansson@arm.com    } else {
4879241Sandreas.hansson@arm.com        // Return the time when the next request should take place.
4889241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4899241Sandreas.hansson@arm.com    }
4909241Sandreas.hansson@arm.com}
4919241Sandreas.hansson@arm.com
4929400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string&
4939400Sandreas.hansson@arm.com                                                           filename)
4949402Sandreas.hansson@arm.com    : trace(filename)
4959400Sandreas.hansson@arm.com{
4969402Sandreas.hansson@arm.com    // Create a protobuf message for the header and read it from the stream
4979402Sandreas.hansson@arm.com    Message::PacketHeader header_msg;
4989402Sandreas.hansson@arm.com    if (!trace.read(header_msg)) {
4999402Sandreas.hansson@arm.com        panic("Failed to read packet header from %s\n", filename);
5009400Sandreas.hansson@arm.com
5019402Sandreas.hansson@arm.com        if (header_msg.tick_freq() != SimClock::Frequency) {
5029402Sandreas.hansson@arm.com            panic("Trace %s was recorded with a different tick frequency %d\n",
5039402Sandreas.hansson@arm.com                  header_msg.tick_freq());
5049402Sandreas.hansson@arm.com        }
5059400Sandreas.hansson@arm.com    }
5069400Sandreas.hansson@arm.com}
5079400Sandreas.hansson@arm.com
5089400Sandreas.hansson@arm.comvoid
5099400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::reset()
5109400Sandreas.hansson@arm.com{
5119402Sandreas.hansson@arm.com    trace.reset();
5129400Sandreas.hansson@arm.com}
5139400Sandreas.hansson@arm.com
5149400Sandreas.hansson@arm.combool
5159400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element)
5169400Sandreas.hansson@arm.com{
5179402Sandreas.hansson@arm.com    Message::Packet pkt_msg;
5189402Sandreas.hansson@arm.com    if (trace.read(pkt_msg)) {
5199402Sandreas.hansson@arm.com        element.cmd = pkt_msg.cmd();
5209402Sandreas.hansson@arm.com        element.addr = pkt_msg.addr();
5219402Sandreas.hansson@arm.com        element.blocksize = pkt_msg.size();
5229402Sandreas.hansson@arm.com        element.tick = pkt_msg.tick();
5239400Sandreas.hansson@arm.com        return true;
5249400Sandreas.hansson@arm.com    }
5259400Sandreas.hansson@arm.com
5269400Sandreas.hansson@arm.com    // We have reached the end of the file
5279400Sandreas.hansson@arm.com    return false;
5289400Sandreas.hansson@arm.com}
5299400Sandreas.hansson@arm.com
5309241Sandreas.hansson@arm.comTick
5319241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::nextExecuteTick() {
5329400Sandreas.hansson@arm.com    if (traceComplete)
5339241Sandreas.hansson@arm.com        // We are at the end of the file, thus we have no more data in
5349241Sandreas.hansson@arm.com        // the trace Return MaxTick to signal that there will be no
5359241Sandreas.hansson@arm.com        // more transactions in this active period for the state.
5369241Sandreas.hansson@arm.com        return MaxTick;
5379400Sandreas.hansson@arm.com
5389241Sandreas.hansson@arm.com
5399241Sandreas.hansson@arm.com    //Reset the nextElement to the default values
5409241Sandreas.hansson@arm.com    currElement = nextElement;
5419241Sandreas.hansson@arm.com    nextElement.clear();
5429241Sandreas.hansson@arm.com
5439400Sandreas.hansson@arm.com    // We need to look at the next line to calculate the next time an
5449400Sandreas.hansson@arm.com    // event occurs, or potentially return MaxTick to signal that
5459400Sandreas.hansson@arm.com    // nothing has to be done.
5469400Sandreas.hansson@arm.com    if (!trace.read(nextElement)) {
5479241Sandreas.hansson@arm.com        traceComplete = true;
5489241Sandreas.hansson@arm.com        return MaxTick;
5499241Sandreas.hansson@arm.com    }
5509241Sandreas.hansson@arm.com
5519241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
5529241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5539241Sandreas.hansson@arm.com            currElement.addr,
5549241Sandreas.hansson@arm.com            currElement.blocksize,
5559241Sandreas.hansson@arm.com            currElement.tick + tickOffset,
5569241Sandreas.hansson@arm.com            currElement.tick);
5579241Sandreas.hansson@arm.com
5589241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
5599241Sandreas.hansson@arm.com            nextElement.cmd.isRead() ? 'r' : 'w',
5609241Sandreas.hansson@arm.com            nextElement.addr,
5619241Sandreas.hansson@arm.com            nextElement.blocksize,
5629241Sandreas.hansson@arm.com            nextElement.tick + tickOffset,
5639241Sandreas.hansson@arm.com            nextElement.tick);
5649241Sandreas.hansson@arm.com
5659241Sandreas.hansson@arm.com    return tickOffset + nextElement.tick;
5669241Sandreas.hansson@arm.com}
5679241Sandreas.hansson@arm.com
5689241Sandreas.hansson@arm.comvoid
5699241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::enter() {
5709241Sandreas.hansson@arm.com    // update the trace offset to the time where the state was entered.
5719241Sandreas.hansson@arm.com    tickOffset = curTick();
5729241Sandreas.hansson@arm.com
5739241Sandreas.hansson@arm.com    // clear everything
5749241Sandreas.hansson@arm.com    nextElement.clear();
5759241Sandreas.hansson@arm.com    currElement.clear();
5769241Sandreas.hansson@arm.com
5779241Sandreas.hansson@arm.com    traceComplete = false;
5789241Sandreas.hansson@arm.com}
5799241Sandreas.hansson@arm.com
5809241Sandreas.hansson@arm.comvoid
5819241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::execute() {
5829241Sandreas.hansson@arm.com    // it is the responsibility of nextExecuteTick to prevent the
5839241Sandreas.hansson@arm.com    // state graph from executing the state if it should not
5849241Sandreas.hansson@arm.com    assert(currElement.isValid());
5859241Sandreas.hansson@arm.com
5869241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
5879241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5889241Sandreas.hansson@arm.com            currElement.addr,
5899241Sandreas.hansson@arm.com            currElement.blocksize,
5909241Sandreas.hansson@arm.com            currElement.tick);
5919241Sandreas.hansson@arm.com
5929403Sandreas.hansson@arm.com    send(currElement.addr + addrOffset, currElement.blocksize,
5939403Sandreas.hansson@arm.com         currElement.cmd);
5949241Sandreas.hansson@arm.com}
5959241Sandreas.hansson@arm.com
5969241Sandreas.hansson@arm.comvoid
5979241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::exit() {
5989241Sandreas.hansson@arm.com    // Check if we reached the end of the trace file. If we did not
5999241Sandreas.hansson@arm.com    // then we want to generate a warning stating that not the entire
6009241Sandreas.hansson@arm.com    // trace was played.
6019400Sandreas.hansson@arm.com    if (!traceComplete) {
6029241Sandreas.hansson@arm.com        warn("Trace player %s was unable to replay the entire trace!\n",
6039241Sandreas.hansson@arm.com             name());
6049241Sandreas.hansson@arm.com    }
6059241Sandreas.hansson@arm.com
6069400Sandreas.hansson@arm.com    // Clear any flags and start over again from the beginning of the
6079400Sandreas.hansson@arm.com    // file
6089400Sandreas.hansson@arm.com    trace.reset();
6099241Sandreas.hansson@arm.com}
6109241Sandreas.hansson@arm.com
6119241Sandreas.hansson@arm.combool
6129241Sandreas.hansson@arm.comTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
6139241Sandreas.hansson@arm.com{
6149241Sandreas.hansson@arm.com    delete pkt->req;
6159241Sandreas.hansson@arm.com    delete pkt;
6169241Sandreas.hansson@arm.com
6179241Sandreas.hansson@arm.com    return true;
6189241Sandreas.hansson@arm.com}
619