traffic_gen.cc revision 9718:1cfcc2960e9f
17008Snate@binkert.org/* 27008Snate@binkert.org * Copyright (c) 2012-2013 ARM Limited 37008Snate@binkert.org * All rights reserved 47008Snate@binkert.org * 57008Snate@binkert.org * The license below extends only to copyright in the software and shall 67008Snate@binkert.org * not be construed as granting a license to any other intellectual 77008Snate@binkert.org * property including but not limited to intellectual property relating 87008Snate@binkert.org * to a hardware implementation of the functionality of the software 97008Snate@binkert.org * licensed hereunder. You may use the software subject to the license 107008Snate@binkert.org * terms below provided that you ensure that this notice is replicated 117008Snate@binkert.org * unmodified and in its entirety in all distributions of the software, 127008Snate@binkert.org * modified or unmodified, in source code or in binary form. 137008Snate@binkert.org * 147008Snate@binkert.org * Redistribution and use in source and binary forms, with or without 157008Snate@binkert.org * modification, are permitted provided that the following conditions are 167008Snate@binkert.org * met: redistributions of source code must retain the above copyright 177008Snate@binkert.org * notice, this list of conditions and the following disclaimer; 187008Snate@binkert.org * redistributions in binary form must reproduce the above copyright 197008Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 207008Snate@binkert.org * documentation and/or other materials provided with the distribution; 217008Snate@binkert.org * neither the name of the copyright holders nor the names of its 227008Snate@binkert.org * contributors may be used to endorse or promote products derived from 237008Snate@binkert.org * this software without specific prior written permission. 247008Snate@binkert.org * 257008Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 267008Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 277008Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 286285Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 2910472Sandreas.hansson@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 3010472Sandreas.hansson@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 318232Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 329104Shestness@cs.utexas.edu * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 337039Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3411339SMichael.Lebeane@amd.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 357039Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3611108Sdavid.hashe@amd.com * 376285Snate@binkert.org * Authors: Thomas Grass 3811702Smichael.lebeane@amd.com * Andreas Hansson 3911702Smichael.lebeane@amd.com * Sascha Bischoff 4011702Smichael.lebeane@amd.com */ 4111702Smichael.lebeane@amd.com 4211702Smichael.lebeane@amd.com#include <sstream> 4311702Smichael.lebeane@amd.com 4411702Smichael.lebeane@amd.com#include "base/random.hh" 4511702Smichael.lebeane@amd.com#include "cpu/testers/traffic_gen/traffic_gen.hh" 4611702Smichael.lebeane@amd.com#include "debug/Checkpoint.hh" 476876Ssteve.reinhardt@amd.com#include "debug/TrafficGen.hh" 4811702Smichael.lebeane@amd.com#include "sim/stats.hh" 4911702Smichael.lebeane@amd.com#include "sim/system.hh" 506285Snate@binkert.org 516285Snate@binkert.orgusing namespace std; 526285Snate@binkert.org 537039Snate@binkert.orgTrafficGen::TrafficGen(const TrafficGenParams* p) 547039Snate@binkert.org : MemObject(p), 556285Snate@binkert.org system(p->system), 5611339SMichael.Lebeane@amd.com masterID(system->getMasterId(name())), 5711443Sandreas.hansson@arm.com configFile(p->config_file), 5811346Santhony.gutierrez@amd.com nextTransitionTick(0), 5911346Santhony.gutierrez@amd.com port(name() + ".port", *this), 6011346Santhony.gutierrez@amd.com updateEvent(this) 6110518Snilay@cs.wisc.edu{ 6210518Snilay@cs.wisc.edu} 637039Snate@binkert.org 648615Snilay@cs.wisc.eduTrafficGen* 656285Snate@binkert.orgTrafficGenParams::create() 6611702Smichael.lebeane@amd.com{ 677544SBrad.Beckmann@amd.com return new TrafficGen(this); 687544SBrad.Beckmann@amd.com} 697544SBrad.Beckmann@amd.com 7011025Snilay@cs.wisc.eduBaseMasterPort& 7110562Sandreas.hansson@arm.comTrafficGen::getMasterPort(const string& if_name, PortID idx) 728615Snilay@cs.wisc.edu{ 738615Snilay@cs.wisc.edu if (if_name == "port") { 746285Snate@binkert.org return port; 7511702Smichael.lebeane@amd.com } else { 7611702Smichael.lebeane@amd.com return MemObject::getMasterPort(if_name, idx); 7711702Smichael.lebeane@amd.com } 7811702Smichael.lebeane@amd.com} 7911702Smichael.lebeane@amd.com 8011702Smichael.lebeane@amd.comvoid 8111702Smichael.lebeane@amd.comTrafficGen::init() 8211702Smichael.lebeane@amd.com{ 836285Snate@binkert.org if (!port.isConnected()) 8411702Smichael.lebeane@amd.com fatal("The port of %s is not connected!\n", name()); 8511702Smichael.lebeane@amd.com 8611702Smichael.lebeane@amd.com // if the system is in timing mode active the request generator 8711702Smichael.lebeane@amd.com if (system->isTimingMode()) { 8811702Smichael.lebeane@amd.com DPRINTF(TrafficGen, "Timing mode, activating request generator\n"); 8911702Smichael.lebeane@amd.com 9011702Smichael.lebeane@amd.com parseConfig(); 9111702Smichael.lebeane@amd.com 9211702Smichael.lebeane@amd.com // enter initial state 936285Snate@binkert.org enterState(currState); 9410472Sandreas.hansson@arm.com } else { 9510472Sandreas.hansson@arm.com DPRINTF(TrafficGen, 9611025Snilay@cs.wisc.edu "Traffic generator is only active in timing mode\n"); 9711702Smichael.lebeane@amd.com } 987453Snate@binkert.org} 997039Snate@binkert.org 1006888SBrad.Beckmann@amd.comvoid 1017453Snate@binkert.orgTrafficGen::initState() 1027039Snate@binkert.org{ 1036888SBrad.Beckmann@amd.com // when not restoring from a checkpoint, make sure we kick things off 1047915SBrad.Beckmann@amd.com if (system->isTimingMode()) { 1057915SBrad.Beckmann@amd.com schedule(updateEvent, nextEventTick()); 1067915SBrad.Beckmann@amd.com } else { 1077915SBrad.Beckmann@amd.com DPRINTF(TrafficGen, 1087039Snate@binkert.org "Traffic generator is only active in timing mode\n"); 1096888SBrad.Beckmann@amd.com } 11011702Smichael.lebeane@amd.com} 11111702Smichael.lebeane@amd.com 1127039Snate@binkert.orgunsigned int 11311111Snilay@cs.wisc.eduTrafficGen::drain(DrainManager *dm) 1147453Snate@binkert.org{ 1156285Snate@binkert.org // @todo we should also stop putting new requests in the queue and 1167039Snate@binkert.org // either interrupt the current state or wait for a transition 1176285Snate@binkert.org return port.drain(dm); 1186285Snate@binkert.org} 1197039Snate@binkert.org 12011702Smichael.lebeane@amd.comvoid 1216285Snate@binkert.orgTrafficGen::serialize(ostream &os) 12211702Smichael.lebeane@amd.com{ 12311702Smichael.lebeane@amd.com DPRINTF(Checkpoint, "Serializing TrafficGen\n"); 12411702Smichael.lebeane@amd.com 12511702Smichael.lebeane@amd.com // save ticks of the graph event if it is scheduled 12611702Smichael.lebeane@amd.com Tick nextEvent = updateEvent.scheduled() ? 12711702Smichael.lebeane@amd.com updateEvent.when() : 0; 1287039Snate@binkert.org 1297039Snate@binkert.org DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", 13011702Smichael.lebeane@amd.com nextEvent); 13111702Smichael.lebeane@amd.com 13211702Smichael.lebeane@amd.com SERIALIZE_SCALAR(nextEvent); 13311702Smichael.lebeane@amd.com 13411702Smichael.lebeane@amd.com SERIALIZE_SCALAR(nextTransitionTick); 13511702Smichael.lebeane@amd.com 1367039Snate@binkert.org // @todo: also serialise the current state, figure out the best 1377039Snate@binkert.org // way to drain and restore 1386285Snate@binkert.org} 13910472Sandreas.hansson@arm.com 14010472Sandreas.hansson@arm.comvoid 14111025Snilay@cs.wisc.eduTrafficGen::unserialize(Checkpoint* cp, const string& section) 14211025Snilay@cs.wisc.edu{ 1436888SBrad.Beckmann@amd.com // restore scheduled events 14411025Snilay@cs.wisc.edu Tick nextEvent; 14511025Snilay@cs.wisc.edu UNSERIALIZE_SCALAR(nextEvent); 1466888SBrad.Beckmann@amd.com if (nextEvent != 0) { 1477453Snate@binkert.org schedule(updateEvent, nextEvent); 1487039Snate@binkert.org } 1496888SBrad.Beckmann@amd.com 1507453Snate@binkert.org UNSERIALIZE_SCALAR(nextTransitionTick); 1517039Snate@binkert.org} 1527039Snate@binkert.org 1537039Snate@binkert.orgvoid 1547039Snate@binkert.orgTrafficGen::update() 1556888SBrad.Beckmann@amd.com{ 1567039Snate@binkert.org // schedule next update event based on either the next execute 1577453Snate@binkert.org // tick or the next transition, which ever comes first 1587039Snate@binkert.org Tick nextEvent = nextEventTick(); 1597453Snate@binkert.org DPRINTF(TrafficGen, "Updating state graph, next event at %lld\n", 1607039Snate@binkert.org nextEvent); 1616888SBrad.Beckmann@amd.com schedule(updateEvent, nextEvent); 1627039Snate@binkert.org 16311111Snilay@cs.wisc.edu // perform the update associated with the current update event 1647453Snate@binkert.org 16510917Sbrandon.potter@amd.com // if we have reached the time for the next state transition, then 1668160SBrad.Beckmann@amd.com // perform the transition 1678160SBrad.Beckmann@amd.com if (curTick() >= nextTransitionTick) { 1688160SBrad.Beckmann@amd.com transition(); 1696285Snate@binkert.org } else { 1706285Snate@binkert.org // we are still in the current state and should execute it 1717039Snate@binkert.org PacketPtr pkt = states[currState]->getNextPacket(); 17211702Smichael.lebeane@amd.com port.schedTimingReq(pkt, curTick()); 1736285Snate@binkert.org } 17411702Smichael.lebeane@amd.com} 17511702Smichael.lebeane@amd.com 17611702Smichael.lebeane@amd.comvoid 17711702Smichael.lebeane@amd.comTrafficGen::parseConfig() 17811702Smichael.lebeane@amd.com{ 1797039Snate@binkert.org // keep track of the transitions parsed to create the matrix when 1807039Snate@binkert.org // done 1817039Snate@binkert.org vector<Transition> transitions; 1827039Snate@binkert.org 18310231Ssteve.reinhardt@amd.com // open input file 1847915SBrad.Beckmann@amd.com ifstream infile; 1857915SBrad.Beckmann@amd.com infile.open(configFile.c_str(), ifstream::in); 1867915SBrad.Beckmann@amd.com if (!infile.is_open()) { 1877915SBrad.Beckmann@amd.com fatal("Traffic generator %s config file not found at %s\n", 18811702Smichael.lebeane@amd.com name(), configFile); 1896285Snate@binkert.org } 1906285Snate@binkert.org 1917039Snate@binkert.org // read line by line and determine the action based on the first 19211702Smichael.lebeane@amd.com // keyword 1936285Snate@binkert.org string keyword; 19411778Santhony.gutierrez@amd.com string line; 19511702Smichael.lebeane@amd.com 1966285Snate@binkert.org while (getline(infile, line).good()) { 1976285Snate@binkert.org // see if this line is a comment line, and if so skip it 1987039Snate@binkert.org if (line.find('#') != 1) { 19910518Snilay@cs.wisc.edu // create an input stream for the tokenization 20010518Snilay@cs.wisc.edu istringstream is(line); 2019104Shestness@cs.utexas.edu 2029104Shestness@cs.utexas.edu // determine the keyword 2039104Shestness@cs.utexas.edu is >> keyword; 2049104Shestness@cs.utexas.edu 2056876Ssteve.reinhardt@amd.com if (keyword == "STATE") { 2066876Ssteve.reinhardt@amd.com // parse the behaviour of this state 2076876Ssteve.reinhardt@amd.com uint32_t id; 2086876Ssteve.reinhardt@amd.com Tick duration; 2096876Ssteve.reinhardt@amd.com string mode; 210 211 is >> id >> duration >> mode; 212 213 if (mode == "TRACE") { 214 string traceFile; 215 Addr addrOffset; 216 217 is >> traceFile >> addrOffset; 218 219 states[id] = new TraceGen(name(), masterID, duration, 220 traceFile, addrOffset); 221 DPRINTF(TrafficGen, "State: %d TraceGen\n", id); 222 } else if (mode == "IDLE") { 223 states[id] = new IdleGen(name(), masterID, duration); 224 DPRINTF(TrafficGen, "State: %d IdleGen\n", id); 225 } else if (mode == "LINEAR" || mode == "RANDOM") { 226 uint32_t read_percent; 227 Addr start_addr; 228 Addr end_addr; 229 Addr blocksize; 230 Tick min_period; 231 Tick max_period; 232 Addr data_limit; 233 234 is >> read_percent >> start_addr >> end_addr >> 235 blocksize >> min_period >> max_period >> data_limit; 236 237 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d," 238 " period %d to %d, %d%% reads\n", 239 mode, start_addr, end_addr, blocksize, min_period, 240 max_period, read_percent); 241 242 243 if (port.deviceBlockSize() && 244 blocksize > port.deviceBlockSize()) 245 fatal("TrafficGen %s block size (%d) is larger than " 246 "port block size (%d)\n", name(), 247 blocksize, port.deviceBlockSize()); 248 249 if (read_percent > 100) 250 fatal("%s cannot have more than 100% reads", name()); 251 252 if (mode == "LINEAR") { 253 states[id] = new LinearGen(name(), masterID, 254 duration, start_addr, 255 end_addr, blocksize, 256 min_period, max_period, 257 read_percent, data_limit); 258 DPRINTF(TrafficGen, "State: %d LinearGen\n", id); 259 } else if (mode == "RANDOM") { 260 states[id] = new RandomGen(name(), masterID, 261 duration, start_addr, 262 end_addr, blocksize, 263 min_period, max_period, 264 read_percent, data_limit); 265 DPRINTF(TrafficGen, "State: %d RandomGen\n", id); 266 } 267 } else { 268 fatal("%s: Unknown traffic generator mode: %s", 269 name(), mode); 270 } 271 } else if (keyword == "TRANSITION") { 272 Transition transition; 273 274 is >> transition.from >> transition.to >> transition.p; 275 276 transitions.push_back(transition); 277 278 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from, 279 transition.to); 280 } else if (keyword == "INIT") { 281 // set the initial state as the active state 282 is >> currState; 283 284 DPRINTF(TrafficGen, "Initial state: %d\n", currState); 285 } 286 } 287 } 288 289 // resize and populate state transition matrix 290 transitionMatrix.resize(transitions.size()); 291 for (size_t i = 0; i < transitions.size(); i++) { 292 transitionMatrix[i].resize(transitions.size()); 293 } 294 295 for (vector<Transition>::iterator t = transitions.begin(); 296 t != transitions.end(); ++t) { 297 transitionMatrix[t->from][t->to] = t->p; 298 } 299 300 // ensure the egress edges do not have a probability larger than 301 // one 302 for (size_t i = 0; i < transitions.size(); i++) { 303 double sum = 0; 304 for (size_t j = 0; j < transitions.size(); j++) { 305 sum += transitionMatrix[i][j]; 306 } 307 308 // avoid comparing floating point numbers 309 if (abs(sum - 1.0) > 0.001) 310 fatal("%s has transition probability != 1 for state %d\n", 311 name(), i); 312 } 313 314 // close input file 315 infile.close(); 316} 317 318void 319TrafficGen::transition() 320{ 321 // exit the current state 322 states[currState]->exit(); 323 324 // determine next state 325 double p = random_mt.gen_real1(); 326 assert(currState < transitionMatrix.size()); 327 double cumulative = 0.0; 328 size_t i = 0; 329 do { 330 cumulative += transitionMatrix[currState][i]; 331 ++i; 332 } while (cumulative < p && i < transitionMatrix[currState].size()); 333 334 enterState(i - 1); 335} 336 337void 338TrafficGen::enterState(uint32_t newState) 339{ 340 DPRINTF(TrafficGen, "Transition to state %d\n", newState); 341 342 currState = newState; 343 nextTransitionTick += states[currState]->duration; 344 states[currState]->enter(); 345} 346 347bool 348TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) 349{ 350 delete pkt->req; 351 delete pkt; 352 353 return true; 354} 355