traffic_gen.cc revision 9718
19241Sandreas.hansson@arm.com/* 29717Sandreas.hansson@arm.com * Copyright (c) 2012-2013 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())), 579718Sandreas.hansson@arm.com configFile(p->config_file), 589717Sandreas.hansson@arm.com nextTransitionTick(0), 599241Sandreas.hansson@arm.com port(name() + ".port", *this), 609717Sandreas.hansson@arm.com updateEvent(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 909718Sandreas.hansson@arm.com parseConfig(); 919718Sandreas.hansson@arm.com 929241Sandreas.hansson@arm.com // enter initial state 939717Sandreas.hansson@arm.com enterState(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 1049524SAndreas.Sandberg@ARM.com if (system->isTimingMode()) { 1059717Sandreas.hansson@arm.com schedule(updateEvent, nextEventTick()); 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 1269717Sandreas.hansson@arm.com Tick nextEvent = updateEvent.scheduled() ? 1279717Sandreas.hansson@arm.com updateEvent.when() : 0; 1289241Sandreas.hansson@arm.com 1299717Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", 1309717Sandreas.hansson@arm.com nextEvent); 1319241Sandreas.hansson@arm.com 1329717Sandreas.hansson@arm.com SERIALIZE_SCALAR(nextEvent); 1339241Sandreas.hansson@arm.com 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 1449717Sandreas.hansson@arm.com Tick nextEvent; 1459717Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(nextEvent); 1469717Sandreas.hansson@arm.com if (nextEvent != 0) { 1479717Sandreas.hansson@arm.com schedule(updateEvent, nextEvent); 1489241Sandreas.hansson@arm.com } 1499241Sandreas.hansson@arm.com 1509241Sandreas.hansson@arm.com UNSERIALIZE_SCALAR(nextTransitionTick); 1519241Sandreas.hansson@arm.com} 1529241Sandreas.hansson@arm.com 1539241Sandreas.hansson@arm.comvoid 1549717Sandreas.hansson@arm.comTrafficGen::update() 1559241Sandreas.hansson@arm.com{ 1569241Sandreas.hansson@arm.com // schedule next update event based on either the next execute 1579241Sandreas.hansson@arm.com // tick or the next transition, which ever comes first 1589717Sandreas.hansson@arm.com Tick nextEvent = nextEventTick(); 1599241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n", 1609717Sandreas.hansson@arm.com nextEvent); 1619717Sandreas.hansson@arm.com schedule(updateEvent, nextEvent); 1629241Sandreas.hansson@arm.com 1639241Sandreas.hansson@arm.com // perform the update associated with the current update event 1649717Sandreas.hansson@arm.com 1659717Sandreas.hansson@arm.com // if we have reached the time for the next state transition, then 1669717Sandreas.hansson@arm.com // perform the transition 1679717Sandreas.hansson@arm.com if (curTick() >= nextTransitionTick) { 1689717Sandreas.hansson@arm.com transition(); 1699717Sandreas.hansson@arm.com } else { 1709717Sandreas.hansson@arm.com // we are still in the current state and should execute it 1719718Sandreas.hansson@arm.com PacketPtr pkt = states[currState]->getNextPacket(); 1729718Sandreas.hansson@arm.com port.schedTimingReq(pkt, curTick()); 1739717Sandreas.hansson@arm.com } 1749241Sandreas.hansson@arm.com} 1759241Sandreas.hansson@arm.com 1769241Sandreas.hansson@arm.comvoid 1779718Sandreas.hansson@arm.comTrafficGen::parseConfig() 1789241Sandreas.hansson@arm.com{ 1799241Sandreas.hansson@arm.com // keep track of the transitions parsed to create the matrix when 1809241Sandreas.hansson@arm.com // done 1819241Sandreas.hansson@arm.com vector<Transition> transitions; 1829241Sandreas.hansson@arm.com 1839241Sandreas.hansson@arm.com // open input file 1849241Sandreas.hansson@arm.com ifstream infile; 1859718Sandreas.hansson@arm.com infile.open(configFile.c_str(), ifstream::in); 1869241Sandreas.hansson@arm.com if (!infile.is_open()) { 1879241Sandreas.hansson@arm.com fatal("Traffic generator %s config file not found at %s\n", 1889718Sandreas.hansson@arm.com name(), configFile); 1899241Sandreas.hansson@arm.com } 1909241Sandreas.hansson@arm.com 1919241Sandreas.hansson@arm.com // read line by line and determine the action based on the first 1929241Sandreas.hansson@arm.com // keyword 1939241Sandreas.hansson@arm.com string keyword; 1949241Sandreas.hansson@arm.com string line; 1959241Sandreas.hansson@arm.com 1969241Sandreas.hansson@arm.com while (getline(infile, line).good()) { 1979241Sandreas.hansson@arm.com // see if this line is a comment line, and if so skip it 1989241Sandreas.hansson@arm.com if (line.find('#') != 1) { 1999241Sandreas.hansson@arm.com // create an input stream for the tokenization 2009241Sandreas.hansson@arm.com istringstream is(line); 2019241Sandreas.hansson@arm.com 2029241Sandreas.hansson@arm.com // determine the keyword 2039241Sandreas.hansson@arm.com is >> keyword; 2049241Sandreas.hansson@arm.com 2059241Sandreas.hansson@arm.com if (keyword == "STATE") { 2069241Sandreas.hansson@arm.com // parse the behaviour of this state 2079241Sandreas.hansson@arm.com uint32_t id; 2089241Sandreas.hansson@arm.com Tick duration; 2099241Sandreas.hansson@arm.com string mode; 2109241Sandreas.hansson@arm.com 2119241Sandreas.hansson@arm.com is >> id >> duration >> mode; 2129241Sandreas.hansson@arm.com 2139241Sandreas.hansson@arm.com if (mode == "TRACE") { 2149241Sandreas.hansson@arm.com string traceFile; 2159241Sandreas.hansson@arm.com Addr addrOffset; 2169241Sandreas.hansson@arm.com 2179241Sandreas.hansson@arm.com is >> traceFile >> addrOffset; 2189241Sandreas.hansson@arm.com 2199718Sandreas.hansson@arm.com states[id] = new TraceGen(name(), masterID, duration, 2209241Sandreas.hansson@arm.com traceFile, addrOffset); 2219241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d TraceGen\n", id); 2229241Sandreas.hansson@arm.com } else if (mode == "IDLE") { 2239718Sandreas.hansson@arm.com states[id] = new IdleGen(name(), masterID, duration); 2249241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d IdleGen\n", id); 2259241Sandreas.hansson@arm.com } else if (mode == "LINEAR" || mode == "RANDOM") { 2269241Sandreas.hansson@arm.com uint32_t read_percent; 2279241Sandreas.hansson@arm.com Addr start_addr; 2289241Sandreas.hansson@arm.com Addr end_addr; 2299241Sandreas.hansson@arm.com Addr blocksize; 2309241Sandreas.hansson@arm.com Tick min_period; 2319241Sandreas.hansson@arm.com Tick max_period; 2329241Sandreas.hansson@arm.com Addr data_limit; 2339241Sandreas.hansson@arm.com 2349241Sandreas.hansson@arm.com is >> read_percent >> start_addr >> end_addr >> 2359241Sandreas.hansson@arm.com blocksize >> min_period >> max_period >> data_limit; 2369241Sandreas.hansson@arm.com 2379241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "%s, addr %x to %x, size %d," 2389241Sandreas.hansson@arm.com " period %d to %d, %d%% reads\n", 2399241Sandreas.hansson@arm.com mode, start_addr, end_addr, blocksize, min_period, 2409241Sandreas.hansson@arm.com max_period, read_percent); 2419241Sandreas.hansson@arm.com 2429718Sandreas.hansson@arm.com 2439718Sandreas.hansson@arm.com if (port.deviceBlockSize() && 2449718Sandreas.hansson@arm.com blocksize > port.deviceBlockSize()) 2459718Sandreas.hansson@arm.com fatal("TrafficGen %s block size (%d) is larger than " 2469718Sandreas.hansson@arm.com "port block size (%d)\n", name(), 2479718Sandreas.hansson@arm.com blocksize, port.deviceBlockSize()); 2489718Sandreas.hansson@arm.com 2499241Sandreas.hansson@arm.com if (read_percent > 100) 2509718Sandreas.hansson@arm.com fatal("%s cannot have more than 100% reads", name()); 2519241Sandreas.hansson@arm.com 2529241Sandreas.hansson@arm.com if (mode == "LINEAR") { 2539718Sandreas.hansson@arm.com states[id] = new LinearGen(name(), masterID, 2549241Sandreas.hansson@arm.com duration, start_addr, 2559241Sandreas.hansson@arm.com end_addr, blocksize, 2569241Sandreas.hansson@arm.com min_period, max_period, 2579241Sandreas.hansson@arm.com read_percent, data_limit); 2589241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d LinearGen\n", id); 2599241Sandreas.hansson@arm.com } else if (mode == "RANDOM") { 2609718Sandreas.hansson@arm.com states[id] = new RandomGen(name(), masterID, 2619241Sandreas.hansson@arm.com duration, start_addr, 2629241Sandreas.hansson@arm.com end_addr, blocksize, 2639241Sandreas.hansson@arm.com min_period, max_period, 2649241Sandreas.hansson@arm.com read_percent, data_limit); 2659241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "State: %d RandomGen\n", id); 2669241Sandreas.hansson@arm.com } 2679241Sandreas.hansson@arm.com } else { 2689241Sandreas.hansson@arm.com fatal("%s: Unknown traffic generator mode: %s", 2699241Sandreas.hansson@arm.com name(), mode); 2709241Sandreas.hansson@arm.com } 2719241Sandreas.hansson@arm.com } else if (keyword == "TRANSITION") { 2729241Sandreas.hansson@arm.com Transition transition; 2739241Sandreas.hansson@arm.com 2749241Sandreas.hansson@arm.com is >> transition.from >> transition.to >> transition.p; 2759241Sandreas.hansson@arm.com 2769241Sandreas.hansson@arm.com transitions.push_back(transition); 2779241Sandreas.hansson@arm.com 2789241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from, 2799241Sandreas.hansson@arm.com transition.to); 2809241Sandreas.hansson@arm.com } else if (keyword == "INIT") { 2819241Sandreas.hansson@arm.com // set the initial state as the active state 2829241Sandreas.hansson@arm.com is >> currState; 2839241Sandreas.hansson@arm.com 2849241Sandreas.hansson@arm.com DPRINTF(TrafficGen, "Initial state: %d\n", currState); 2859241Sandreas.hansson@arm.com } 2869241Sandreas.hansson@arm.com } 2879241Sandreas.hansson@arm.com } 2889241Sandreas.hansson@arm.com 2899241Sandreas.hansson@arm.com // resize and populate state transition matrix 2909241Sandreas.hansson@arm.com transitionMatrix.resize(transitions.size()); 2919241Sandreas.hansson@arm.com for (size_t i = 0; i < transitions.size(); i++) { 2929241Sandreas.hansson@arm.com transitionMatrix[i].resize(transitions.size()); 2939241Sandreas.hansson@arm.com } 2949241Sandreas.hansson@arm.com 2959241Sandreas.hansson@arm.com for (vector<Transition>::iterator t = transitions.begin(); 2969241Sandreas.hansson@arm.com t != transitions.end(); ++t) { 2979241Sandreas.hansson@arm.com transitionMatrix[t->from][t->to] = t->p; 2989241Sandreas.hansson@arm.com } 2999241Sandreas.hansson@arm.com 3009241Sandreas.hansson@arm.com // ensure the egress edges do not have a probability larger than 3019241Sandreas.hansson@arm.com // one 3029241Sandreas.hansson@arm.com for (size_t i = 0; i < transitions.size(); i++) { 3039241Sandreas.hansson@arm.com double sum = 0; 3049241Sandreas.hansson@arm.com for (size_t j = 0; j < transitions.size(); j++) { 3059241Sandreas.hansson@arm.com sum += transitionMatrix[i][j]; 3069241Sandreas.hansson@arm.com } 3079241Sandreas.hansson@arm.com 3089241Sandreas.hansson@arm.com // avoid comparing floating point numbers 3099241Sandreas.hansson@arm.com if (abs(sum - 1.0) > 0.001) 3109241Sandreas.hansson@arm.com fatal("%s has transition probability != 1 for state %d\n", 3119241Sandreas.hansson@arm.com name(), i); 3129241Sandreas.hansson@arm.com } 3139241Sandreas.hansson@arm.com 3149241Sandreas.hansson@arm.com // close input file 3159241Sandreas.hansson@arm.com infile.close(); 3169241Sandreas.hansson@arm.com} 3179241Sandreas.hansson@arm.com 3189241Sandreas.hansson@arm.comvoid 3199717Sandreas.hansson@arm.comTrafficGen::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 3389717Sandreas.hansson@arm.comTrafficGen::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.combool 3489241Sandreas.hansson@arm.comTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) 3499241Sandreas.hansson@arm.com{ 3509241Sandreas.hansson@arm.com delete pkt->req; 3519241Sandreas.hansson@arm.com delete pkt; 3529241Sandreas.hansson@arm.com 3539241Sandreas.hansson@arm.com return true; 3549241Sandreas.hansson@arm.com} 355