traffic_gen.cc revision 9402
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    Enums::MemoryMode mode = system->getMemoryMode();
879241Sandreas.hansson@arm.com
889241Sandreas.hansson@arm.com    // if the system is in timing mode active the request generator
899241Sandreas.hansson@arm.com    if (mode == Enums::timing) {
909241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Timing mode, activating request generator\n");
919241Sandreas.hansson@arm.com
929241Sandreas.hansson@arm.com        // enter initial state
939241Sandreas.hansson@arm.com        stateGraph.enterState(stateGraph.currState);
949241Sandreas.hansson@arm.com    } else {
959241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
969241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
979241Sandreas.hansson@arm.com    }
989241Sandreas.hansson@arm.com}
999241Sandreas.hansson@arm.com
1009241Sandreas.hansson@arm.comvoid
1019241Sandreas.hansson@arm.comTrafficGen::initState()
1029241Sandreas.hansson@arm.com{
1039241Sandreas.hansson@arm.com    // when not restoring from a checkpoint, make sure we kick things off
1049241Sandreas.hansson@arm.com    if (system->getMemoryMode() == Enums::timing) {
1059241Sandreas.hansson@arm.com        Tick nextStateGraphEvent = stateGraph.nextEventTick();
1069241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1079241Sandreas.hansson@arm.com    } else {
1089241Sandreas.hansson@arm.com        DPRINTF(TrafficGen,
1099241Sandreas.hansson@arm.com                "Traffic generator is only active in timing mode\n");
1109241Sandreas.hansson@arm.com    }
1119241Sandreas.hansson@arm.com}
1129241Sandreas.hansson@arm.com
1139241Sandreas.hansson@arm.comunsigned int
1149342SAndreas.Sandberg@arm.comTrafficGen::drain(DrainManager *dm)
1159241Sandreas.hansson@arm.com{
1169241Sandreas.hansson@arm.com    // @todo we should also stop putting new requests in the queue and
1179241Sandreas.hansson@arm.com    // either interrupt the current state or wait for a transition
1189342SAndreas.Sandberg@arm.com    return port.drain(dm);
1199241Sandreas.hansson@arm.com}
1209241Sandreas.hansson@arm.com
1219241Sandreas.hansson@arm.comvoid
1229241Sandreas.hansson@arm.comTrafficGen::serialize(ostream &os)
1239241Sandreas.hansson@arm.com{
1249241Sandreas.hansson@arm.com    DPRINTF(Checkpoint, "Serializing TrafficGen\n");
1259241Sandreas.hansson@arm.com
1269241Sandreas.hansson@arm.com    // save ticks of the graph event if it is scheduled
1279241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ?
1289241Sandreas.hansson@arm.com        updateStateGraphEvent.when() : 0;
1299241Sandreas.hansson@arm.com
1309241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n",
1319241Sandreas.hansson@arm.com            nextStateGraphEvent);
1329241Sandreas.hansson@arm.com
1339241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextStateGraphEvent);
1349241Sandreas.hansson@arm.com
1359241Sandreas.hansson@arm.com    Tick nextTransitionTick = stateGraph.nextTransitionTick;
1369241Sandreas.hansson@arm.com    SERIALIZE_SCALAR(nextTransitionTick);
1379241Sandreas.hansson@arm.com
1389241Sandreas.hansson@arm.com    // @todo: also serialise the current state, figure out the best
1399241Sandreas.hansson@arm.com    // way to drain and restore
1409241Sandreas.hansson@arm.com}
1419241Sandreas.hansson@arm.com
1429241Sandreas.hansson@arm.comvoid
1439241Sandreas.hansson@arm.comTrafficGen::unserialize(Checkpoint* cp, const string& section)
1449241Sandreas.hansson@arm.com{
1459241Sandreas.hansson@arm.com    // restore scheduled events
1469241Sandreas.hansson@arm.com    Tick nextStateGraphEvent;
1479241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextStateGraphEvent);
1489241Sandreas.hansson@arm.com    if (nextStateGraphEvent != 0) {
1499241Sandreas.hansson@arm.com        schedule(updateStateGraphEvent, nextStateGraphEvent);
1509241Sandreas.hansson@arm.com    }
1519241Sandreas.hansson@arm.com
1529241Sandreas.hansson@arm.com    Tick nextTransitionTick;
1539241Sandreas.hansson@arm.com    UNSERIALIZE_SCALAR(nextTransitionTick);
1549241Sandreas.hansson@arm.com    stateGraph.nextTransitionTick = nextTransitionTick;
1559241Sandreas.hansson@arm.com}
1569241Sandreas.hansson@arm.com
1579241Sandreas.hansson@arm.comvoid
1589241Sandreas.hansson@arm.comTrafficGen::updateStateGraph()
1599241Sandreas.hansson@arm.com{
1609241Sandreas.hansson@arm.com    // schedule next update event based on either the next execute
1619241Sandreas.hansson@arm.com    // tick or the next transition, which ever comes first
1629241Sandreas.hansson@arm.com    Tick nextStateGraphEvent = stateGraph.nextEventTick();
1639241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n",
1649241Sandreas.hansson@arm.com            nextStateGraphEvent);
1659241Sandreas.hansson@arm.com    schedule(updateStateGraphEvent, nextStateGraphEvent);
1669241Sandreas.hansson@arm.com
1679241Sandreas.hansson@arm.com    // perform the update associated with the current update event
1689241Sandreas.hansson@arm.com    stateGraph.update();
1699241Sandreas.hansson@arm.com}
1709241Sandreas.hansson@arm.com
1719241Sandreas.hansson@arm.comvoid
1729241Sandreas.hansson@arm.comTrafficGen::StateGraph::parseConfig(const string& file_name,
1739241Sandreas.hansson@arm.com                                    MasterID master_id)
1749241Sandreas.hansson@arm.com{
1759241Sandreas.hansson@arm.com    // keep track of the transitions parsed to create the matrix when
1769241Sandreas.hansson@arm.com    // done
1779241Sandreas.hansson@arm.com    vector<Transition> transitions;
1789241Sandreas.hansson@arm.com
1799241Sandreas.hansson@arm.com    // open input file
1809241Sandreas.hansson@arm.com    ifstream infile;
1819241Sandreas.hansson@arm.com    infile.open(file_name.c_str(), ifstream::in);
1829241Sandreas.hansson@arm.com    if (!infile.is_open()) {
1839241Sandreas.hansson@arm.com        fatal("Traffic generator %s config file not found at %s\n",
1849241Sandreas.hansson@arm.com              owner.name(), file_name);
1859241Sandreas.hansson@arm.com    }
1869241Sandreas.hansson@arm.com
1879241Sandreas.hansson@arm.com    // read line by line and determine the action based on the first
1889241Sandreas.hansson@arm.com    // keyword
1899241Sandreas.hansson@arm.com    string keyword;
1909241Sandreas.hansson@arm.com    string line;
1919241Sandreas.hansson@arm.com
1929241Sandreas.hansson@arm.com    while (getline(infile, line).good()) {
1939241Sandreas.hansson@arm.com        // see if this line is a comment line, and if so skip it
1949241Sandreas.hansson@arm.com        if (line.find('#') != 1) {
1959241Sandreas.hansson@arm.com            // create an input stream for the tokenization
1969241Sandreas.hansson@arm.com            istringstream is(line);
1979241Sandreas.hansson@arm.com
1989241Sandreas.hansson@arm.com            // determine the keyword
1999241Sandreas.hansson@arm.com            is >> keyword;
2009241Sandreas.hansson@arm.com
2019241Sandreas.hansson@arm.com            if (keyword == "STATE") {
2029241Sandreas.hansson@arm.com                // parse the behaviour of this state
2039241Sandreas.hansson@arm.com                uint32_t id;
2049241Sandreas.hansson@arm.com                Tick duration;
2059241Sandreas.hansson@arm.com                string mode;
2069241Sandreas.hansson@arm.com
2079241Sandreas.hansson@arm.com                is >> id >> duration >> mode;
2089241Sandreas.hansson@arm.com
2099241Sandreas.hansson@arm.com                if (mode == "TRACE") {
2109241Sandreas.hansson@arm.com                    string traceFile;
2119241Sandreas.hansson@arm.com                    Addr addrOffset;
2129241Sandreas.hansson@arm.com
2139241Sandreas.hansson@arm.com                    is >> traceFile >> addrOffset;
2149241Sandreas.hansson@arm.com
2159241Sandreas.hansson@arm.com                    states[id] = new TraceGen(port, master_id, duration,
2169241Sandreas.hansson@arm.com                                              traceFile, addrOffset);
2179241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d TraceGen\n", id);
2189241Sandreas.hansson@arm.com                } else if (mode == "IDLE") {
2199241Sandreas.hansson@arm.com                    states[id] = new IdleGen(port, master_id, duration);
2209241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "State: %d IdleGen\n", id);
2219241Sandreas.hansson@arm.com                } else if (mode == "LINEAR" || mode == "RANDOM") {
2229241Sandreas.hansson@arm.com                    uint32_t read_percent;
2239241Sandreas.hansson@arm.com                    Addr start_addr;
2249241Sandreas.hansson@arm.com                    Addr end_addr;
2259241Sandreas.hansson@arm.com                    Addr blocksize;
2269241Sandreas.hansson@arm.com                    Tick min_period;
2279241Sandreas.hansson@arm.com                    Tick max_period;
2289241Sandreas.hansson@arm.com                    Addr data_limit;
2299241Sandreas.hansson@arm.com
2309241Sandreas.hansson@arm.com                    is >> read_percent >> start_addr >> end_addr >>
2319241Sandreas.hansson@arm.com                        blocksize >> min_period >> max_period >> data_limit;
2329241Sandreas.hansson@arm.com
2339241Sandreas.hansson@arm.com                    DPRINTF(TrafficGen, "%s, addr %x to %x, size %d,"
2349241Sandreas.hansson@arm.com                            " period %d to %d, %d%% reads\n",
2359241Sandreas.hansson@arm.com                            mode, start_addr, end_addr, blocksize, min_period,
2369241Sandreas.hansson@arm.com                            max_period, read_percent);
2379241Sandreas.hansson@arm.com
2389241Sandreas.hansson@arm.com                    if (read_percent > 100)
2399241Sandreas.hansson@arm.com                        panic("%s cannot have more than 100% reads", name());
2409241Sandreas.hansson@arm.com
2419241Sandreas.hansson@arm.com                    if (mode == "LINEAR") {
2429241Sandreas.hansson@arm.com                        states[id] = new LinearGen(port, master_id,
2439241Sandreas.hansson@arm.com                                                   duration, start_addr,
2449241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2459241Sandreas.hansson@arm.com                                                   min_period, max_period,
2469241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2479241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d LinearGen\n", id);
2489241Sandreas.hansson@arm.com                    } else if (mode == "RANDOM") {
2499241Sandreas.hansson@arm.com                        states[id] = new RandomGen(port, master_id,
2509241Sandreas.hansson@arm.com                                                   duration, start_addr,
2519241Sandreas.hansson@arm.com                                                   end_addr, blocksize,
2529241Sandreas.hansson@arm.com                                                   min_period, max_period,
2539241Sandreas.hansson@arm.com                                                   read_percent, data_limit);
2549241Sandreas.hansson@arm.com                        DPRINTF(TrafficGen, "State: %d RandomGen\n", id);
2559241Sandreas.hansson@arm.com                    }
2569241Sandreas.hansson@arm.com                } else {
2579241Sandreas.hansson@arm.com                    fatal("%s: Unknown traffic generator mode: %s",
2589241Sandreas.hansson@arm.com                          name(), mode);
2599241Sandreas.hansson@arm.com                }
2609241Sandreas.hansson@arm.com            } else if (keyword == "TRANSITION") {
2619241Sandreas.hansson@arm.com                Transition transition;
2629241Sandreas.hansson@arm.com
2639241Sandreas.hansson@arm.com                is >> transition.from >> transition.to >> transition.p;
2649241Sandreas.hansson@arm.com
2659241Sandreas.hansson@arm.com                transitions.push_back(transition);
2669241Sandreas.hansson@arm.com
2679241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from,
2689241Sandreas.hansson@arm.com                        transition.to);
2699241Sandreas.hansson@arm.com            } else if (keyword == "INIT") {
2709241Sandreas.hansson@arm.com                // set the initial state as the active state
2719241Sandreas.hansson@arm.com                is >> currState;
2729241Sandreas.hansson@arm.com
2739241Sandreas.hansson@arm.com                DPRINTF(TrafficGen, "Initial state: %d\n", currState);
2749241Sandreas.hansson@arm.com            }
2759241Sandreas.hansson@arm.com        }
2769241Sandreas.hansson@arm.com    }
2779241Sandreas.hansson@arm.com
2789241Sandreas.hansson@arm.com    // resize and populate state transition matrix
2799241Sandreas.hansson@arm.com    transitionMatrix.resize(transitions.size());
2809241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2819241Sandreas.hansson@arm.com        transitionMatrix[i].resize(transitions.size());
2829241Sandreas.hansson@arm.com    }
2839241Sandreas.hansson@arm.com
2849241Sandreas.hansson@arm.com    for (vector<Transition>::iterator t = transitions.begin();
2859241Sandreas.hansson@arm.com         t != transitions.end(); ++t) {
2869241Sandreas.hansson@arm.com        transitionMatrix[t->from][t->to] = t->p;
2879241Sandreas.hansson@arm.com    }
2889241Sandreas.hansson@arm.com
2899241Sandreas.hansson@arm.com    // ensure the egress edges do not have a probability larger than
2909241Sandreas.hansson@arm.com    // one
2919241Sandreas.hansson@arm.com    for (size_t i = 0; i < transitions.size(); i++) {
2929241Sandreas.hansson@arm.com        double sum = 0;
2939241Sandreas.hansson@arm.com        for (size_t j = 0; j < transitions.size(); j++) {
2949241Sandreas.hansson@arm.com            sum += transitionMatrix[i][j];
2959241Sandreas.hansson@arm.com        }
2969241Sandreas.hansson@arm.com
2979241Sandreas.hansson@arm.com        // avoid comparing floating point numbers
2989241Sandreas.hansson@arm.com        if (abs(sum - 1.0) > 0.001)
2999241Sandreas.hansson@arm.com            fatal("%s has transition probability != 1 for state %d\n",
3009241Sandreas.hansson@arm.com                  name(), i);
3019241Sandreas.hansson@arm.com    }
3029241Sandreas.hansson@arm.com
3039241Sandreas.hansson@arm.com    // close input file
3049241Sandreas.hansson@arm.com    infile.close();
3059241Sandreas.hansson@arm.com}
3069241Sandreas.hansson@arm.com
3079241Sandreas.hansson@arm.comvoid
3089241Sandreas.hansson@arm.comTrafficGen::StateGraph::update()
3099241Sandreas.hansson@arm.com{
3109241Sandreas.hansson@arm.com    // if we have reached the time for the next state transition, then
3119241Sandreas.hansson@arm.com    // perform the transition
3129241Sandreas.hansson@arm.com    if (curTick() >= nextTransitionTick) {
3139241Sandreas.hansson@arm.com        transition();
3149241Sandreas.hansson@arm.com    } else {
3159241Sandreas.hansson@arm.com        // we are still in the current state and should execute it
3169241Sandreas.hansson@arm.com        states[currState]->execute();
3179241Sandreas.hansson@arm.com    }
3189241Sandreas.hansson@arm.com}
3199241Sandreas.hansson@arm.com
3209241Sandreas.hansson@arm.comvoid
3219241Sandreas.hansson@arm.comTrafficGen::StateGraph::transition()
3229241Sandreas.hansson@arm.com{
3239241Sandreas.hansson@arm.com    // exit the current state
3249241Sandreas.hansson@arm.com    states[currState]->exit();
3259241Sandreas.hansson@arm.com
3269241Sandreas.hansson@arm.com    // determine next state
3279241Sandreas.hansson@arm.com    double p = random_mt.gen_real1();
3289241Sandreas.hansson@arm.com    assert(currState < transitionMatrix.size());
3299241Sandreas.hansson@arm.com    double cumulative = transitionMatrix[currState][0];
3309241Sandreas.hansson@arm.com    size_t i = 1;
3319241Sandreas.hansson@arm.com    while (p < cumulative && i != transitionMatrix[currState].size()) {
3329241Sandreas.hansson@arm.com        cumulative += transitionMatrix[currState][i];
3339241Sandreas.hansson@arm.com        ++i;
3349241Sandreas.hansson@arm.com    }
3359241Sandreas.hansson@arm.com    enterState(i);
3369241Sandreas.hansson@arm.com}
3379241Sandreas.hansson@arm.com
3389241Sandreas.hansson@arm.comvoid
3399241Sandreas.hansson@arm.comTrafficGen::StateGraph::enterState(uint32_t newState)
3409241Sandreas.hansson@arm.com{
3419241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "Transition to state %d\n", newState);
3429241Sandreas.hansson@arm.com
3439241Sandreas.hansson@arm.com    currState = newState;
3449241Sandreas.hansson@arm.com    nextTransitionTick += states[currState]->duration;
3459241Sandreas.hansson@arm.com    states[currState]->enter();
3469241Sandreas.hansson@arm.com}
3479241Sandreas.hansson@arm.com
3489241Sandreas.hansson@arm.comTrafficGen::StateGraph::BaseGen::BaseGen(QueuedMasterPort& _port,
3499241Sandreas.hansson@arm.com                                         MasterID master_id,
3509241Sandreas.hansson@arm.com                                         Tick _duration)
3519241Sandreas.hansson@arm.com    : port(_port), masterID(master_id), duration(_duration)
3529241Sandreas.hansson@arm.com{
3539241Sandreas.hansson@arm.com}
3549241Sandreas.hansson@arm.com
3559241Sandreas.hansson@arm.comvoid
3569241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::enter()
3579241Sandreas.hansson@arm.com{
3589241Sandreas.hansson@arm.com    // reset the address and the data counter
3599241Sandreas.hansson@arm.com    nextAddr = startAddr;
3609241Sandreas.hansson@arm.com    dataManipulated = 0;
3619241Sandreas.hansson@arm.com
3629241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
3639241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
3649241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
3659241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
3669241Sandreas.hansson@arm.com              " block size (%d)\n", blocksize, port.deviceBlockSize());
3679241Sandreas.hansson@arm.com
3689241Sandreas.hansson@arm.com}
3699241Sandreas.hansson@arm.com
3709241Sandreas.hansson@arm.comvoid
3719241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::execute()
3729241Sandreas.hansson@arm.com{
3739241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
3749391Sandreas.hansson@arm.com    bool isRead = readPercent != 0 &&
3759391Sandreas.hansson@arm.com        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
3769241Sandreas.hansson@arm.com
3779391Sandreas.hansson@arm.com    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
3789391Sandreas.hansson@arm.com           readPercent != 100);
3799241Sandreas.hansson@arm.com
3809241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n",
3819241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', nextAddr, blocksize);
3829241Sandreas.hansson@arm.com
3839241Sandreas.hansson@arm.com    // Create new request
3849241Sandreas.hansson@arm.com    Request::Flags flags;
3859241Sandreas.hansson@arm.com    Request *req = new Request(nextAddr, blocksize, flags, masterID);
3869241Sandreas.hansson@arm.com
3879241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
3889241Sandreas.hansson@arm.com                               MemCmd::WriteReq);
3899241Sandreas.hansson@arm.com
3909241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
3919241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
3929241Sandreas.hansson@arm.com
3939241Sandreas.hansson@arm.com    if (!isRead) {
3949241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
3959241Sandreas.hansson@arm.com    }
3969241Sandreas.hansson@arm.com
3979241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
3989241Sandreas.hansson@arm.com
3999241Sandreas.hansson@arm.com    // increment the address
4009241Sandreas.hansson@arm.com    nextAddr += blocksize;
4019241Sandreas.hansson@arm.com
4029241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4039241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4049241Sandreas.hansson@arm.com}
4059241Sandreas.hansson@arm.com
4069241Sandreas.hansson@arm.comTick
4079241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::nextExecuteTick()
4089241Sandreas.hansson@arm.com{
4099241Sandreas.hansson@arm.com    // If we have reached the end of the address space, reset the
4109241Sandreas.hansson@arm.com    // address to the start of the range
4119241Sandreas.hansson@arm.com    if (nextAddr + blocksize > endAddr) {
4129241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Wrapping address to the start of "
4139241Sandreas.hansson@arm.com                "the range\n");
4149241Sandreas.hansson@arm.com        nextAddr = startAddr;
4159241Sandreas.hansson@arm.com    }
4169241Sandreas.hansson@arm.com
4179241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4189241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4199241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4209241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit) {
4219241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n");
4229241Sandreas.hansson@arm.com        // there are no more requests, therefore return MaxTick
4239241Sandreas.hansson@arm.com        return MaxTick;
4249241Sandreas.hansson@arm.com    } else {
4259241Sandreas.hansson@arm.com        // return the time when the next request should take place
4269241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4279241Sandreas.hansson@arm.com    }
4289241Sandreas.hansson@arm.com}
4299241Sandreas.hansson@arm.com
4309241Sandreas.hansson@arm.comvoid
4319241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::enter()
4329241Sandreas.hansson@arm.com{
4339241Sandreas.hansson@arm.com    // reset the counter to zero
4349241Sandreas.hansson@arm.com    dataManipulated = 0;
4359241Sandreas.hansson@arm.com
4369241Sandreas.hansson@arm.com    // this test only needs to happen once, but cannot be performed
4379241Sandreas.hansson@arm.com    // before init() is called and the ports are connected
4389241Sandreas.hansson@arm.com    if (port.deviceBlockSize() && blocksize > port.deviceBlockSize())
4399241Sandreas.hansson@arm.com        fatal("TrafficGen %s block size (%d) is larger than port"
4409241Sandreas.hansson@arm.com              " block size (%d)\n", name(), blocksize, port.deviceBlockSize());
4419241Sandreas.hansson@arm.com}
4429241Sandreas.hansson@arm.com
4439241Sandreas.hansson@arm.comvoid
4449241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::execute()
4459241Sandreas.hansson@arm.com{
4469241Sandreas.hansson@arm.com    // choose if we generate a read or a write here
4479391Sandreas.hansson@arm.com    bool isRead = readPercent != 0 &&
4489391Sandreas.hansson@arm.com        (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent);
4499241Sandreas.hansson@arm.com
4509391Sandreas.hansson@arm.com    assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) ||
4519391Sandreas.hansson@arm.com           readPercent != 100);
4529241Sandreas.hansson@arm.com
4539241Sandreas.hansson@arm.com    // address of the request
4549241Sandreas.hansson@arm.com    Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1);
4559241Sandreas.hansson@arm.com
4569241Sandreas.hansson@arm.com    // round down to start address of block
4579241Sandreas.hansson@arm.com    addr -= addr % blocksize;
4589241Sandreas.hansson@arm.com
4599241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n",
4609241Sandreas.hansson@arm.com            isRead ? 'r' : 'w', addr, blocksize);
4619241Sandreas.hansson@arm.com
4629241Sandreas.hansson@arm.com    // create new request packet
4639241Sandreas.hansson@arm.com    Request::Flags flags;
4649241Sandreas.hansson@arm.com    Request *req = new Request(addr, blocksize, flags, masterID);
4659241Sandreas.hansson@arm.com
4669241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq :
4679241Sandreas.hansson@arm.com                               MemCmd::WriteReq);
4689241Sandreas.hansson@arm.com
4699241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
4709241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
4719241Sandreas.hansson@arm.com
4729241Sandreas.hansson@arm.com    if (!isRead) {
4739241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
4749241Sandreas.hansson@arm.com    }
4759241Sandreas.hansson@arm.com
4769241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
4779241Sandreas.hansson@arm.com
4789241Sandreas.hansson@arm.com    // Add the amount of data manipulated to the total
4799241Sandreas.hansson@arm.com    dataManipulated += blocksize;
4809241Sandreas.hansson@arm.com}
4819241Sandreas.hansson@arm.com
4829241Sandreas.hansson@arm.comTick
4839241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::nextExecuteTick()
4849241Sandreas.hansson@arm.com{
4859241Sandreas.hansson@arm.com    // Check to see if we have reached the data limit. If dataLimit is
4869241Sandreas.hansson@arm.com    // zero we do not have a data limit and therefore we will keep
4879241Sandreas.hansson@arm.com    // generating requests for the entire residency in this state.
4889241Sandreas.hansson@arm.com    if (dataLimit && dataManipulated >= dataLimit)
4899241Sandreas.hansson@arm.com    {
4909241Sandreas.hansson@arm.com        DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n");
4919241Sandreas.hansson@arm.com        // No more requests. Return MaxTick.
4929241Sandreas.hansson@arm.com        return MaxTick;
4939241Sandreas.hansson@arm.com    } else {
4949241Sandreas.hansson@arm.com        // Return the time when the next request should take place.
4959241Sandreas.hansson@arm.com        return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod);
4969241Sandreas.hansson@arm.com    }
4979241Sandreas.hansson@arm.com}
4989241Sandreas.hansson@arm.com
4999400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string&
5009400Sandreas.hansson@arm.com                                                           filename)
5019402Sandreas.hansson@arm.com    : trace(filename)
5029400Sandreas.hansson@arm.com{
5039402Sandreas.hansson@arm.com    // Create a protobuf message for the header and read it from the stream
5049402Sandreas.hansson@arm.com    Message::PacketHeader header_msg;
5059402Sandreas.hansson@arm.com    if (!trace.read(header_msg)) {
5069402Sandreas.hansson@arm.com        panic("Failed to read packet header from %s\n", filename);
5079400Sandreas.hansson@arm.com
5089402Sandreas.hansson@arm.com        if (header_msg.tick_freq() != SimClock::Frequency) {
5099402Sandreas.hansson@arm.com            panic("Trace %s was recorded with a different tick frequency %d\n",
5109402Sandreas.hansson@arm.com                  header_msg.tick_freq());
5119402Sandreas.hansson@arm.com        }
5129400Sandreas.hansson@arm.com    }
5139400Sandreas.hansson@arm.com}
5149400Sandreas.hansson@arm.com
5159400Sandreas.hansson@arm.comvoid
5169400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::reset()
5179400Sandreas.hansson@arm.com{
5189402Sandreas.hansson@arm.com    trace.reset();
5199400Sandreas.hansson@arm.com}
5209400Sandreas.hansson@arm.com
5219400Sandreas.hansson@arm.combool
5229400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element)
5239400Sandreas.hansson@arm.com{
5249402Sandreas.hansson@arm.com    Message::Packet pkt_msg;
5259402Sandreas.hansson@arm.com    if (trace.read(pkt_msg)) {
5269402Sandreas.hansson@arm.com        element.cmd = pkt_msg.cmd();
5279402Sandreas.hansson@arm.com        element.addr = pkt_msg.addr();
5289402Sandreas.hansson@arm.com        element.blocksize = pkt_msg.size();
5299402Sandreas.hansson@arm.com        element.tick = pkt_msg.tick();
5309400Sandreas.hansson@arm.com        return true;
5319400Sandreas.hansson@arm.com    }
5329400Sandreas.hansson@arm.com
5339400Sandreas.hansson@arm.com    // We have reached the end of the file
5349400Sandreas.hansson@arm.com    return false;
5359400Sandreas.hansson@arm.com}
5369400Sandreas.hansson@arm.com
5379241Sandreas.hansson@arm.comTick
5389241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::nextExecuteTick() {
5399400Sandreas.hansson@arm.com    if (traceComplete)
5409241Sandreas.hansson@arm.com        // We are at the end of the file, thus we have no more data in
5419241Sandreas.hansson@arm.com        // the trace Return MaxTick to signal that there will be no
5429241Sandreas.hansson@arm.com        // more transactions in this active period for the state.
5439241Sandreas.hansson@arm.com        return MaxTick;
5449400Sandreas.hansson@arm.com
5459241Sandreas.hansson@arm.com
5469241Sandreas.hansson@arm.com    //Reset the nextElement to the default values
5479241Sandreas.hansson@arm.com    currElement = nextElement;
5489241Sandreas.hansson@arm.com    nextElement.clear();
5499241Sandreas.hansson@arm.com
5509400Sandreas.hansson@arm.com    // We need to look at the next line to calculate the next time an
5519400Sandreas.hansson@arm.com    // event occurs, or potentially return MaxTick to signal that
5529400Sandreas.hansson@arm.com    // nothing has to be done.
5539400Sandreas.hansson@arm.com    if (!trace.read(nextElement)) {
5549241Sandreas.hansson@arm.com        traceComplete = true;
5559241Sandreas.hansson@arm.com        return MaxTick;
5569241Sandreas.hansson@arm.com    }
5579241Sandreas.hansson@arm.com
5589241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n",
5599241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5609241Sandreas.hansson@arm.com            currElement.addr,
5619241Sandreas.hansson@arm.com            currElement.blocksize,
5629241Sandreas.hansson@arm.com            currElement.tick + tickOffset,
5639241Sandreas.hansson@arm.com            currElement.tick);
5649241Sandreas.hansson@arm.com
5659241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n",
5669241Sandreas.hansson@arm.com            nextElement.cmd.isRead() ? 'r' : 'w',
5679241Sandreas.hansson@arm.com            nextElement.addr,
5689241Sandreas.hansson@arm.com            nextElement.blocksize,
5699241Sandreas.hansson@arm.com            nextElement.tick + tickOffset,
5709241Sandreas.hansson@arm.com            nextElement.tick);
5719241Sandreas.hansson@arm.com
5729241Sandreas.hansson@arm.com    return tickOffset + nextElement.tick;
5739241Sandreas.hansson@arm.com}
5749241Sandreas.hansson@arm.com
5759241Sandreas.hansson@arm.comvoid
5769241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::enter() {
5779241Sandreas.hansson@arm.com    // update the trace offset to the time where the state was entered.
5789241Sandreas.hansson@arm.com    tickOffset = curTick();
5799241Sandreas.hansson@arm.com
5809241Sandreas.hansson@arm.com    // clear everything
5819241Sandreas.hansson@arm.com    nextElement.clear();
5829241Sandreas.hansson@arm.com    currElement.clear();
5839241Sandreas.hansson@arm.com
5849241Sandreas.hansson@arm.com    traceComplete = false;
5859241Sandreas.hansson@arm.com}
5869241Sandreas.hansson@arm.com
5879241Sandreas.hansson@arm.comvoid
5889241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::execute() {
5899241Sandreas.hansson@arm.com    // it is the responsibility of nextExecuteTick to prevent the
5909241Sandreas.hansson@arm.com    // state graph from executing the state if it should not
5919241Sandreas.hansson@arm.com    assert(currElement.isValid());
5929241Sandreas.hansson@arm.com
5939241Sandreas.hansson@arm.com    DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n",
5949241Sandreas.hansson@arm.com            currElement.cmd.isRead() ? 'r' : 'w',
5959241Sandreas.hansson@arm.com            currElement.addr,
5969241Sandreas.hansson@arm.com            currElement.blocksize,
5979241Sandreas.hansson@arm.com            currElement.tick);
5989241Sandreas.hansson@arm.com
5999241Sandreas.hansson@arm.com    Request::Flags flags;
6009241Sandreas.hansson@arm.com    Request *req = new Request(currElement.addr + addrOffset,
6019241Sandreas.hansson@arm.com                               currElement.blocksize, flags, masterID);
6029241Sandreas.hansson@arm.com
6039241Sandreas.hansson@arm.com    PacketPtr pkt = new Packet(req, currElement.cmd);
6049241Sandreas.hansson@arm.com
6059241Sandreas.hansson@arm.com    uint8_t* pkt_data = new uint8_t[req->getSize()];
6069241Sandreas.hansson@arm.com    pkt->dataDynamicArray(pkt_data);
6079241Sandreas.hansson@arm.com
6089241Sandreas.hansson@arm.com    if (currElement.cmd.isWrite()) {
6099241Sandreas.hansson@arm.com        memset(pkt_data, 0xA, req->getSize());
6109241Sandreas.hansson@arm.com    }
6119241Sandreas.hansson@arm.com
6129241Sandreas.hansson@arm.com    port.schedTimingReq(pkt, curTick());
6139241Sandreas.hansson@arm.com}
6149241Sandreas.hansson@arm.com
6159241Sandreas.hansson@arm.comvoid
6169241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::exit() {
6179241Sandreas.hansson@arm.com    // Check if we reached the end of the trace file. If we did not
6189241Sandreas.hansson@arm.com    // then we want to generate a warning stating that not the entire
6199241Sandreas.hansson@arm.com    // trace was played.
6209400Sandreas.hansson@arm.com    if (!traceComplete) {
6219241Sandreas.hansson@arm.com        warn("Trace player %s was unable to replay the entire trace!\n",
6229241Sandreas.hansson@arm.com             name());
6239241Sandreas.hansson@arm.com    }
6249241Sandreas.hansson@arm.com
6259400Sandreas.hansson@arm.com    // Clear any flags and start over again from the beginning of the
6269400Sandreas.hansson@arm.com    // file
6279400Sandreas.hansson@arm.com    trace.reset();
6289241Sandreas.hansson@arm.com}
6299241Sandreas.hansson@arm.com
6309241Sandreas.hansson@arm.combool
6319241Sandreas.hansson@arm.comTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt)
6329241Sandreas.hansson@arm.com{
6339241Sandreas.hansson@arm.com    delete pkt->req;
6349241Sandreas.hansson@arm.com    delete pkt;
6359241Sandreas.hansson@arm.com
6369241Sandreas.hansson@arm.com    return true;
6379241Sandreas.hansson@arm.com}
638