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
|