2 * Copyright (c) 2012 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Authors: Thomas Grass
41 #include "debug/CommMonitor.hh"
42 #include "mem/comm_monitor.hh"
43 #include "sim/stats.hh"
45 CommMonitor::CommMonitor(Params
* params
)
47 masterPort(name() + "-master", *this),
48 slavePort(name() + "-slave", *this),
49 samplePeriodicEvent(this),
50 samplePeriodTicks(params
->sample_period
),
51 readAddrMask(params
->read_addr_mask
),
52 writeAddrMask(params
->write_addr_mask
),
55 // keep track of the sample period both in ticks and absolute time
56 samplePeriod
.setTick(params
->sample_period
);
59 "Created monitor %s with sample period %d ticks (%f s)\n",
60 name(), samplePeriodTicks
, samplePeriod
);
64 CommMonitorParams::create()
66 return new CommMonitor(this);
72 // make sure both sides of the monitor are connected
73 if (!slavePort
.isConnected() || !masterPort
.isConnected())
74 fatal("Communication monitor is not connected on both sides.\n");
78 CommMonitor::getMasterPort(const std::string
& if_name
, int idx
)
80 if (if_name
== "master") {
83 return MemObject::getMasterPort(if_name
, idx
);
88 CommMonitor::getSlavePort(const std::string
& if_name
, int idx
)
90 if (if_name
== "slave") {
93 return MemObject::getSlavePort(if_name
, idx
);
98 CommMonitor::recvFunctional(PacketPtr pkt
)
100 masterPort
.sendFunctional(pkt
);
104 CommMonitor::recvFunctionalSnoop(PacketPtr pkt
)
106 slavePort
.sendFunctionalSnoop(pkt
);
110 CommMonitor::recvAtomic(PacketPtr pkt
)
112 return masterPort
.sendAtomic(pkt
);
116 CommMonitor::recvAtomicSnoop(PacketPtr pkt
)
118 return slavePort
.sendAtomicSnoop(pkt
);
122 CommMonitor::recvTimingReq(PacketPtr pkt
)
124 // should always see a request
125 assert(pkt
->isRequest());
127 // Store relevant fields of packet, because packet may be modified
128 // or even deleted when sendTiming() is called.
129 bool isRead
= pkt
->isRead();
130 bool isWrite
= pkt
->isWrite();
131 unsigned size
= pkt
->getSize();
132 Addr addr
= pkt
->getAddr();
133 bool needsResponse
= pkt
->needsResponse();
134 bool memInhibitAsserted
= pkt
->memInhibitAsserted();
135 Packet::SenderState
* senderState
= pkt
->senderState
;
137 // If a cache miss is served by a cache, a monitor near the memory
138 // would see a request which needs a response, but this response
139 // would be inhibited and not come back from the memory. Therefore
140 // we additionally have to check the inhibit flag.
141 if (needsResponse
&& !memInhibitAsserted
&& !stats
.disableLatencyHists
) {
142 pkt
->senderState
= new CommMonitorSenderState(senderState
,
146 // Attempt to send the packet (always succeeds for inhibited
148 bool successful
= masterPort
.sendTimingReq(pkt
);
150 // If not successful, restore the sender state
151 if (!successful
&& needsResponse
&& !stats
.disableLatencyHists
) {
152 delete pkt
->senderState
;
153 pkt
->senderState
= senderState
;
156 if (successful
&& isRead
) {
157 DPRINTF(CommMonitor
, "Forwarded read request\n");
159 // Increment number of observed read transactions
160 if (!stats
.disableTransactionHists
) {
164 // Get sample of burst length
165 if (!stats
.disableBurstLengthHists
) {
166 stats
.readBurstLengthHist
.sample(size
);
169 // Sample the masked address
170 if (!stats
.disableAddrDists
) {
171 stats
.readAddrDist
.sample(addr
& readAddrMask
);
174 // If it needs a response increment number of outstanding read
176 if (!stats
.disableOutstandingHists
&& needsResponse
) {
177 ++stats
.outstandingReadReqs
;
180 if (!stats
.disableITTDists
) {
181 // Sample value of read-read inter transaction time
182 if (stats
.timeOfLastRead
!= 0) {
183 stats
.ittReadRead
.sample(curTick() - stats
.timeOfLastRead
);
185 stats
.timeOfLastRead
= curTick();
187 // Sample value of req-req inter transaction time
188 if (stats
.timeOfLastReq
!= 0) {
189 stats
.ittReqReq
.sample(curTick() - stats
.timeOfLastReq
);
191 stats
.timeOfLastReq
= curTick();
193 } else if (successful
&& isWrite
) {
194 DPRINTF(CommMonitor
, "Forwarded write request\n");
197 if (!stats
.disableTransactionHists
) {
201 if (!stats
.disableBurstLengthHists
) {
202 stats
.writeBurstLengthHist
.sample(size
);
205 // Update the bandwidth stats on the request
206 if (!stats
.disableBandwidthHists
) {
207 stats
.writtenBytes
+= size
;
208 stats
.totalWrittenBytes
+= size
;
211 // Sample the masked write address
212 if (!stats
.disableAddrDists
) {
213 stats
.writeAddrDist
.sample(addr
& writeAddrMask
);
216 if (!stats
.disableOutstandingHists
&& needsResponse
) {
217 ++stats
.outstandingWriteReqs
;
220 if (!stats
.disableITTDists
) {
221 // Sample value of write-to-write inter transaction time
222 if (stats
.timeOfLastWrite
!= 0) {
223 stats
.ittWriteWrite
.sample(curTick() - stats
.timeOfLastWrite
);
225 stats
.timeOfLastWrite
= curTick();
227 // Sample value of req-to-req inter transaction time
228 if (stats
.timeOfLastReq
!= 0) {
229 stats
.ittReqReq
.sample(curTick() - stats
.timeOfLastReq
);
231 stats
.timeOfLastReq
= curTick();
233 } else if (successful
) {
234 DPRINTF(CommMonitor
, "Forwarded non read/write request\n");
241 CommMonitor::recvTimingResp(PacketPtr pkt
)
243 // should always see responses
244 assert(pkt
->isResponse());
246 // Store relevant fields of packet, because packet may be modified
247 // or even deleted when sendTiming() is called.
248 bool isRead
= pkt
->isRead();
249 bool isWrite
= pkt
->isWrite();
250 unsigned size
= pkt
->getSize();
252 CommMonitorSenderState
* commReceivedState
=
253 dynamic_cast<CommMonitorSenderState
*>(pkt
->senderState
);
255 if (!stats
.disableLatencyHists
) {
256 // Restore initial sender state
257 if (commReceivedState
== NULL
)
258 panic("Monitor got a response without monitor sender state\n");
261 pkt
->senderState
= commReceivedState
->origSenderState
;
264 // Attempt to send the packet
265 bool successful
= slavePort
.sendTimingResp(pkt
);
267 if (!stats
.disableLatencyHists
) {
268 // If packet successfully send, sample value of latency,
269 // afterwards delete sender state, otherwise restore state
271 latency
= curTick() - commReceivedState
->transmitTime
;
272 DPRINTF(CommMonitor
, "Latency: %d\n", latency
);
273 delete commReceivedState
;
275 // Don't delete anything and let the packet look like we
277 pkt
->senderState
= commReceivedState
;
281 if (successful
&& isRead
) {
282 // Decrement number of outstanding read requests
283 DPRINTF(CommMonitor
, "Received read response\n");
284 if (!stats
.disableOutstandingHists
) {
285 assert(stats
.outstandingReadReqs
!= 0);
286 --stats
.outstandingReadReqs
;
289 if (!stats
.disableLatencyHists
) {
290 stats
.readLatencyHist
.sample(latency
);
293 // Update the bandwidth stats based on responses for reads
294 if (!stats
.disableBandwidthHists
) {
295 stats
.readBytes
+= size
;
296 stats
.totalReadBytes
+= size
;
299 } else if (successful
&& isWrite
) {
300 // Decrement number of outstanding write requests
301 DPRINTF(CommMonitor
, "Received write response\n");
302 if (!stats
.disableOutstandingHists
) {
303 assert(stats
.outstandingWriteReqs
!= 0);
304 --stats
.outstandingWriteReqs
;
307 if (!stats
.disableLatencyHists
) {
308 stats
.writeLatencyHist
.sample(latency
);
310 } else if (successful
) {
311 DPRINTF(CommMonitor
, "Received non read/write response\n");
317 CommMonitor::recvTimingSnoopReq(PacketPtr pkt
)
319 slavePort
.sendTimingSnoopReq(pkt
);
323 CommMonitor::recvTimingSnoopResp(PacketPtr pkt
)
325 return masterPort
.sendTimingSnoopResp(pkt
);
329 CommMonitor::isSnooping() const
331 // check if the connected master port is snooping
332 return slavePort
.isSnooping();
336 CommMonitor::deviceBlockSizeMaster()
338 return slavePort
.peerBlockSize();
342 CommMonitor::deviceBlockSizeSlave()
344 return masterPort
.peerBlockSize();
348 CommMonitor::getAddrRanges()
350 return masterPort
.getSlavePort().getAddrRanges();
354 CommMonitor::recvRetryMaster()
356 slavePort
.sendRetry();
360 CommMonitor::recvRetrySlave()
362 masterPort
.sendRetry();
366 CommMonitor::recvRangeChange()
368 slavePort
.sendRangeChange();
372 CommMonitor::regStats()
374 // Initialise all the monitor stats
375 using namespace Stats
;
377 stats
.readBurstLengthHist
378 .init(params()->burst_length_bins
)
379 .name(name() + ".readBurstLengthHist")
380 .desc("Histogram of burst lengths of transmitted packets")
381 .flags(stats
.disableBurstLengthHists
? nozero
: pdf
);
383 stats
.writeBurstLengthHist
384 .init(params()->burst_length_bins
)
385 .name(name() + ".writeBurstLengthHist")
386 .desc("Histogram of burst lengths of transmitted packets")
387 .flags(stats
.disableBurstLengthHists
? nozero
: pdf
);
389 // Stats based on received responses
390 stats
.readBandwidthHist
391 .init(params()->bandwidth_bins
)
392 .name(name() + ".readBandwidthHist")
393 .desc("Histogram of read bandwidth per sample period (bytes/s)")
394 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
397 .name(name() + ".averageReadBandwidth")
398 .desc("Average read bandwidth (bytes/s)")
399 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
402 .name(name() + ".totalReadBytes")
403 .desc("Number of bytes read")
404 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
406 stats
.averageReadBW
= stats
.totalReadBytes
/ simSeconds
;
408 // Stats based on successfully sent requests
409 stats
.writeBandwidthHist
410 .init(params()->bandwidth_bins
)
411 .name(name() + ".writeBandwidthHist")
412 .desc("Histogram of write bandwidth (bytes/s)")
413 .flags(stats
.disableBandwidthHists
? (pdf
| nozero
) : pdf
);
416 .name(name() + ".averageWriteBandwidth")
417 .desc("Average write bandwidth (bytes/s)")
418 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
420 stats
.totalWrittenBytes
421 .name(name() + ".totalWrittenBytes")
422 .desc("Number of bytes written")
423 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
425 stats
.averageWriteBW
= stats
.totalWrittenBytes
/ simSeconds
;
427 stats
.readLatencyHist
428 .init(params()->latency_bins
)
429 .name(name() + ".readLatencyHist")
430 .desc("Read request-response latency")
431 .flags(stats
.disableLatencyHists
? nozero
: pdf
);
433 stats
.writeLatencyHist
434 .init(params()->latency_bins
)
435 .name(name() + ".writeLatencyHist")
436 .desc("Write request-response latency")
437 .flags(stats
.disableLatencyHists
? nozero
: pdf
);
440 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
442 .name(name() + ".ittReadRead")
443 .desc("Read-to-read inter transaction time")
444 .flags(stats
.disableITTDists
? nozero
: pdf
);
447 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
449 .name(name() + ".ittWriteWrite")
450 .desc("Write-to-write inter transaction time")
451 .flags(stats
.disableITTDists
? nozero
: pdf
);
454 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
456 .name(name() + ".ittReqReq")
457 .desc("Request-to-request inter transaction time")
458 .flags(stats
.disableITTDists
? nozero
: pdf
);
460 stats
.outstandingReadsHist
461 .init(params()->outstanding_bins
)
462 .name(name() + ".outstandingReadsHist")
463 .desc("Outstanding read transactions")
464 .flags(stats
.disableOutstandingHists
? nozero
: pdf
);
466 stats
.outstandingWritesHist
467 .init(params()->outstanding_bins
)
468 .name(name() + ".outstandingWritesHist")
469 .desc("Outstanding write transactions")
470 .flags(stats
.disableOutstandingHists
? nozero
: pdf
);
473 .init(params()->transaction_bins
)
474 .name(name() + ".readTransHist")
475 .desc("Histogram of read transactions per sample period")
476 .flags(stats
.disableTransactionHists
? nozero
: pdf
);
479 .init(params()->transaction_bins
)
480 .name(name() + ".writeTransHist")
481 .desc("Histogram of read transactions per sample period")
482 .flags(stats
.disableTransactionHists
? nozero
: pdf
);
486 .name(name() + ".readAddrDist")
487 .desc("Read address distribution")
488 .flags(stats
.disableAddrDists
? nozero
: pdf
);
492 .name(name() + ".writeAddrDist")
493 .desc("Write address distribution")
494 .flags(stats
.disableAddrDists
? nozero
: pdf
);
498 CommMonitor::samplePeriodic()
500 // the periodic stats update runs on the granularity of sample
501 // periods, but in combination with this there may also be a
502 // external resets and dumps of the stats (through schedStatEvent)
503 // causing the stats themselves to capture less than a sample
506 // only capture if we have not reset the stats during the last
508 if (simTicks
.value() >= samplePeriodTicks
) {
509 if (!stats
.disableTransactionHists
) {
510 stats
.readTransHist
.sample(stats
.readTrans
);
511 stats
.writeTransHist
.sample(stats
.writeTrans
);
514 if (!stats
.disableBandwidthHists
) {
515 stats
.readBandwidthHist
.sample(stats
.readBytes
/ samplePeriod
);
516 stats
.writeBandwidthHist
.sample(stats
.writtenBytes
/ samplePeriod
);
519 if (!stats
.disableOutstandingHists
) {
520 stats
.outstandingReadsHist
.sample(stats
.outstandingReadReqs
);
521 stats
.outstandingWritesHist
.sample(stats
.outstandingWriteReqs
);
525 // reset the sampled values
527 stats
.writeTrans
= 0;
530 stats
.writtenBytes
= 0;
532 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);
536 CommMonitor::startup()
538 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);