traffic_gen.cc revision 9400
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" 489241Sandreas.hansson@arm.com#include "sim/stats.hh" 499241Sandreas.hansson@arm.com#include "sim/system.hh" 509241Sandreas.hansson@arm.com 519241Sandreas.hansson@arm.comusing namespace std; 529241Sandreas.hansson@arm.com 539241Sandreas.hansson@arm.comTrafficGen::TrafficGen(const TrafficGenParams* p) 549241Sandreas.hansson@arm.com : MemObject(p), 559241Sandreas.hansson@arm.com system(p->system), 569241Sandreas.hansson@arm.com masterID(system->getMasterId(name())), 579241Sandreas.hansson@arm.com port(name() + ".port", *this), 589241Sandreas.hansson@arm.com stateGraph(*this, port, p->config_file, masterID), 599241Sandreas.hansson@arm.com updateStateGraphEvent(this) 609241Sandreas.hansson@arm.com{ 619241Sandreas.hansson@arm.com} 629241Sandreas.hansson@arm.com 639241Sandreas.hansson@arm.comTrafficGen* 649241Sandreas.hansson@arm.comTrafficGenParams::create() 659241Sandreas.hansson@arm.com{ 669241Sandreas.hansson@arm.com return new TrafficGen(this); 679241Sandreas.hansson@arm.com} 689241Sandreas.hansson@arm.com 699294Sandreas.hansson@arm.comBaseMasterPort& 709294Sandreas.hansson@arm.comTrafficGen::getMasterPort(const string& if_name, PortID idx) 719241Sandreas.hansson@arm.com{ 729241Sandreas.hansson@arm.com if (if_name == "port") { 739241Sandreas.hansson@arm.com return port; 749241Sandreas.hansson@arm.com } else { 759241Sandreas.hansson@arm.com return MemObject::getMasterPort(if_name, idx); 769241Sandreas.hansson@arm.com } 779241Sandreas.hansson@arm.com} 789241Sandreas.hansson@arm.com 799241Sandreas.hansson@arm.comvoid 809241Sandreas.hansson@arm.comTrafficGen::init() 819241Sandreas.hansson@arm.com{ 829241Sandreas.hansson@arm.com if (!port.isConnected()) 839241Sandreas.hansson@arm.com fatal("The port of %s is not connected!\n", name()); 849241Sandreas.hansson@arm.com 859241Sandreas.hansson@arm.com Enums::MemoryMode mode = system->getMemoryMode(); 869241Sandreas.hansson@arm.com 879241Sandreas.hansson@arm.com // if the system is in timing mode active the request generator 889241Sandreas.hansson@arm.com if (mode == Enums::timing) { 899241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Timing mode, activating request generator\n"); 909241Sandreas.hansson@arm.com 919241Sandreas.hansson@arm.com // enter initial state 929241Sandreas.hansson@arm.com stateGraph.enterState(stateGraph.currState); 939241Sandreas.hansson@arm.com } else { 949241Sandreas.hansson@arm.com DPRINTF(TrafficGen, 959241Sandreas.hansson@arm.com "Traffic generator is only active in timing mode\n"); 969241Sandreas.hansson@arm.com } 979241Sandreas.hansson@arm.com} 989241Sandreas.hansson@arm.com 999241Sandreas.hansson@arm.comvoid 1009241Sandreas.hansson@arm.comTrafficGen::initState() 1019241Sandreas.hansson@arm.com{ 1029241Sandreas.hansson@arm.com // when not restoring from a checkpoint, make sure we kick things off 1039241Sandreas.hansson@arm.com if (system->getMemoryMode() == Enums::timing) { 1049241Sandreas.hansson@arm.com Tick nextStateGraphEvent = stateGraph.nextEventTick(); 1059241Sandreas.hansson@arm.com schedule(updateStateGraphEvent, nextStateGraphEvent); 1069241Sandreas.hansson@arm.com } else { 1079241Sandreas.hansson@arm.com DPRINTF(TrafficGen, 1089241Sandreas.hansson@arm.com "Traffic generator is only active in timing mode\n"); 1099241Sandreas.hansson@arm.com } 1109241Sandreas.hansson@arm.com} 1119241Sandreas.hansson@arm.com 1129241Sandreas.hansson@arm.comunsigned int 1139342SAndreas.Sandberg@arm.comTrafficGen::drain(DrainManager *dm) 1149241Sandreas.hansson@arm.com{ 1159241Sandreas.hansson@arm.com // @todo we should also stop putting new requests in the queue and 1169241Sandreas.hansson@arm.com // either interrupt the current state or wait for a transition 1179342SAndreas.Sandberg@arm.com return port.drain(dm); 1189241Sandreas.hansson@arm.com} 1199241Sandreas.hansson@arm.com 1209241Sandreas.hansson@arm.comvoid 1219241Sandreas.hansson@arm.comTrafficGen::serialize(ostream &os) 1229241Sandreas.hansson@arm.com{ 1239241Sandreas.hansson@arm.com DPRINTF(Checkpoint, "Serializing TrafficGen\n"); 1249241Sandreas.hansson@arm.com 1259241Sandreas.hansson@arm.com // save ticks of the graph event if it is scheduled 1269241Sandreas.hansson@arm.com Tick nextStateGraphEvent = updateStateGraphEvent.scheduled() ? 1279241Sandreas.hansson@arm.com updateStateGraphEvent.when() : 0; 1289241Sandreas.hansson@arm.com 1299241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Saving nextStateGraphEvent=%llu\n", 1309241Sandreas.hansson@arm.com nextStateGraphEvent); 1319241Sandreas.hansson@arm.com 1329241Sandreas.hansson@arm.com SERIALIZE_SCALAR(nextStateGraphEvent); 1339241Sandreas.hansson@arm.com 1349241Sandreas.hansson@arm.com Tick nextTransitionTick = stateGraph.nextTransitionTick; 1359241Sandreas.hansson@arm.com SERIALIZE_SCALAR(nextTransitionTick); 1369241Sandreas.hansson@arm.com 1379241Sandreas.hansson@arm.com // @todo: also serialise the current state, figure out the best 1389241Sandreas.hansson@arm.com // way to drain and restore 1399241Sandreas.hansson@arm.com} 1409241Sandreas.hansson@arm.com 1419241Sandreas.hansson@arm.comvoid 1429241Sandreas.hansson@arm.comTrafficGen::unserialize(Checkpoint* cp, const string& section) 1439241Sandreas.hansson@arm.com{ 1449241Sandreas.hansson@arm.com // restore scheduled events 1459241Sandreas.hansson@arm.com Tick nextStateGraphEvent; 1469241Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(nextStateGraphEvent); 1479241Sandreas.hansson@arm.com if (nextStateGraphEvent != 0) { 1489241Sandreas.hansson@arm.com schedule(updateStateGraphEvent, nextStateGraphEvent); 1499241Sandreas.hansson@arm.com } 1509241Sandreas.hansson@arm.com 1519241Sandreas.hansson@arm.com Tick nextTransitionTick; 1529241Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(nextTransitionTick); 1539241Sandreas.hansson@arm.com stateGraph.nextTransitionTick = nextTransitionTick; 1549241Sandreas.hansson@arm.com} 1559241Sandreas.hansson@arm.com 1569241Sandreas.hansson@arm.comvoid 1579241Sandreas.hansson@arm.comTrafficGen::updateStateGraph() 1589241Sandreas.hansson@arm.com{ 1599241Sandreas.hansson@arm.com // schedule next update event based on either the next execute 1609241Sandreas.hansson@arm.com // tick or the next transition, which ever comes first 1619241Sandreas.hansson@arm.com Tick nextStateGraphEvent = stateGraph.nextEventTick(); 1629241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n", 1639241Sandreas.hansson@arm.com nextStateGraphEvent); 1649241Sandreas.hansson@arm.com schedule(updateStateGraphEvent, nextStateGraphEvent); 1659241Sandreas.hansson@arm.com 1669241Sandreas.hansson@arm.com // perform the update associated with the current update event 1679241Sandreas.hansson@arm.com stateGraph.update(); 1689241Sandreas.hansson@arm.com} 1699241Sandreas.hansson@arm.com 1709241Sandreas.hansson@arm.comvoid 1719241Sandreas.hansson@arm.comTrafficGen::StateGraph::parseConfig(const string& file_name, 1729241Sandreas.hansson@arm.com MasterID master_id) 1739241Sandreas.hansson@arm.com{ 1749241Sandreas.hansson@arm.com // keep track of the transitions parsed to create the matrix when 1759241Sandreas.hansson@arm.com // done 1769241Sandreas.hansson@arm.com vector<Transition> transitions; 1779241Sandreas.hansson@arm.com 1789241Sandreas.hansson@arm.com // open input file 1799241Sandreas.hansson@arm.com ifstream infile; 1809241Sandreas.hansson@arm.com infile.open(file_name.c_str(), ifstream::in); 1819241Sandreas.hansson@arm.com if (!infile.is_open()) { 1829241Sandreas.hansson@arm.com fatal("Traffic generator %s config file not found at %s\n", 1839241Sandreas.hansson@arm.com owner.name(), file_name); 1849241Sandreas.hansson@arm.com } 1859241Sandreas.hansson@arm.com 1869241Sandreas.hansson@arm.com // read line by line and determine the action based on the first 1879241Sandreas.hansson@arm.com // keyword 1889241Sandreas.hansson@arm.com string keyword; 1899241Sandreas.hansson@arm.com string line; 1909241Sandreas.hansson@arm.com 1919241Sandreas.hansson@arm.com while (getline(infile, line).good()) { 1929241Sandreas.hansson@arm.com // see if this line is a comment line, and if so skip it 1939241Sandreas.hansson@arm.com if (line.find('#') != 1) { 1949241Sandreas.hansson@arm.com // create an input stream for the tokenization 1959241Sandreas.hansson@arm.com istringstream is(line); 1969241Sandreas.hansson@arm.com 1979241Sandreas.hansson@arm.com // determine the keyword 1989241Sandreas.hansson@arm.com is >> keyword; 1999241Sandreas.hansson@arm.com 2009241Sandreas.hansson@arm.com if (keyword == "STATE") { 2019241Sandreas.hansson@arm.com // parse the behaviour of this state 2029241Sandreas.hansson@arm.com uint32_t id; 2039241Sandreas.hansson@arm.com Tick duration; 2049241Sandreas.hansson@arm.com string mode; 2059241Sandreas.hansson@arm.com 2069241Sandreas.hansson@arm.com is >> id >> duration >> mode; 2079241Sandreas.hansson@arm.com 2089241Sandreas.hansson@arm.com if (mode == "TRACE") { 2099241Sandreas.hansson@arm.com string traceFile; 2109241Sandreas.hansson@arm.com Addr addrOffset; 2119241Sandreas.hansson@arm.com 2129241Sandreas.hansson@arm.com is >> traceFile >> addrOffset; 2139241Sandreas.hansson@arm.com 2149241Sandreas.hansson@arm.com states[id] = new TraceGen(port, master_id, duration, 2159241Sandreas.hansson@arm.com traceFile, addrOffset); 2169241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d TraceGen\n", id); 2179241Sandreas.hansson@arm.com } else if (mode == "IDLE") { 2189241Sandreas.hansson@arm.com states[id] = new IdleGen(port, master_id, duration); 2199241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d IdleGen\n", id); 2209241Sandreas.hansson@arm.com } else if (mode == "LINEAR" || mode == "RANDOM") { 2219241Sandreas.hansson@arm.com uint32_t read_percent; 2229241Sandreas.hansson@arm.com Addr start_addr; 2239241Sandreas.hansson@arm.com Addr end_addr; 2249241Sandreas.hansson@arm.com Addr blocksize; 2259241Sandreas.hansson@arm.com Tick min_period; 2269241Sandreas.hansson@arm.com Tick max_period; 2279241Sandreas.hansson@arm.com Addr data_limit; 2289241Sandreas.hansson@arm.com 2299241Sandreas.hansson@arm.com is >> read_percent >> start_addr >> end_addr >> 2309241Sandreas.hansson@arm.com blocksize >> min_period >> max_period >> data_limit; 2319241Sandreas.hansson@arm.com 2329241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "%s, addr %x to %x, size %d," 2339241Sandreas.hansson@arm.com " period %d to %d, %d%% reads\n", 2349241Sandreas.hansson@arm.com mode, start_addr, end_addr, blocksize, min_period, 2359241Sandreas.hansson@arm.com max_period, read_percent); 2369241Sandreas.hansson@arm.com 2379241Sandreas.hansson@arm.com if (read_percent > 100) 2389241Sandreas.hansson@arm.com panic("%s cannot have more than 100% reads", name()); 2399241Sandreas.hansson@arm.com 2409241Sandreas.hansson@arm.com if (mode == "LINEAR") { 2419241Sandreas.hansson@arm.com states[id] = new LinearGen(port, master_id, 2429241Sandreas.hansson@arm.com duration, start_addr, 2439241Sandreas.hansson@arm.com end_addr, blocksize, 2449241Sandreas.hansson@arm.com min_period, max_period, 2459241Sandreas.hansson@arm.com read_percent, data_limit); 2469241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d LinearGen\n", id); 2479241Sandreas.hansson@arm.com } else if (mode == "RANDOM") { 2489241Sandreas.hansson@arm.com states[id] = new RandomGen(port, master_id, 2499241Sandreas.hansson@arm.com duration, start_addr, 2509241Sandreas.hansson@arm.com end_addr, blocksize, 2519241Sandreas.hansson@arm.com min_period, max_period, 2529241Sandreas.hansson@arm.com read_percent, data_limit); 2539241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d RandomGen\n", id); 2549241Sandreas.hansson@arm.com } 2559241Sandreas.hansson@arm.com } else { 2569241Sandreas.hansson@arm.com fatal("%s: Unknown traffic generator mode: %s", 2579241Sandreas.hansson@arm.com name(), mode); 2589241Sandreas.hansson@arm.com } 2599241Sandreas.hansson@arm.com } else if (keyword == "TRANSITION") { 2609241Sandreas.hansson@arm.com Transition transition; 2619241Sandreas.hansson@arm.com 2629241Sandreas.hansson@arm.com is >> transition.from >> transition.to >> transition.p; 2639241Sandreas.hansson@arm.com 2649241Sandreas.hansson@arm.com transitions.push_back(transition); 2659241Sandreas.hansson@arm.com 2669241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from, 2679241Sandreas.hansson@arm.com transition.to); 2689241Sandreas.hansson@arm.com } else if (keyword == "INIT") { 2699241Sandreas.hansson@arm.com // set the initial state as the active state 2709241Sandreas.hansson@arm.com is >> currState; 2719241Sandreas.hansson@arm.com 2729241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Initial state: %d\n", currState); 2739241Sandreas.hansson@arm.com } 2749241Sandreas.hansson@arm.com } 2759241Sandreas.hansson@arm.com } 2769241Sandreas.hansson@arm.com 2779241Sandreas.hansson@arm.com // resize and populate state transition matrix 2789241Sandreas.hansson@arm.com transitionMatrix.resize(transitions.size()); 2799241Sandreas.hansson@arm.com for (size_t i = 0; i < transitions.size(); i++) { 2809241Sandreas.hansson@arm.com transitionMatrix[i].resize(transitions.size()); 2819241Sandreas.hansson@arm.com } 2829241Sandreas.hansson@arm.com 2839241Sandreas.hansson@arm.com for (vector<Transition>::iterator t = transitions.begin(); 2849241Sandreas.hansson@arm.com t != transitions.end(); ++t) { 2859241Sandreas.hansson@arm.com transitionMatrix[t->from][t->to] = t->p; 2869241Sandreas.hansson@arm.com } 2879241Sandreas.hansson@arm.com 2889241Sandreas.hansson@arm.com // ensure the egress edges do not have a probability larger than 2899241Sandreas.hansson@arm.com // one 2909241Sandreas.hansson@arm.com for (size_t i = 0; i < transitions.size(); i++) { 2919241Sandreas.hansson@arm.com double sum = 0; 2929241Sandreas.hansson@arm.com for (size_t j = 0; j < transitions.size(); j++) { 2939241Sandreas.hansson@arm.com sum += transitionMatrix[i][j]; 2949241Sandreas.hansson@arm.com } 2959241Sandreas.hansson@arm.com 2969241Sandreas.hansson@arm.com // avoid comparing floating point numbers 2979241Sandreas.hansson@arm.com if (abs(sum - 1.0) > 0.001) 2989241Sandreas.hansson@arm.com fatal("%s has transition probability != 1 for state %d\n", 2999241Sandreas.hansson@arm.com name(), i); 3009241Sandreas.hansson@arm.com } 3019241Sandreas.hansson@arm.com 3029241Sandreas.hansson@arm.com // close input file 3039241Sandreas.hansson@arm.com infile.close(); 3049241Sandreas.hansson@arm.com} 3059241Sandreas.hansson@arm.com 3069241Sandreas.hansson@arm.comvoid 3079241Sandreas.hansson@arm.comTrafficGen::StateGraph::update() 3089241Sandreas.hansson@arm.com{ 3099241Sandreas.hansson@arm.com // if we have reached the time for the next state transition, then 3109241Sandreas.hansson@arm.com // perform the transition 3119241Sandreas.hansson@arm.com if (curTick() >= nextTransitionTick) { 3129241Sandreas.hansson@arm.com transition(); 3139241Sandreas.hansson@arm.com } else { 3149241Sandreas.hansson@arm.com // we are still in the current state and should execute it 3159241Sandreas.hansson@arm.com states[currState]->execute(); 3169241Sandreas.hansson@arm.com } 3179241Sandreas.hansson@arm.com} 3189241Sandreas.hansson@arm.com 3199241Sandreas.hansson@arm.comvoid 3209241Sandreas.hansson@arm.comTrafficGen::StateGraph::transition() 3219241Sandreas.hansson@arm.com{ 3229241Sandreas.hansson@arm.com // exit the current state 3239241Sandreas.hansson@arm.com states[currState]->exit(); 3249241Sandreas.hansson@arm.com 3259241Sandreas.hansson@arm.com // determine next state 3269241Sandreas.hansson@arm.com double p = random_mt.gen_real1(); 3279241Sandreas.hansson@arm.com assert(currState < transitionMatrix.size()); 3289241Sandreas.hansson@arm.com double cumulative = transitionMatrix[currState][0]; 3299241Sandreas.hansson@arm.com size_t i = 1; 3309241Sandreas.hansson@arm.com while (p < cumulative && i != transitionMatrix[currState].size()) { 3319241Sandreas.hansson@arm.com cumulative += transitionMatrix[currState][i]; 3329241Sandreas.hansson@arm.com ++i; 3339241Sandreas.hansson@arm.com } 3349241Sandreas.hansson@arm.com enterState(i); 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 3559241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::enter() 3569241Sandreas.hansson@arm.com{ 3579241Sandreas.hansson@arm.com // reset the address and the data counter 3589241Sandreas.hansson@arm.com nextAddr = startAddr; 3599241Sandreas.hansson@arm.com dataManipulated = 0; 3609241Sandreas.hansson@arm.com 3619241Sandreas.hansson@arm.com // this test only needs to happen once, but cannot be performed 3629241Sandreas.hansson@arm.com // before init() is called and the ports are connected 3639241Sandreas.hansson@arm.com if (port.deviceBlockSize() && blocksize > port.deviceBlockSize()) 3649241Sandreas.hansson@arm.com fatal("TrafficGen %s block size (%d) is larger than port" 3659241Sandreas.hansson@arm.com " block size (%d)\n", blocksize, port.deviceBlockSize()); 3669241Sandreas.hansson@arm.com 3679241Sandreas.hansson@arm.com} 3689241Sandreas.hansson@arm.com 3699241Sandreas.hansson@arm.comvoid 3709241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::execute() 3719241Sandreas.hansson@arm.com{ 3729241Sandreas.hansson@arm.com // choose if we generate a read or a write here 3739391Sandreas.hansson@arm.com bool isRead = readPercent != 0 && 3749391Sandreas.hansson@arm.com (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent); 3759241Sandreas.hansson@arm.com 3769391Sandreas.hansson@arm.com assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) || 3779391Sandreas.hansson@arm.com readPercent != 100); 3789241Sandreas.hansson@arm.com 3799241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "LinearGen::execute: %c to addr %x, size %d\n", 3809241Sandreas.hansson@arm.com isRead ? 'r' : 'w', nextAddr, blocksize); 3819241Sandreas.hansson@arm.com 3829241Sandreas.hansson@arm.com // Create new request 3839241Sandreas.hansson@arm.com Request::Flags flags; 3849241Sandreas.hansson@arm.com Request *req = new Request(nextAddr, blocksize, flags, masterID); 3859241Sandreas.hansson@arm.com 3869241Sandreas.hansson@arm.com PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq : 3879241Sandreas.hansson@arm.com MemCmd::WriteReq); 3889241Sandreas.hansson@arm.com 3899241Sandreas.hansson@arm.com uint8_t* pkt_data = new uint8_t[req->getSize()]; 3909241Sandreas.hansson@arm.com pkt->dataDynamicArray(pkt_data); 3919241Sandreas.hansson@arm.com 3929241Sandreas.hansson@arm.com if (!isRead) { 3939241Sandreas.hansson@arm.com memset(pkt_data, 0xA, req->getSize()); 3949241Sandreas.hansson@arm.com } 3959241Sandreas.hansson@arm.com 3969241Sandreas.hansson@arm.com port.schedTimingReq(pkt, curTick()); 3979241Sandreas.hansson@arm.com 3989241Sandreas.hansson@arm.com // increment the address 3999241Sandreas.hansson@arm.com nextAddr += blocksize; 4009241Sandreas.hansson@arm.com 4019241Sandreas.hansson@arm.com // Add the amount of data manipulated to the total 4029241Sandreas.hansson@arm.com dataManipulated += blocksize; 4039241Sandreas.hansson@arm.com} 4049241Sandreas.hansson@arm.com 4059241Sandreas.hansson@arm.comTick 4069241Sandreas.hansson@arm.comTrafficGen::StateGraph::LinearGen::nextExecuteTick() 4079241Sandreas.hansson@arm.com{ 4089241Sandreas.hansson@arm.com // If we have reached the end of the address space, reset the 4099241Sandreas.hansson@arm.com // address to the start of the range 4109241Sandreas.hansson@arm.com if (nextAddr + blocksize > endAddr) { 4119241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Wrapping address to the start of " 4129241Sandreas.hansson@arm.com "the range\n"); 4139241Sandreas.hansson@arm.com nextAddr = startAddr; 4149241Sandreas.hansson@arm.com } 4159241Sandreas.hansson@arm.com 4169241Sandreas.hansson@arm.com // Check to see if we have reached the data limit. If dataLimit is 4179241Sandreas.hansson@arm.com // zero we do not have a data limit and therefore we will keep 4189241Sandreas.hansson@arm.com // generating requests for the entire residency in this state. 4199241Sandreas.hansson@arm.com if (dataLimit && dataManipulated >= dataLimit) { 4209241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Data limit for LinearGen reached.\n"); 4219241Sandreas.hansson@arm.com // there are no more requests, therefore return MaxTick 4229241Sandreas.hansson@arm.com return MaxTick; 4239241Sandreas.hansson@arm.com } else { 4249241Sandreas.hansson@arm.com // return the time when the next request should take place 4259241Sandreas.hansson@arm.com return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod); 4269241Sandreas.hansson@arm.com } 4279241Sandreas.hansson@arm.com} 4289241Sandreas.hansson@arm.com 4299241Sandreas.hansson@arm.comvoid 4309241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::enter() 4319241Sandreas.hansson@arm.com{ 4329241Sandreas.hansson@arm.com // reset the counter to zero 4339241Sandreas.hansson@arm.com dataManipulated = 0; 4349241Sandreas.hansson@arm.com 4359241Sandreas.hansson@arm.com // this test only needs to happen once, but cannot be performed 4369241Sandreas.hansson@arm.com // before init() is called and the ports are connected 4379241Sandreas.hansson@arm.com if (port.deviceBlockSize() && blocksize > port.deviceBlockSize()) 4389241Sandreas.hansson@arm.com fatal("TrafficGen %s block size (%d) is larger than port" 4399241Sandreas.hansson@arm.com " block size (%d)\n", name(), blocksize, port.deviceBlockSize()); 4409241Sandreas.hansson@arm.com} 4419241Sandreas.hansson@arm.com 4429241Sandreas.hansson@arm.comvoid 4439241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::execute() 4449241Sandreas.hansson@arm.com{ 4459241Sandreas.hansson@arm.com // choose if we generate a read or a write here 4469391Sandreas.hansson@arm.com bool isRead = readPercent != 0 && 4479391Sandreas.hansson@arm.com (readPercent == 100 || random_mt.random<uint8_t>(0, 100) < readPercent); 4489241Sandreas.hansson@arm.com 4499391Sandreas.hansson@arm.com assert((readPercent == 0 && !isRead) || (readPercent == 100 && isRead) || 4509391Sandreas.hansson@arm.com readPercent != 100); 4519241Sandreas.hansson@arm.com 4529241Sandreas.hansson@arm.com // address of the request 4539241Sandreas.hansson@arm.com Addr addr = random_mt.random<Addr>(startAddr, endAddr - 1); 4549241Sandreas.hansson@arm.com 4559241Sandreas.hansson@arm.com // round down to start address of block 4569241Sandreas.hansson@arm.com addr -= addr % blocksize; 4579241Sandreas.hansson@arm.com 4589241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "RandomGen::execute: %c to addr %x, size %d\n", 4599241Sandreas.hansson@arm.com isRead ? 'r' : 'w', addr, blocksize); 4609241Sandreas.hansson@arm.com 4619241Sandreas.hansson@arm.com // create new request packet 4629241Sandreas.hansson@arm.com Request::Flags flags; 4639241Sandreas.hansson@arm.com Request *req = new Request(addr, blocksize, flags, masterID); 4649241Sandreas.hansson@arm.com 4659241Sandreas.hansson@arm.com PacketPtr pkt = new Packet(req, isRead ? MemCmd::ReadReq : 4669241Sandreas.hansson@arm.com MemCmd::WriteReq); 4679241Sandreas.hansson@arm.com 4689241Sandreas.hansson@arm.com uint8_t* pkt_data = new uint8_t[req->getSize()]; 4699241Sandreas.hansson@arm.com pkt->dataDynamicArray(pkt_data); 4709241Sandreas.hansson@arm.com 4719241Sandreas.hansson@arm.com if (!isRead) { 4729241Sandreas.hansson@arm.com memset(pkt_data, 0xA, req->getSize()); 4739241Sandreas.hansson@arm.com } 4749241Sandreas.hansson@arm.com 4759241Sandreas.hansson@arm.com port.schedTimingReq(pkt, curTick()); 4769241Sandreas.hansson@arm.com 4779241Sandreas.hansson@arm.com // Add the amount of data manipulated to the total 4789241Sandreas.hansson@arm.com dataManipulated += blocksize; 4799241Sandreas.hansson@arm.com} 4809241Sandreas.hansson@arm.com 4819241Sandreas.hansson@arm.comTick 4829241Sandreas.hansson@arm.comTrafficGen::StateGraph::RandomGen::nextExecuteTick() 4839241Sandreas.hansson@arm.com{ 4849241Sandreas.hansson@arm.com // Check to see if we have reached the data limit. If dataLimit is 4859241Sandreas.hansson@arm.com // zero we do not have a data limit and therefore we will keep 4869241Sandreas.hansson@arm.com // generating requests for the entire residency in this state. 4879241Sandreas.hansson@arm.com if (dataLimit && dataManipulated >= dataLimit) 4889241Sandreas.hansson@arm.com { 4899241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Data limit for RandomGen reached.\n"); 4909241Sandreas.hansson@arm.com // No more requests. Return MaxTick. 4919241Sandreas.hansson@arm.com return MaxTick; 4929241Sandreas.hansson@arm.com } else { 4939241Sandreas.hansson@arm.com // Return the time when the next request should take place. 4949241Sandreas.hansson@arm.com return curTick() + random_mt.random<Tick>(minPeriod, maxPeriod); 4959241Sandreas.hansson@arm.com } 4969241Sandreas.hansson@arm.com} 4979241Sandreas.hansson@arm.com 4989400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::InputStream(const string& 4999400Sandreas.hansson@arm.com filename) 5009400Sandreas.hansson@arm.com{ 5019400Sandreas.hansson@arm.com trace.rdbuf()->pubsetbuf(readBuffer, 4 * 1024 * 1024); 5029400Sandreas.hansson@arm.com trace.open(filename.c_str(), ifstream::in); 5039400Sandreas.hansson@arm.com 5049400Sandreas.hansson@arm.com if (!trace.is_open()) { 5059400Sandreas.hansson@arm.com fatal("Traffic generator trace file could not be" 5069400Sandreas.hansson@arm.com " opened: %s\n", filename); 5079400Sandreas.hansson@arm.com } 5089400Sandreas.hansson@arm.com} 5099400Sandreas.hansson@arm.com 5109400Sandreas.hansson@arm.comvoid 5119400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::reset() 5129400Sandreas.hansson@arm.com{ 5139400Sandreas.hansson@arm.com // seek to the start of the input trace file 5149400Sandreas.hansson@arm.com trace.seekg(0, ifstream::beg); 5159400Sandreas.hansson@arm.com trace.clear(); 5169400Sandreas.hansson@arm.com} 5179400Sandreas.hansson@arm.com 5189400Sandreas.hansson@arm.combool 5199400Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::InputStream::read(TraceElement& element) 5209400Sandreas.hansson@arm.com{ 5219400Sandreas.hansson@arm.com string buffer; 5229400Sandreas.hansson@arm.com bool format_error = false; 5239400Sandreas.hansson@arm.com assert(trace.good()); 5249400Sandreas.hansson@arm.com getline(trace, buffer); 5259400Sandreas.hansson@arm.com 5269400Sandreas.hansson@arm.com // Check that we have something to process. This assumes no EOF at 5279400Sandreas.hansson@arm.com // the end of the line. 5289400Sandreas.hansson@arm.com if (buffer.size() > 0 && !trace.eof()) { 5299400Sandreas.hansson@arm.com std::istringstream iss(buffer); 5309400Sandreas.hansson@arm.com 5319400Sandreas.hansson@arm.com char rOrW, ch; 5329400Sandreas.hansson@arm.com iss >> rOrW; 5339400Sandreas.hansson@arm.com if (rOrW == 'r') { 5349400Sandreas.hansson@arm.com element.cmd = MemCmd::ReadReq; 5359400Sandreas.hansson@arm.com } else if (rOrW == 'w') { 5369400Sandreas.hansson@arm.com element.cmd = MemCmd::WriteReq; 5379400Sandreas.hansson@arm.com } else { 5389400Sandreas.hansson@arm.com format_error = true; 5399400Sandreas.hansson@arm.com } 5409400Sandreas.hansson@arm.com 5419400Sandreas.hansson@arm.com // eat a comma, then get the address 5429400Sandreas.hansson@arm.com iss >> ch; 5439400Sandreas.hansson@arm.com format_error |= ch != ','; 5449400Sandreas.hansson@arm.com iss >> element.addr; 5459400Sandreas.hansson@arm.com 5469400Sandreas.hansson@arm.com // eat a comma, then get the blocksize 5479400Sandreas.hansson@arm.com iss >> ch; 5489400Sandreas.hansson@arm.com format_error |= ch != ','; 5499400Sandreas.hansson@arm.com iss >> element.blocksize; 5509400Sandreas.hansson@arm.com 5519400Sandreas.hansson@arm.com // eat a comma, then get the tick 5529400Sandreas.hansson@arm.com iss >> ch; 5539400Sandreas.hansson@arm.com format_error |= ch != ','; 5549400Sandreas.hansson@arm.com iss >> element.tick; 5559400Sandreas.hansson@arm.com 5569400Sandreas.hansson@arm.com if (format_error) 5579400Sandreas.hansson@arm.com fatal("Trace format error in %s\n", buffer); 5589400Sandreas.hansson@arm.com 5599400Sandreas.hansson@arm.com return true; 5609400Sandreas.hansson@arm.com } 5619400Sandreas.hansson@arm.com 5629400Sandreas.hansson@arm.com // We have reached the end of the file 5639400Sandreas.hansson@arm.com return false; 5649400Sandreas.hansson@arm.com} 5659400Sandreas.hansson@arm.com 5669241Sandreas.hansson@arm.comTick 5679241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::nextExecuteTick() { 5689400Sandreas.hansson@arm.com if (traceComplete) 5699241Sandreas.hansson@arm.com // We are at the end of the file, thus we have no more data in 5709241Sandreas.hansson@arm.com // the trace Return MaxTick to signal that there will be no 5719241Sandreas.hansson@arm.com // more transactions in this active period for the state. 5729241Sandreas.hansson@arm.com return MaxTick; 5739400Sandreas.hansson@arm.com 5749241Sandreas.hansson@arm.com 5759241Sandreas.hansson@arm.com //Reset the nextElement to the default values 5769241Sandreas.hansson@arm.com currElement = nextElement; 5779241Sandreas.hansson@arm.com nextElement.clear(); 5789241Sandreas.hansson@arm.com 5799400Sandreas.hansson@arm.com // We need to look at the next line to calculate the next time an 5809400Sandreas.hansson@arm.com // event occurs, or potentially return MaxTick to signal that 5819400Sandreas.hansson@arm.com // nothing has to be done. 5829400Sandreas.hansson@arm.com if (!trace.read(nextElement)) { 5839241Sandreas.hansson@arm.com traceComplete = true; 5849241Sandreas.hansson@arm.com return MaxTick; 5859241Sandreas.hansson@arm.com } 5869241Sandreas.hansson@arm.com 5879241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "currElement: %c addr %d size %d tick %d (%d)\n", 5889241Sandreas.hansson@arm.com currElement.cmd.isRead() ? 'r' : 'w', 5899241Sandreas.hansson@arm.com currElement.addr, 5909241Sandreas.hansson@arm.com currElement.blocksize, 5919241Sandreas.hansson@arm.com currElement.tick + tickOffset, 5929241Sandreas.hansson@arm.com currElement.tick); 5939241Sandreas.hansson@arm.com 5949241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "nextElement: %c addr %d size %d tick %d (%d)\n", 5959241Sandreas.hansson@arm.com nextElement.cmd.isRead() ? 'r' : 'w', 5969241Sandreas.hansson@arm.com nextElement.addr, 5979241Sandreas.hansson@arm.com nextElement.blocksize, 5989241Sandreas.hansson@arm.com nextElement.tick + tickOffset, 5999241Sandreas.hansson@arm.com nextElement.tick); 6009241Sandreas.hansson@arm.com 6019241Sandreas.hansson@arm.com return tickOffset + nextElement.tick; 6029241Sandreas.hansson@arm.com} 6039241Sandreas.hansson@arm.com 6049241Sandreas.hansson@arm.comvoid 6059241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::enter() { 6069241Sandreas.hansson@arm.com // update the trace offset to the time where the state was entered. 6079241Sandreas.hansson@arm.com tickOffset = curTick(); 6089241Sandreas.hansson@arm.com 6099241Sandreas.hansson@arm.com // clear everything 6109241Sandreas.hansson@arm.com nextElement.clear(); 6119241Sandreas.hansson@arm.com currElement.clear(); 6129241Sandreas.hansson@arm.com 6139241Sandreas.hansson@arm.com traceComplete = false; 6149241Sandreas.hansson@arm.com} 6159241Sandreas.hansson@arm.com 6169241Sandreas.hansson@arm.comvoid 6179241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::execute() { 6189241Sandreas.hansson@arm.com // it is the responsibility of nextExecuteTick to prevent the 6199241Sandreas.hansson@arm.com // state graph from executing the state if it should not 6209241Sandreas.hansson@arm.com assert(currElement.isValid()); 6219241Sandreas.hansson@arm.com 6229241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "TraceGen::execute: %c %d %d %d\n", 6239241Sandreas.hansson@arm.com currElement.cmd.isRead() ? 'r' : 'w', 6249241Sandreas.hansson@arm.com currElement.addr, 6259241Sandreas.hansson@arm.com currElement.blocksize, 6269241Sandreas.hansson@arm.com currElement.tick); 6279241Sandreas.hansson@arm.com 6289241Sandreas.hansson@arm.com Request::Flags flags; 6299241Sandreas.hansson@arm.com Request *req = new Request(currElement.addr + addrOffset, 6309241Sandreas.hansson@arm.com currElement.blocksize, flags, masterID); 6319241Sandreas.hansson@arm.com 6329241Sandreas.hansson@arm.com PacketPtr pkt = new Packet(req, currElement.cmd); 6339241Sandreas.hansson@arm.com 6349241Sandreas.hansson@arm.com uint8_t* pkt_data = new uint8_t[req->getSize()]; 6359241Sandreas.hansson@arm.com pkt->dataDynamicArray(pkt_data); 6369241Sandreas.hansson@arm.com 6379241Sandreas.hansson@arm.com if (currElement.cmd.isWrite()) { 6389241Sandreas.hansson@arm.com memset(pkt_data, 0xA, req->getSize()); 6399241Sandreas.hansson@arm.com } 6409241Sandreas.hansson@arm.com 6419241Sandreas.hansson@arm.com port.schedTimingReq(pkt, curTick()); 6429241Sandreas.hansson@arm.com} 6439241Sandreas.hansson@arm.com 6449241Sandreas.hansson@arm.comvoid 6459241Sandreas.hansson@arm.comTrafficGen::StateGraph::TraceGen::exit() { 6469241Sandreas.hansson@arm.com // Check if we reached the end of the trace file. If we did not 6479241Sandreas.hansson@arm.com // then we want to generate a warning stating that not the entire 6489241Sandreas.hansson@arm.com // trace was played. 6499400Sandreas.hansson@arm.com if (!traceComplete) { 6509241Sandreas.hansson@arm.com warn("Trace player %s was unable to replay the entire trace!\n", 6519241Sandreas.hansson@arm.com name()); 6529241Sandreas.hansson@arm.com } 6539241Sandreas.hansson@arm.com 6549400Sandreas.hansson@arm.com // Clear any flags and start over again from the beginning of the 6559400Sandreas.hansson@arm.com // file 6569400Sandreas.hansson@arm.com trace.reset(); 6579241Sandreas.hansson@arm.com} 6589241Sandreas.hansson@arm.com 6599241Sandreas.hansson@arm.combool 6609241Sandreas.hansson@arm.comTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) 6619241Sandreas.hansson@arm.com{ 6629241Sandreas.hansson@arm.com delete pkt->req; 6639241Sandreas.hansson@arm.com delete pkt; 6649241Sandreas.hansson@arm.com 6659241Sandreas.hansson@arm.com return true; 6669241Sandreas.hansson@arm.com} 667