traffic_gen.cc revision 10128
12SN/A/* 21762SN/A * Copyright (c) 2012-2013 ARM Limited 32SN/A * All rights reserved 42SN/A * 52SN/A * The license below extends only to copyright in the software and shall 62SN/A * not be construed as granting a license to any other intellectual 72SN/A * property including but not limited to intellectual property relating 82SN/A * to a hardware implementation of the functionality of the software 92SN/A * licensed hereunder. You may use the software subject to the license 102SN/A * terms below provided that you ensure that this notice is replicated 112SN/A * unmodified and in its entirety in all distributions of the software, 122SN/A * modified or unmodified, in source code or in binary form. 132SN/A * 142SN/A * Redistribution and use in source and binary forms, with or without 152SN/A * modification, are permitted provided that the following conditions are 162SN/A * met: redistributions of source code must retain the above copyright 172SN/A * notice, this list of conditions and the following disclaimer; 182SN/A * redistributions in binary form must reproduce the above copyright 192SN/A * notice, this list of conditions and the following disclaimer in the 202SN/A * documentation and/or other materials provided with the distribution; 212SN/A * neither the name of the copyright holders nor the names of its 222SN/A * contributors may be used to endorse or promote products derived from 232SN/A * this software without specific prior written permission. 242SN/A * 252SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 262SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 272665Ssaidi@eecs.umich.edu * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 282760Sbinkertn@umich.edu * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 292760Sbinkertn@umich.edu * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 302665Ssaidi@eecs.umich.edu * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 312SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 322SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 332SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 342SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 352SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 362SN/A * 372SN/A * Authors: Thomas Grass 382SN/A * Andreas Hansson 392SN/A * Sascha Bischoff 402SN/A */ 412SN/A 424841Ssaidi@eecs.umich.edu#include <sstream> 432SN/A 44217SN/A#include "base/random.hh" 452SN/A#include "cpu/testers/traffic_gen/traffic_gen.hh" 4656SN/A#include "debug/Checkpoint.hh" 472SN/A#include "debug/TrafficGen.hh" 482738Sstever@eecs.umich.edu#include "sim/stats.hh" 49395SN/A#include "sim/system.hh" 50237SN/A 514000Ssaidi@eecs.umich.eduusing namespace std; 522SN/A 53217SN/ATrafficGen::TrafficGen(const TrafficGenParams* p) 54502SN/A : MemObject(p), 55217SN/A system(p->system), 56217SN/A masterID(system->getMasterId(name())), 57237SN/A configFile(p->config_file), 58502SN/A elasticReq(p->elastic_req), 59217SN/A nextTransitionTick(0), 60217SN/A nextPacketTick(0), 61217SN/A port(name() + ".port", *this), 62217SN/A retryPkt(NULL), 63217SN/A retryPktTick(0), 64217SN/A updateEvent(this), 654841Ssaidi@eecs.umich.edu drainManager(NULL) 664841Ssaidi@eecs.umich.edu{ 674841Ssaidi@eecs.umich.edu} 684841Ssaidi@eecs.umich.edu 69237SN/ATrafficGen* 70217SN/ATrafficGenParams::create() 71217SN/A{ 724841Ssaidi@eecs.umich.edu return new TrafficGen(this); 734841Ssaidi@eecs.umich.edu} 744841Ssaidi@eecs.umich.edu 754841Ssaidi@eecs.umich.eduBaseMasterPort& 76237SN/ATrafficGen::getMasterPort(const string& if_name, PortID idx) 77237SN/A{ 784000Ssaidi@eecs.umich.edu if (if_name == "port") { 79237SN/A return port; 80237SN/A } else { 81217SN/A return MemObject::getMasterPort(if_name, idx); 82217SN/A } 83217SN/A} 84237SN/A 85222SN/Avoid 86217SN/ATrafficGen::init() 87237SN/A{ 88217SN/A if (!port.isConnected()) 89223SN/A fatal("The port of %s is not connected!\n", name()); 90223SN/A 91223SN/A // if the system is in timing mode active the request generator 92223SN/A if (system->isTimingMode()) { 93223SN/A DPRINTF(TrafficGen, "Timing mode, activating request generator\n"); 94223SN/A 95237SN/A parseConfig(); 96223SN/A 97223SN/A // enter initial state 98223SN/A enterState(currState); 99217SN/A } else { 100217SN/A DPRINTF(TrafficGen, 101217SN/A "Traffic generator is only active in timing mode\n"); 102217SN/A } 103237SN/A} 104237SN/A 105237SN/Avoid 106237SN/ATrafficGen::initState() 107237SN/A{ 108237SN/A // when not restoring from a checkpoint, make sure we kick things off 1094000Ssaidi@eecs.umich.edu if (system->isTimingMode()) { 110237SN/A // call nextPacketTick on the state to advance it 111237SN/A nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); 112237SN/A schedule(updateEvent, std::min(nextPacketTick, nextTransitionTick)); 113217SN/A } else { 1142SN/A DPRINTF(TrafficGen, 1152SN/A "Traffic generator is only active in timing mode\n"); 1162SN/A } 117395SN/A} 1182SN/A 1192SN/Aunsigned int 120510SN/ATrafficGen::drain(DrainManager *dm) 121510SN/A{ 1222SN/A if (!updateEvent.scheduled()) { 1232SN/A // no event has been scheduled yet (e.g. switched from atomic mode) 124395SN/A return 0; 125395SN/A } 1262SN/A 127265SN/A if (retryPkt == NULL) { 128512SN/A // shut things down 1292SN/A nextPacketTick = MaxTick; 130510SN/A nextTransitionTick = MaxTick; 131237SN/A deschedule(updateEvent); 132237SN/A return 0; 133395SN/A } else { 134237SN/A drainManager = dm; 1352SN/A return 1; 1362287SN/A } 1372287SN/A} 1382287SN/A 1392868Sktlim@umich.eduvoid 1402868Sktlim@umich.eduTrafficGen::serialize(ostream &os) 141395SN/A{ 1422SN/A DPRINTF(Checkpoint, "Serializing TrafficGen\n"); 1432SN/A 1442SN/A // save ticks of the graph event if it is scheduled 145395SN/A Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0; 146395SN/A 1472SN/A DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent); 1482SN/A 1492SN/A SERIALIZE_SCALAR(nextEvent); 150395SN/A 1512SN/A SERIALIZE_SCALAR(nextTransitionTick); 152395SN/A 1532SN/A SERIALIZE_SCALAR(nextPacketTick); 1542SN/A 155395SN/A SERIALIZE_SCALAR(currState); 1562SN/A} 157395SN/A 1582SN/Avoid 1592SN/ATrafficGen::unserialize(Checkpoint* cp, const string& section) 1602SN/A{ 161395SN/A // restore scheduled events 1622SN/A Tick nextEvent; 163395SN/A UNSERIALIZE_SCALAR(nextEvent); 1642SN/A if (nextEvent != 0) { 165395SN/A schedule(updateEvent, nextEvent); 1662SN/A } 1672SN/A 168395SN/A UNSERIALIZE_SCALAR(nextTransitionTick); 169395SN/A 1702SN/A UNSERIALIZE_SCALAR(nextPacketTick); 1712SN/A 1722SN/A // @todo In the case of a stateful generator state such as the 173395SN/A // trace player we would also have to restore the position in the 174395SN/A // trace playback and the tick offset 1752SN/A UNSERIALIZE_SCALAR(currState); 1762SN/A} 1772SN/A 1782SN/Avoid 1792SN/ATrafficGen::update() 1802SN/A{ 181395SN/A // if we have reached the time for the next state transition, then 1822SN/A // perform the transition 1832SN/A if (curTick() >= nextTransitionTick) { 1842SN/A transition(); 1852SN/A } else { 1862SN/A assert(curTick() >= nextPacketTick); 1872SN/A // get the next packet and try to send it 1882SN/A PacketPtr pkt = states[currState]->getNextPacket(); 1892SN/A numPackets++; 190395SN/A if (!port.sendTimingReq(pkt)) { 191395SN/A retryPkt = pkt; 1922738Sstever@eecs.umich.edu retryPktTick = curTick(); 1932SN/A } 1942SN/A } 1952SN/A 1962SN/A // if we are waiting for a retry, do not schedule any further 1972SN/A // events, in the case of a transition or a successful send, go 198395SN/A // ahead and determine when the next update should take place 199395SN/A if (retryPkt == NULL) { 2002SN/A // schedule next update event based on either the next execute 201395SN/A // tick or the next transition, which ever comes first 2022SN/A nextPacketTick = states[currState]->nextPacketTick(elasticReq, 0); 203395SN/A Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); 2042SN/A DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick); 205395SN/A schedule(updateEvent, nextEventTick); 2062738Sstever@eecs.umich.edu } 2072SN/A} 2082SN/A 2092SN/Avoid 2102SN/ATrafficGen::parseConfig() 211395SN/A{ 2122SN/A // keep track of the transitions parsed to create the matrix when 2132SN/A // done 214237SN/A vector<Transition> transitions; 215395SN/A 216237SN/A // open input file 2172SN/A ifstream infile; 2182797Sktlim@umich.edu infile.open(configFile.c_str(), ifstream::in); 2192868Sktlim@umich.edu if (!infile.is_open()) { 2202797Sktlim@umich.edu fatal("Traffic generator %s config file not found at %s\n", 221237SN/A name(), configFile); 222237SN/A } 223237SN/A 224237SN/A bool init_state_set = false; 225237SN/A 226237SN/A // read line by line and determine the action based on the first 227395SN/A // keyword 228237SN/A string keyword; 229237SN/A string line; 2302738Sstever@eecs.umich.edu 231237SN/A while (getline(infile, line).good()) { 232937SN/A // see if this line is a comment line, and if so skip it 233937SN/A if (line.find('#') != 1) { 234237SN/A // create an input stream for the tokenization 235237SN/A istringstream is(line); 236237SN/A 237237SN/A // determine the keyword 2384000Ssaidi@eecs.umich.edu is >> keyword; 239304SN/A 240304SN/A if (keyword == "STATE") { 241449SN/A // parse the behaviour of this state 242449SN/A uint32_t id; 243449SN/A Tick duration; 244449SN/A string mode; 245449SN/A 246449SN/A is >> id >> duration >> mode; 247449SN/A 248449SN/A if (mode == "TRACE") { 249449SN/A string traceFile; 250449SN/A Addr addrOffset; 251449SN/A 252449SN/A is >> traceFile >> addrOffset; 253449SN/A 254237SN/A states[id] = new TraceGen(name(), masterID, duration, 2552SN/A traceFile, addrOffset); 2562SN/A DPRINTF(TrafficGen, "State: %d TraceGen\n", id); 257 } else if (mode == "IDLE") { 258 states[id] = new IdleGen(name(), masterID, duration); 259 DPRINTF(TrafficGen, "State: %d IdleGen\n", id); 260 } else if (mode == "LINEAR" || mode == "RANDOM") { 261 uint32_t read_percent; 262 Addr start_addr; 263 Addr end_addr; 264 Addr blocksize; 265 Tick min_period; 266 Tick max_period; 267 Addr data_limit; 268 269 is >> read_percent >> start_addr >> end_addr >> 270 blocksize >> min_period >> max_period >> data_limit; 271 272 DPRINTF(TrafficGen, "%s, addr %x to %x, size %d," 273 " period %d to %d, %d%% reads\n", 274 mode, start_addr, end_addr, blocksize, min_period, 275 max_period, read_percent); 276 277 278 if (blocksize > system->cacheLineSize()) 279 fatal("TrafficGen %s block size (%d) is larger than " 280 "system block size (%d)\n", name(), 281 blocksize, system->cacheLineSize()); 282 283 if (read_percent > 100) 284 fatal("%s cannot have more than 100% reads", name()); 285 286 if (min_period > max_period) 287 fatal("%s cannot have min_period > max_period", name()); 288 289 if (mode == "LINEAR") { 290 states[id] = new LinearGen(name(), masterID, 291 duration, start_addr, 292 end_addr, blocksize, 293 min_period, max_period, 294 read_percent, data_limit); 295 DPRINTF(TrafficGen, "State: %d LinearGen\n", id); 296 } else if (mode == "RANDOM") { 297 states[id] = new RandomGen(name(), masterID, 298 duration, start_addr, 299 end_addr, blocksize, 300 min_period, max_period, 301 read_percent, data_limit); 302 DPRINTF(TrafficGen, "State: %d RandomGen\n", id); 303 } 304 } else { 305 fatal("%s: Unknown traffic generator mode: %s", 306 name(), mode); 307 } 308 } else if (keyword == "TRANSITION") { 309 Transition transition; 310 311 is >> transition.from >> transition.to >> transition.p; 312 313 transitions.push_back(transition); 314 315 DPRINTF(TrafficGen, "Transition: %d -> %d\n", transition.from, 316 transition.to); 317 } else if (keyword == "INIT") { 318 // set the initial state as the active state 319 is >> currState; 320 321 init_state_set = true; 322 323 DPRINTF(TrafficGen, "Initial state: %d\n", currState); 324 } 325 } 326 } 327 328 if (!init_state_set) 329 fatal("%s: initial state not specified (add 'INIT <id>' line " 330 "to the config file)\n", name()); 331 332 // resize and populate state transition matrix 333 transitionMatrix.resize(states.size()); 334 for (size_t i = 0; i < states.size(); i++) { 335 transitionMatrix[i].resize(states.size()); 336 } 337 338 for (vector<Transition>::iterator t = transitions.begin(); 339 t != transitions.end(); ++t) { 340 transitionMatrix[t->from][t->to] = t->p; 341 } 342 343 // ensure the egress edges do not have a probability larger than 344 // one 345 for (size_t i = 0; i < states.size(); i++) { 346 double sum = 0; 347 for (size_t j = 0; j < states.size(); j++) { 348 sum += transitionMatrix[i][j]; 349 } 350 351 // avoid comparing floating point numbers 352 if (abs(sum - 1.0) > 0.001) 353 fatal("%s has transition probability != 1 for state %d\n", 354 name(), i); 355 } 356 357 // close input file 358 infile.close(); 359} 360 361void 362TrafficGen::transition() 363{ 364 // exit the current state 365 states[currState]->exit(); 366 367 // determine next state 368 double p = random_mt.gen_real1(); 369 assert(currState < transitionMatrix.size()); 370 double cumulative = 0.0; 371 size_t i = 0; 372 do { 373 cumulative += transitionMatrix[currState][i]; 374 ++i; 375 } while (cumulative < p && i < transitionMatrix[currState].size()); 376 377 enterState(i - 1); 378} 379 380void 381TrafficGen::enterState(uint32_t newState) 382{ 383 DPRINTF(TrafficGen, "Transition to state %d\n", newState); 384 385 currState = newState; 386 // we could have been delayed and not transitioned on the exact 387 // tick when we were supposed to (due to back pressure when 388 // sending a packet) 389 nextTransitionTick = curTick() + states[currState]->duration; 390 states[currState]->enter(); 391} 392 393void 394TrafficGen::recvRetry() 395{ 396 assert(retryPkt != NULL); 397 398 DPRINTF(TrafficGen, "Received retry\n"); 399 numRetries++; 400 // attempt to send the packet, and if we are successful start up 401 // the machinery again 402 if (port.sendTimingReq(retryPkt)) { 403 retryPkt = NULL; 404 // remember how much delay was incurred due to back-pressure 405 // when sending the request, we also use this to derive 406 // the tick for the next packet 407 Tick delay = curTick() - retryPktTick; 408 retryPktTick = 0; 409 retryTicks += delay; 410 411 if (drainManager == NULL) { 412 // packet is sent, so find out when the next one is due 413 nextPacketTick = states[currState]->nextPacketTick(elasticReq, 414 delay); 415 Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); 416 schedule(updateEvent, std::max(curTick(), nextEventTick)); 417 } else { 418 // shut things down 419 nextPacketTick = MaxTick; 420 nextTransitionTick = MaxTick; 421 drainManager->signalDrainDone(); 422 // Clear the drain event once we're done with it. 423 drainManager = NULL; 424 } 425 } 426} 427 428void 429TrafficGen::regStats() 430{ 431 // Initialise all the stats 432 using namespace Stats; 433 434 numPackets 435 .name(name() + ".numPackets") 436 .desc("Number of packets generated"); 437 438 numRetries 439 .name(name() + ".numRetries") 440 .desc("Number of retries"); 441 442 retryTicks 443 .name(name() + ".retryTicks") 444 .desc("Time spent waiting due to back-pressure (ticks)"); 445} 446 447bool 448TrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) 449{ 450 delete pkt->req; 451 delete pkt; 452 453 return true; 454} 455