base.cc revision 12812:8f14879aebe1
18999Suri.wiener@arm.com/* 28999Suri.wiener@arm.com * Copyright (c) 2012-2013, 2016-2018 ARM Limited 38999Suri.wiener@arm.com * All rights reserved 48999Suri.wiener@arm.com * 58999Suri.wiener@arm.com * The license below extends only to copyright in the software and shall 68999Suri.wiener@arm.com * not be construed as granting a license to any other intellectual 78999Suri.wiener@arm.com * property including but not limited to intellectual property relating 88999Suri.wiener@arm.com * to a hardware implementation of the functionality of the software 98999Suri.wiener@arm.com * licensed hereunder. You may use the software subject to the license 108999Suri.wiener@arm.com * terms below provided that you ensure that this notice is replicated 118999Suri.wiener@arm.com * unmodified and in its entirety in all distributions of the software, 128999Suri.wiener@arm.com * modified or unmodified, in source code or in binary form. 138999Suri.wiener@arm.com * 148999Suri.wiener@arm.com * Redistribution and use in source and binary forms, with or without 158999Suri.wiener@arm.com * modification, are permitted provided that the following conditions are 168999Suri.wiener@arm.com * met: redistributions of source code must retain the above copyright 178999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer; 188999Suri.wiener@arm.com * redistributions in binary form must reproduce the above copyright 198999Suri.wiener@arm.com * notice, this list of conditions and the following disclaimer in the 208999Suri.wiener@arm.com * documentation and/or other materials provided with the distribution; 218999Suri.wiener@arm.com * neither the name of the copyright holders nor the names of its 228999Suri.wiener@arm.com * contributors may be used to endorse or promote products derived from 238999Suri.wiener@arm.com * this software without specific prior written permission. 248999Suri.wiener@arm.com * 258999Suri.wiener@arm.com * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 268999Suri.wiener@arm.com * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 278999Suri.wiener@arm.com * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 288999Suri.wiener@arm.com * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 298999Suri.wiener@arm.com * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 308999Suri.wiener@arm.com * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 318999Suri.wiener@arm.com * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 328999Suri.wiener@arm.com * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 338999Suri.wiener@arm.com * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 348999Suri.wiener@arm.com * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 358999Suri.wiener@arm.com * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 368999Suri.wiener@arm.com * 378999Suri.wiener@arm.com * Authors: Thomas Grass 388999Suri.wiener@arm.com * Andreas Hansson 398999Suri.wiener@arm.com * Sascha Bischoff 408999Suri.wiener@arm.com */ 418999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/base.hh" 428999Suri.wiener@arm.com 438999Suri.wiener@arm.com#include <sstream> 448999Suri.wiener@arm.com 458999Suri.wiener@arm.com#include "base/intmath.hh" 468999Suri.wiener@arm.com#include "base/random.hh" 478999Suri.wiener@arm.com#include "config/have_protobuf.hh" 488999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/base_gen.hh" 498999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/dram_gen.hh" 508999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/dram_rot_gen.hh" 518999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/exit_gen.hh" 528999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/idle_gen.hh" 538999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/linear_gen.hh" 548999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/random_gen.hh" 558999Suri.wiener@arm.com#include "debug/Checkpoint.hh" 568999Suri.wiener@arm.com#include "debug/TrafficGen.hh" 578999Suri.wiener@arm.com#include "params/BaseTrafficGen.hh" 588999Suri.wiener@arm.com#include "sim/sim_exit.hh" 598999Suri.wiener@arm.com#include "sim/stats.hh" 609528Ssascha.bischoff@arm.com#include "sim/system.hh" 618999Suri.wiener@arm.com 628999Suri.wiener@arm.com#if HAVE_PROTOBUF 638999Suri.wiener@arm.com#include "cpu/testers/traffic_gen/trace_gen.hh" 648999Suri.wiener@arm.com#endif 658999Suri.wiener@arm.com 668999Suri.wiener@arm.com 678999Suri.wiener@arm.comusing namespace std; 688999Suri.wiener@arm.com 698999Suri.wiener@arm.comBaseTrafficGen::BaseTrafficGen(const BaseTrafficGenParams* p) 708999Suri.wiener@arm.com : MemObject(p), 718999Suri.wiener@arm.com system(p->system), 728999Suri.wiener@arm.com elasticReq(p->elastic_req), 738999Suri.wiener@arm.com progressCheck(p->progress_check), 748999Suri.wiener@arm.com noProgressEvent([this]{ noProgress(); }, name()), 758999Suri.wiener@arm.com nextTransitionTick(0), 768999Suri.wiener@arm.com nextPacketTick(0), 778999Suri.wiener@arm.com port(name() + ".port", *this), 788999Suri.wiener@arm.com retryPkt(NULL), 798999Suri.wiener@arm.com retryPktTick(0), 808999Suri.wiener@arm.com updateEvent([this]{ update(); }, name()), 818999Suri.wiener@arm.com numSuppressed(0), 828999Suri.wiener@arm.com masterID(system->getMasterId(this)) 838999Suri.wiener@arm.com{ 848999Suri.wiener@arm.com} 858999Suri.wiener@arm.com 868999Suri.wiener@arm.comBaseMasterPort& 878999Suri.wiener@arm.comBaseTrafficGen::getMasterPort(const string& if_name, PortID idx) 888999Suri.wiener@arm.com{ 898999Suri.wiener@arm.com if (if_name == "port") { 908999Suri.wiener@arm.com return port; 918999Suri.wiener@arm.com } else { 928999Suri.wiener@arm.com return MemObject::getMasterPort(if_name, idx); 938999Suri.wiener@arm.com } 948999Suri.wiener@arm.com} 958999Suri.wiener@arm.com 968999Suri.wiener@arm.comvoid 978999Suri.wiener@arm.comBaseTrafficGen::init() 988999Suri.wiener@arm.com{ 998999Suri.wiener@arm.com MemObject::init(); 1008999Suri.wiener@arm.com 1018999Suri.wiener@arm.com if (!port.isConnected()) 1028999Suri.wiener@arm.com fatal("The port of %s is not connected!\n", name()); 1038999Suri.wiener@arm.com} 1048999Suri.wiener@arm.com 1058999Suri.wiener@arm.comDrainState 1068999Suri.wiener@arm.comBaseTrafficGen::drain() 1078999Suri.wiener@arm.com{ 1088999Suri.wiener@arm.com if (!updateEvent.scheduled()) { 1098999Suri.wiener@arm.com // no event has been scheduled yet (e.g. switched from atomic mode) 1108999Suri.wiener@arm.com return DrainState::Drained; 1118999Suri.wiener@arm.com } 1128999Suri.wiener@arm.com 1138999Suri.wiener@arm.com if (retryPkt == NULL) { 1148999Suri.wiener@arm.com // shut things down 1158999Suri.wiener@arm.com nextPacketTick = MaxTick; 1168999Suri.wiener@arm.com nextTransitionTick = MaxTick; 1178999Suri.wiener@arm.com deschedule(updateEvent); 1188999Suri.wiener@arm.com return DrainState::Drained; 1198999Suri.wiener@arm.com } else { 1208999Suri.wiener@arm.com return DrainState::Draining; 1218999Suri.wiener@arm.com } 1228999Suri.wiener@arm.com} 1238999Suri.wiener@arm.com 1248999Suri.wiener@arm.comvoid 1258999Suri.wiener@arm.comBaseTrafficGen::serialize(CheckpointOut &cp) const 1268999Suri.wiener@arm.com{ 1278999Suri.wiener@arm.com DPRINTF(Checkpoint, "Serializing BaseTrafficGen\n"); 1288999Suri.wiener@arm.com 1298999Suri.wiener@arm.com // save ticks of the graph event if it is scheduled 1308999Suri.wiener@arm.com Tick nextEvent = updateEvent.scheduled() ? updateEvent.when() : 0; 1318999Suri.wiener@arm.com 1328999Suri.wiener@arm.com DPRINTF(TrafficGen, "Saving nextEvent=%llu\n", nextEvent); 1338999Suri.wiener@arm.com 1348999Suri.wiener@arm.com SERIALIZE_SCALAR(nextEvent); 1358999Suri.wiener@arm.com 1368999Suri.wiener@arm.com SERIALIZE_SCALAR(nextTransitionTick); 1378999Suri.wiener@arm.com 1388999Suri.wiener@arm.com SERIALIZE_SCALAR(nextPacketTick); 1398999Suri.wiener@arm.com} 1408999Suri.wiener@arm.com 1418999Suri.wiener@arm.comvoid 1428999Suri.wiener@arm.comBaseTrafficGen::unserialize(CheckpointIn &cp) 1438999Suri.wiener@arm.com{ 1448999Suri.wiener@arm.com // restore scheduled events 1458999Suri.wiener@arm.com Tick nextEvent; 1468999Suri.wiener@arm.com UNSERIALIZE_SCALAR(nextEvent); 1478999Suri.wiener@arm.com if (nextEvent != 0) 1488999Suri.wiener@arm.com schedule(updateEvent, nextEvent); 1498999Suri.wiener@arm.com 1508999Suri.wiener@arm.com UNSERIALIZE_SCALAR(nextTransitionTick); 1518999Suri.wiener@arm.com 1528999Suri.wiener@arm.com UNSERIALIZE_SCALAR(nextPacketTick); 1538999Suri.wiener@arm.com} 1548999Suri.wiener@arm.com 1558999Suri.wiener@arm.comvoid 1568999Suri.wiener@arm.comBaseTrafficGen::update() 1578999Suri.wiener@arm.com{ 1588999Suri.wiener@arm.com // shift our progress-tracking event forward 1598999Suri.wiener@arm.com reschedule(noProgressEvent, curTick() + progressCheck, true); 1608999Suri.wiener@arm.com 1618999Suri.wiener@arm.com // if we have reached the time for the next state transition, then 1628999Suri.wiener@arm.com // perform the transition 1638999Suri.wiener@arm.com if (curTick() >= nextTransitionTick) { 1648999Suri.wiener@arm.com transition(); 1658999Suri.wiener@arm.com } else { 1668999Suri.wiener@arm.com assert(curTick() >= nextPacketTick); 1678999Suri.wiener@arm.com // get the next packet and try to send it 1688999Suri.wiener@arm.com PacketPtr pkt = activeGenerator->getNextPacket(); 1698999Suri.wiener@arm.com 1708999Suri.wiener@arm.com // suppress packets that are not destined for a memory, such as 1718999Suri.wiener@arm.com // device accesses that could be part of a trace 1728999Suri.wiener@arm.com if (pkt && system->isMemAddr(pkt->getAddr())) { 1738999Suri.wiener@arm.com numPackets++; 1748999Suri.wiener@arm.com if (!port.sendTimingReq(pkt)) { 1758999Suri.wiener@arm.com retryPkt = pkt; 1768999Suri.wiener@arm.com retryPktTick = curTick(); 1778999Suri.wiener@arm.com } 1788999Suri.wiener@arm.com } else if (pkt) { 1798999Suri.wiener@arm.com DPRINTF(TrafficGen, "Suppressed packet %s 0x%x\n", 1809528Ssascha.bischoff@arm.com pkt->cmdString(), pkt->getAddr()); 181 182 ++numSuppressed; 183 if (numSuppressed % 10000) 184 warn("%s suppressed %d packets with non-memory addresses\n", 185 name(), numSuppressed); 186 187 delete pkt; 188 pkt = nullptr; 189 } 190 } 191 192 // if we are waiting for a retry, do not schedule any further 193 // events, in the case of a transition or a successful send, go 194 // ahead and determine when the next update should take place 195 if (retryPkt == NULL) { 196 nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0); 197 scheduleUpdate(); 198 } 199} 200 201void 202BaseTrafficGen::transition() 203{ 204 if (activeGenerator) 205 activeGenerator->exit(); 206 207 activeGenerator = nextGenerator(); 208 209 if (activeGenerator) { 210 const Tick duration = activeGenerator->duration; 211 if (duration != MaxTick && duration != 0) { 212 // we could have been delayed and not transitioned on the 213 // exact tick when we were supposed to (due to back 214 // pressure when sending a packet) 215 nextTransitionTick = curTick() + duration; 216 } else { 217 nextTransitionTick = MaxTick; 218 } 219 220 activeGenerator->enter(); 221 nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 0); 222 } else { 223 nextPacketTick = MaxTick; 224 nextTransitionTick = MaxTick; 225 assert(!updateEvent.scheduled()); 226 } 227} 228 229void 230BaseTrafficGen::scheduleUpdate() 231{ 232 // Has the generator run out of work? In that case, force a 233 // transition if a transition period hasn't been configured. 234 while (activeGenerator && 235 nextPacketTick == MaxTick && nextTransitionTick == MaxTick) { 236 transition(); 237 } 238 239 if (!activeGenerator) 240 return; 241 242 // schedule next update event based on either the next execute 243 // tick or the next transition, which ever comes first 244 const Tick nextEventTick = std::min(nextPacketTick, nextTransitionTick); 245 246 DPRINTF(TrafficGen, "Next event scheduled at %lld\n", nextEventTick); 247 248 // The next transition tick may be in the past if there was a 249 // retry, so ensure that we don't schedule anything in the past. 250 schedule(updateEvent, std::max(curTick(), nextEventTick)); 251} 252 253void 254BaseTrafficGen::start() 255{ 256 transition(); 257 scheduleUpdate(); 258} 259 260void 261BaseTrafficGen::recvReqRetry() 262{ 263 assert(retryPkt != NULL); 264 265 DPRINTF(TrafficGen, "Received retry\n"); 266 numRetries++; 267 // attempt to send the packet, and if we are successful start up 268 // the machinery again 269 if (port.sendTimingReq(retryPkt)) { 270 retryPkt = NULL; 271 // remember how much delay was incurred due to back-pressure 272 // when sending the request, we also use this to derive 273 // the tick for the next packet 274 Tick delay = curTick() - retryPktTick; 275 retryPktTick = 0; 276 retryTicks += delay; 277 278 if (drainState() != DrainState::Draining) { 279 // packet is sent, so find out when the next one is due 280 nextPacketTick = activeGenerator->nextPacketTick(elasticReq, 281 delay); 282 scheduleUpdate(); 283 } else { 284 // shut things down 285 nextPacketTick = MaxTick; 286 nextTransitionTick = MaxTick; 287 signalDrainDone(); 288 } 289 } 290} 291 292void 293BaseTrafficGen::noProgress() 294{ 295 fatal("BaseTrafficGen %s spent %llu ticks without making progress", 296 name(), progressCheck); 297} 298 299void 300BaseTrafficGen::regStats() 301{ 302 ClockedObject::regStats(); 303 304 // Initialise all the stats 305 using namespace Stats; 306 307 numPackets 308 .name(name() + ".numPackets") 309 .desc("Number of packets generated"); 310 311 numRetries 312 .name(name() + ".numRetries") 313 .desc("Number of retries"); 314 315 retryTicks 316 .name(name() + ".retryTicks") 317 .desc("Time spent waiting due to back-pressure (ticks)"); 318} 319 320std::shared_ptr<BaseGen> 321BaseTrafficGen::createIdle(Tick duration) 322{ 323 return std::shared_ptr<BaseGen>(new IdleGen(*this, duration)); 324} 325 326std::shared_ptr<BaseGen> 327BaseTrafficGen::createExit(Tick duration) 328{ 329 return std::shared_ptr<BaseGen>(new ExitGen(*this, duration)); 330} 331 332std::shared_ptr<BaseGen> 333BaseTrafficGen::createLinear(Tick duration, 334 Addr start_addr, Addr end_addr, Addr blocksize, 335 Tick min_period, Tick max_period, 336 uint8_t read_percent, Addr data_limit) 337{ 338 return std::shared_ptr<BaseGen>(new LinearGen(*this, 339 duration, start_addr, 340 end_addr, blocksize, 341 min_period, max_period, 342 read_percent, data_limit)); 343} 344 345std::shared_ptr<BaseGen> 346BaseTrafficGen::createRandom(Tick duration, 347 Addr start_addr, Addr end_addr, Addr blocksize, 348 Tick min_period, Tick max_period, 349 uint8_t read_percent, Addr data_limit) 350{ 351 return std::shared_ptr<BaseGen>(new RandomGen(*this, 352 duration, start_addr, 353 end_addr, blocksize, 354 min_period, max_period, 355 read_percent, data_limit)); 356} 357 358std::shared_ptr<BaseGen> 359BaseTrafficGen::createDram(Tick duration, 360 Addr start_addr, Addr end_addr, Addr blocksize, 361 Tick min_period, Tick max_period, 362 uint8_t read_percent, Addr data_limit, 363 unsigned int num_seq_pkts, unsigned int page_size, 364 unsigned int nbr_of_banks_DRAM, 365 unsigned int nbr_of_banks_util, 366 unsigned int addr_mapping, 367 unsigned int nbr_of_ranks) 368{ 369 return std::shared_ptr<BaseGen>(new DramGen(*this, 370 duration, start_addr, 371 end_addr, blocksize, 372 min_period, max_period, 373 read_percent, data_limit, 374 num_seq_pkts, page_size, 375 nbr_of_banks_DRAM, 376 nbr_of_banks_util, 377 addr_mapping, 378 nbr_of_ranks)); 379} 380 381std::shared_ptr<BaseGen> 382BaseTrafficGen::createDramRot(Tick duration, 383 Addr start_addr, Addr end_addr, Addr blocksize, 384 Tick min_period, Tick max_period, 385 uint8_t read_percent, Addr data_limit, 386 unsigned int num_seq_pkts, 387 unsigned int page_size, 388 unsigned int nbr_of_banks_DRAM, 389 unsigned int nbr_of_banks_util, 390 unsigned int addr_mapping, 391 unsigned int nbr_of_ranks, 392 unsigned int max_seq_count_per_rank) 393{ 394 return std::shared_ptr<BaseGen>(new DramRotGen(*this, 395 duration, start_addr, 396 end_addr, blocksize, 397 min_period, max_period, 398 read_percent, data_limit, 399 num_seq_pkts, page_size, 400 nbr_of_banks_DRAM, 401 nbr_of_banks_util, 402 addr_mapping, 403 nbr_of_ranks, 404 max_seq_count_per_rank)); 405} 406 407std::shared_ptr<BaseGen> 408BaseTrafficGen::createTrace(Tick duration, 409 const std::string& trace_file, Addr addr_offset) 410{ 411#if HAVE_PROTOBUF 412 return std::shared_ptr<BaseGen>( 413 new TraceGen(*this, duration, trace_file, addr_offset)); 414#else 415 panic("Can't instantiate trace generation without Protobuf support!\n"); 416#endif 417} 418 419bool 420BaseTrafficGen::TrafficGenPort::recvTimingResp(PacketPtr pkt) 421{ 422 delete pkt; 423 424 return true; 425} 426