comm_monitor.cc revision 12084
1/* 2 * Copyright (c) 2012-2013, 2015 ARM Limited 3 * Copyright (c) 2016 Google Inc. 4 * Copyright (c) 2017, Centre National de la Recherche Scientifique 5 * All rights reserved. 6 * 7 * The license below extends only to copyright in the software and shall 8 * not be construed as granting a license to any other intellectual 9 * property including but not limited to intellectual property relating 10 * to a hardware implementation of the functionality of the software 11 * licensed hereunder. You may use the software subject to the license 12 * terms below provided that you ensure that this notice is replicated 13 * unmodified and in its entirety in all distributions of the software, 14 * modified or unmodified, in source code or in binary form. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions are 18 * met: redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer; 20 * redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution; 23 * neither the name of the copyright holders nor the names of its 24 * contributors may be used to endorse or promote products derived from 25 * this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 28 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 29 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 30 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 31 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 32 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 33 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 34 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 35 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 36 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 37 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 38 * 39 * Authors: Thomas Grass 40 * Andreas Hansson 41 * Rahul Thakur 42 * Pierre-Yves Peneau 43 */ 44 45#include "mem/comm_monitor.hh" 46 47#include "base/trace.hh" 48#include "debug/CommMonitor.hh" 49#include "sim/stats.hh" 50 51CommMonitor::CommMonitor(Params* params) 52 : MemObject(params), 53 masterPort(name() + "-master", *this), 54 slavePort(name() + "-slave", *this), 55 samplePeriodicEvent([this]{ samplePeriodic(); }, name()), 56 samplePeriodTicks(params->sample_period), 57 samplePeriod(params->sample_period / SimClock::Float::s), 58 stats(params) 59{ 60 DPRINTF(CommMonitor, 61 "Created monitor %s with sample period %d ticks (%f ms)\n", 62 name(), samplePeriodTicks, samplePeriod * 1E3); 63} 64 65CommMonitor* 66CommMonitorParams::create() 67{ 68 return new CommMonitor(this); 69} 70 71void 72CommMonitor::init() 73{ 74 // make sure both sides of the monitor are connected 75 if (!slavePort.isConnected() || !masterPort.isConnected()) 76 fatal("Communication monitor is not connected on both sides.\n"); 77} 78 79void 80CommMonitor::regProbePoints() 81{ 82 ppPktReq.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest")); 83 ppPktResp.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse")); 84} 85 86BaseMasterPort& 87CommMonitor::getMasterPort(const std::string& if_name, PortID idx) 88{ 89 if (if_name == "master") { 90 return masterPort; 91 } else { 92 return MemObject::getMasterPort(if_name, idx); 93 } 94} 95 96BaseSlavePort& 97CommMonitor::getSlavePort(const std::string& if_name, PortID idx) 98{ 99 if (if_name == "slave") { 100 return slavePort; 101 } else { 102 return MemObject::getSlavePort(if_name, idx); 103 } 104} 105 106void 107CommMonitor::recvFunctional(PacketPtr pkt) 108{ 109 masterPort.sendFunctional(pkt); 110} 111 112void 113CommMonitor::recvFunctionalSnoop(PacketPtr pkt) 114{ 115 slavePort.sendFunctionalSnoop(pkt); 116} 117 118void 119CommMonitor::MonitorStats::updateReqStats( 120 const ProbePoints::PacketInfo& pkt_info, bool is_atomic, 121 bool expects_response) 122{ 123 if (pkt_info.cmd.isRead()) { 124 // Increment number of observed read transactions 125 if (!disableTransactionHists) 126 ++readTrans; 127 128 // Get sample of burst length 129 if (!disableBurstLengthHists) 130 readBurstLengthHist.sample(pkt_info.size); 131 132 // Sample the masked address 133 if (!disableAddrDists) 134 readAddrDist.sample(pkt_info.addr & readAddrMask); 135 136 if (!disableITTDists) { 137 // Sample value of read-read inter transaction time 138 if (timeOfLastRead != 0) 139 ittReadRead.sample(curTick() - timeOfLastRead); 140 timeOfLastRead = curTick(); 141 142 // Sample value of req-req inter transaction time 143 if (timeOfLastReq != 0) 144 ittReqReq.sample(curTick() - timeOfLastReq); 145 timeOfLastReq = curTick(); 146 } 147 if (!is_atomic && !disableOutstandingHists && expects_response) 148 ++outstandingReadReqs; 149 150 } else if (pkt_info.cmd.isWrite()) { 151 // Same as for reads 152 if (!disableTransactionHists) 153 ++writeTrans; 154 155 if (!disableBurstLengthHists) 156 writeBurstLengthHist.sample(pkt_info.size); 157 158 // Update the bandwidth stats on the request 159 if (!disableBandwidthHists) { 160 writtenBytes += pkt_info.size; 161 totalWrittenBytes += pkt_info.size; 162 } 163 164 // Sample the masked write address 165 if (!disableAddrDists) 166 writeAddrDist.sample(pkt_info.addr & writeAddrMask); 167 168 if (!disableITTDists) { 169 // Sample value of write-to-write inter transaction time 170 if (timeOfLastWrite != 0) 171 ittWriteWrite.sample(curTick() - timeOfLastWrite); 172 timeOfLastWrite = curTick(); 173 174 // Sample value of req-to-req inter transaction time 175 if (timeOfLastReq != 0) 176 ittReqReq.sample(curTick() - timeOfLastReq); 177 timeOfLastReq = curTick(); 178 } 179 180 if (!is_atomic && !disableOutstandingHists && expects_response) 181 ++outstandingWriteReqs; 182 } 183} 184 185void 186CommMonitor::MonitorStats::updateRespStats( 187 const ProbePoints::PacketInfo& pkt_info, Tick latency, bool is_atomic) 188{ 189 if (pkt_info.cmd.isRead()) { 190 // Decrement number of outstanding read requests 191 if (!is_atomic && !disableOutstandingHists) { 192 assert(outstandingReadReqs != 0); 193 --outstandingReadReqs; 194 } 195 196 if (!disableLatencyHists) 197 readLatencyHist.sample(latency); 198 199 // Update the bandwidth stats based on responses for reads 200 if (!disableBandwidthHists) { 201 readBytes += pkt_info.size; 202 totalReadBytes += pkt_info.size; 203 } 204 205 } else if (pkt_info.cmd.isWrite()) { 206 // Decrement number of outstanding write requests 207 if (!is_atomic && !disableOutstandingHists) { 208 assert(outstandingWriteReqs != 0); 209 --outstandingWriteReqs; 210 } 211 212 if (!disableLatencyHists) 213 writeLatencyHist.sample(latency); 214 } 215} 216 217Tick 218CommMonitor::recvAtomic(PacketPtr pkt) 219{ 220 const bool expects_response(pkt->needsResponse() && 221 !pkt->cacheResponding()); 222 ProbePoints::PacketInfo req_pkt_info(pkt); 223 ppPktReq->notify(req_pkt_info); 224 225 const Tick delay(masterPort.sendAtomic(pkt)); 226 227 stats.updateReqStats(req_pkt_info, true, expects_response); 228 if (expects_response) 229 stats.updateRespStats(req_pkt_info, delay, true); 230 231 assert(pkt->isResponse()); 232 ProbePoints::PacketInfo resp_pkt_info(pkt); 233 ppPktResp->notify(resp_pkt_info); 234 return delay; 235} 236 237Tick 238CommMonitor::recvAtomicSnoop(PacketPtr pkt) 239{ 240 return slavePort.sendAtomicSnoop(pkt); 241} 242 243bool 244CommMonitor::recvTimingReq(PacketPtr pkt) 245{ 246 // should always see a request 247 assert(pkt->isRequest()); 248 249 // Store relevant fields of packet, because packet may be modified 250 // or even deleted when sendTiming() is called. 251 const ProbePoints::PacketInfo pkt_info(pkt); 252 253 const bool expects_response(pkt->needsResponse() && 254 !pkt->cacheResponding()); 255 256 // If a cache miss is served by a cache, a monitor near the memory 257 // would see a request which needs a response, but this response 258 // would not come back from the memory. Therefore we additionally 259 // have to check the cacheResponding flag 260 if (expects_response && !stats.disableLatencyHists) { 261 pkt->pushSenderState(new CommMonitorSenderState(curTick())); 262 } 263 264 // Attempt to send the packet 265 bool successful = masterPort.sendTimingReq(pkt); 266 267 // If not successful, restore the sender state 268 if (!successful && expects_response && !stats.disableLatencyHists) { 269 delete pkt->popSenderState(); 270 } 271 272 if (successful) { 273 ppPktReq->notify(pkt_info); 274 } 275 276 if (successful) { 277 DPRINTF(CommMonitor, "Forwarded %s request\n", pkt->isRead() ? "read" : 278 pkt->isWrite() ? "write" : "non read/write"); 279 stats.updateReqStats(pkt_info, false, expects_response); 280 } 281 return successful; 282} 283 284bool 285CommMonitor::recvTimingResp(PacketPtr pkt) 286{ 287 // should always see responses 288 assert(pkt->isResponse()); 289 290 // Store relevant fields of packet, because packet may be modified 291 // or even deleted when sendTiming() is called. 292 const ProbePoints::PacketInfo pkt_info(pkt); 293 294 Tick latency = 0; 295 CommMonitorSenderState* received_state = 296 dynamic_cast<CommMonitorSenderState*>(pkt->senderState); 297 298 if (!stats.disableLatencyHists) { 299 // Restore initial sender state 300 if (received_state == NULL) 301 panic("Monitor got a response without monitor sender state\n"); 302 303 // Restore the sate 304 pkt->senderState = received_state->predecessor; 305 } 306 307 // Attempt to send the packet 308 bool successful = slavePort.sendTimingResp(pkt); 309 310 if (!stats.disableLatencyHists) { 311 // If packet successfully send, sample value of latency, 312 // afterwards delete sender state, otherwise restore state 313 if (successful) { 314 latency = curTick() - received_state->transmitTime; 315 DPRINTF(CommMonitor, "Latency: %d\n", latency); 316 delete received_state; 317 } else { 318 // Don't delete anything and let the packet look like we 319 // did not touch it 320 pkt->senderState = received_state; 321 } 322 } 323 324 if (successful) { 325 ppPktResp->notify(pkt_info); 326 DPRINTF(CommMonitor, "Received %s response\n", pkt->isRead() ? "read" : 327 pkt->isWrite() ? "write" : "non read/write"); 328 stats.updateRespStats(pkt_info, latency, false); 329 } 330 return successful; 331} 332 333void 334CommMonitor::recvTimingSnoopReq(PacketPtr pkt) 335{ 336 slavePort.sendTimingSnoopReq(pkt); 337} 338 339bool 340CommMonitor::recvTimingSnoopResp(PacketPtr pkt) 341{ 342 return masterPort.sendTimingSnoopResp(pkt); 343} 344 345void 346CommMonitor::recvRetrySnoopResp() 347{ 348 slavePort.sendRetrySnoopResp(); 349} 350 351bool 352CommMonitor::isSnooping() const 353{ 354 // check if the connected master port is snooping 355 return slavePort.isSnooping(); 356} 357 358AddrRangeList 359CommMonitor::getAddrRanges() const 360{ 361 // get the address ranges of the connected slave port 362 return masterPort.getAddrRanges(); 363} 364 365void 366CommMonitor::recvReqRetry() 367{ 368 slavePort.sendRetryReq(); 369} 370 371void 372CommMonitor::recvRespRetry() 373{ 374 masterPort.sendRetryResp(); 375} 376 377void 378CommMonitor::recvRangeChange() 379{ 380 slavePort.sendRangeChange(); 381} 382 383void 384CommMonitor::regStats() 385{ 386 MemObject::regStats(); 387 388 // Initialise all the monitor stats 389 using namespace Stats; 390 391 stats.readBurstLengthHist 392 .init(params()->burst_length_bins) 393 .name(name() + ".readBurstLengthHist") 394 .desc("Histogram of burst lengths of transmitted packets") 395 .flags(stats.disableBurstLengthHists ? nozero : pdf); 396 397 stats.writeBurstLengthHist 398 .init(params()->burst_length_bins) 399 .name(name() + ".writeBurstLengthHist") 400 .desc("Histogram of burst lengths of transmitted packets") 401 .flags(stats.disableBurstLengthHists ? nozero : pdf); 402 403 // Stats based on received responses 404 stats.readBandwidthHist 405 .init(params()->bandwidth_bins) 406 .name(name() + ".readBandwidthHist") 407 .desc("Histogram of read bandwidth per sample period (bytes/s)") 408 .flags(stats.disableBandwidthHists ? nozero : pdf); 409 410 stats.averageReadBW 411 .name(name() + ".averageReadBandwidth") 412 .desc("Average read bandwidth (bytes/s)") 413 .flags(stats.disableBandwidthHists ? nozero : pdf); 414 415 stats.totalReadBytes 416 .name(name() + ".totalReadBytes") 417 .desc("Number of bytes read") 418 .flags(stats.disableBandwidthHists ? nozero : pdf); 419 420 stats.averageReadBW = stats.totalReadBytes / simSeconds; 421 422 // Stats based on successfully sent requests 423 stats.writeBandwidthHist 424 .init(params()->bandwidth_bins) 425 .name(name() + ".writeBandwidthHist") 426 .desc("Histogram of write bandwidth (bytes/s)") 427 .flags(stats.disableBandwidthHists ? (pdf | nozero) : pdf); 428 429 stats.averageWriteBW 430 .name(name() + ".averageWriteBandwidth") 431 .desc("Average write bandwidth (bytes/s)") 432 .flags(stats.disableBandwidthHists ? nozero : pdf); 433 434 stats.totalWrittenBytes 435 .name(name() + ".totalWrittenBytes") 436 .desc("Number of bytes written") 437 .flags(stats.disableBandwidthHists ? nozero : pdf); 438 439 stats.averageWriteBW = stats.totalWrittenBytes / simSeconds; 440 441 stats.readLatencyHist 442 .init(params()->latency_bins) 443 .name(name() + ".readLatencyHist") 444 .desc("Read request-response latency") 445 .flags(stats.disableLatencyHists ? nozero : pdf); 446 447 stats.writeLatencyHist 448 .init(params()->latency_bins) 449 .name(name() + ".writeLatencyHist") 450 .desc("Write request-response latency") 451 .flags(stats.disableLatencyHists ? nozero : pdf); 452 453 stats.ittReadRead 454 .init(1, params()->itt_max_bin, params()->itt_max_bin / 455 params()->itt_bins) 456 .name(name() + ".ittReadRead") 457 .desc("Read-to-read inter transaction time") 458 .flags(stats.disableITTDists ? nozero : pdf); 459 460 stats.ittWriteWrite 461 .init(1, params()->itt_max_bin, params()->itt_max_bin / 462 params()->itt_bins) 463 .name(name() + ".ittWriteWrite") 464 .desc("Write-to-write inter transaction time") 465 .flags(stats.disableITTDists ? nozero : pdf); 466 467 stats.ittReqReq 468 .init(1, params()->itt_max_bin, params()->itt_max_bin / 469 params()->itt_bins) 470 .name(name() + ".ittReqReq") 471 .desc("Request-to-request inter transaction time") 472 .flags(stats.disableITTDists ? nozero : pdf); 473 474 stats.outstandingReadsHist 475 .init(params()->outstanding_bins) 476 .name(name() + ".outstandingReadsHist") 477 .desc("Outstanding read transactions") 478 .flags(stats.disableOutstandingHists ? nozero : pdf); 479 480 stats.outstandingWritesHist 481 .init(params()->outstanding_bins) 482 .name(name() + ".outstandingWritesHist") 483 .desc("Outstanding write transactions") 484 .flags(stats.disableOutstandingHists ? nozero : pdf); 485 486 stats.readTransHist 487 .init(params()->transaction_bins) 488 .name(name() + ".readTransHist") 489 .desc("Histogram of read transactions per sample period") 490 .flags(stats.disableTransactionHists ? nozero : pdf); 491 492 stats.writeTransHist 493 .init(params()->transaction_bins) 494 .name(name() + ".writeTransHist") 495 .desc("Histogram of write transactions per sample period") 496 .flags(stats.disableTransactionHists ? nozero : pdf); 497 498 stats.readAddrDist 499 .init(0) 500 .name(name() + ".readAddrDist") 501 .desc("Read address distribution") 502 .flags(stats.disableAddrDists ? nozero : pdf); 503 504 stats.writeAddrDist 505 .init(0) 506 .name(name() + ".writeAddrDist") 507 .desc("Write address distribution") 508 .flags(stats.disableAddrDists ? nozero : pdf); 509} 510 511void 512CommMonitor::samplePeriodic() 513{ 514 // the periodic stats update runs on the granularity of sample 515 // periods, but in combination with this there may also be a 516 // external resets and dumps of the stats (through schedStatEvent) 517 // causing the stats themselves to capture less than a sample 518 // period 519 520 // only capture if we have not reset the stats during the last 521 // sample period 522 if (simTicks.value() >= samplePeriodTicks) { 523 if (!stats.disableTransactionHists) { 524 stats.readTransHist.sample(stats.readTrans); 525 stats.writeTransHist.sample(stats.writeTrans); 526 } 527 528 if (!stats.disableBandwidthHists) { 529 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod); 530 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod); 531 } 532 533 if (!stats.disableOutstandingHists) { 534 stats.outstandingReadsHist.sample(stats.outstandingReadReqs); 535 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs); 536 } 537 } 538 539 // reset the sampled values 540 stats.readTrans = 0; 541 stats.writeTrans = 0; 542 543 stats.readBytes = 0; 544 stats.writtenBytes = 0; 545 546 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks); 547} 548 549void 550CommMonitor::startup() 551{ 552 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks); 553} 554