aea0286928f0841aafd81fb726952ac92420fd62
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
, PortID idx
)
80 if (if_name
== "master") {
83 return MemObject::getMasterPort(if_name
, idx
);
88 CommMonitor::getSlavePort(const std::string
& if_name
, PortID 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() const
350 // get the address ranges of the connected slave port
351 return masterPort
.getAddrRanges();
355 CommMonitor::recvRetryMaster()
357 slavePort
.sendRetry();
361 CommMonitor::recvRetrySlave()
363 masterPort
.sendRetry();
367 CommMonitor::recvRangeChange()
369 slavePort
.sendRangeChange();
373 CommMonitor::regStats()
375 // Initialise all the monitor stats
376 using namespace Stats
;
378 stats
.readBurstLengthHist
379 .init(params()->burst_length_bins
)
380 .name(name() + ".readBurstLengthHist")
381 .desc("Histogram of burst lengths of transmitted packets")
382 .flags(stats
.disableBurstLengthHists
? nozero
: pdf
);
384 stats
.writeBurstLengthHist
385 .init(params()->burst_length_bins
)
386 .name(name() + ".writeBurstLengthHist")
387 .desc("Histogram of burst lengths of transmitted packets")
388 .flags(stats
.disableBurstLengthHists
? nozero
: pdf
);
390 // Stats based on received responses
391 stats
.readBandwidthHist
392 .init(params()->bandwidth_bins
)
393 .name(name() + ".readBandwidthHist")
394 .desc("Histogram of read bandwidth per sample period (bytes/s)")
395 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
398 .name(name() + ".averageReadBandwidth")
399 .desc("Average read bandwidth (bytes/s)")
400 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
403 .name(name() + ".totalReadBytes")
404 .desc("Number of bytes read")
405 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
407 stats
.averageReadBW
= stats
.totalReadBytes
/ simSeconds
;
409 // Stats based on successfully sent requests
410 stats
.writeBandwidthHist
411 .init(params()->bandwidth_bins
)
412 .name(name() + ".writeBandwidthHist")
413 .desc("Histogram of write bandwidth (bytes/s)")
414 .flags(stats
.disableBandwidthHists
? (pdf
| nozero
) : pdf
);
417 .name(name() + ".averageWriteBandwidth")
418 .desc("Average write bandwidth (bytes/s)")
419 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
421 stats
.totalWrittenBytes
422 .name(name() + ".totalWrittenBytes")
423 .desc("Number of bytes written")
424 .flags(stats
.disableBandwidthHists
? nozero
: pdf
);
426 stats
.averageWriteBW
= stats
.totalWrittenBytes
/ simSeconds
;
428 stats
.readLatencyHist
429 .init(params()->latency_bins
)
430 .name(name() + ".readLatencyHist")
431 .desc("Read request-response latency")
432 .flags(stats
.disableLatencyHists
? nozero
: pdf
);
434 stats
.writeLatencyHist
435 .init(params()->latency_bins
)
436 .name(name() + ".writeLatencyHist")
437 .desc("Write request-response latency")
438 .flags(stats
.disableLatencyHists
? nozero
: pdf
);
441 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
443 .name(name() + ".ittReadRead")
444 .desc("Read-to-read inter transaction time")
445 .flags(stats
.disableITTDists
? nozero
: pdf
);
448 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
450 .name(name() + ".ittWriteWrite")
451 .desc("Write-to-write inter transaction time")
452 .flags(stats
.disableITTDists
? nozero
: pdf
);
455 .init(1, params()->itt_max_bin
, params()->itt_max_bin
/
457 .name(name() + ".ittReqReq")
458 .desc("Request-to-request inter transaction time")
459 .flags(stats
.disableITTDists
? nozero
: pdf
);
461 stats
.outstandingReadsHist
462 .init(params()->outstanding_bins
)
463 .name(name() + ".outstandingReadsHist")
464 .desc("Outstanding read transactions")
465 .flags(stats
.disableOutstandingHists
? nozero
: pdf
);
467 stats
.outstandingWritesHist
468 .init(params()->outstanding_bins
)
469 .name(name() + ".outstandingWritesHist")
470 .desc("Outstanding write transactions")
471 .flags(stats
.disableOutstandingHists
? nozero
: pdf
);
474 .init(params()->transaction_bins
)
475 .name(name() + ".readTransHist")
476 .desc("Histogram of read transactions per sample period")
477 .flags(stats
.disableTransactionHists
? nozero
: pdf
);
480 .init(params()->transaction_bins
)
481 .name(name() + ".writeTransHist")
482 .desc("Histogram of read transactions per sample period")
483 .flags(stats
.disableTransactionHists
? nozero
: pdf
);
487 .name(name() + ".readAddrDist")
488 .desc("Read address distribution")
489 .flags(stats
.disableAddrDists
? nozero
: pdf
);
493 .name(name() + ".writeAddrDist")
494 .desc("Write address distribution")
495 .flags(stats
.disableAddrDists
? nozero
: pdf
);
499 CommMonitor::samplePeriodic()
501 // the periodic stats update runs on the granularity of sample
502 // periods, but in combination with this there may also be a
503 // external resets and dumps of the stats (through schedStatEvent)
504 // causing the stats themselves to capture less than a sample
507 // only capture if we have not reset the stats during the last
509 if (simTicks
.value() >= samplePeriodTicks
) {
510 if (!stats
.disableTransactionHists
) {
511 stats
.readTransHist
.sample(stats
.readTrans
);
512 stats
.writeTransHist
.sample(stats
.writeTrans
);
515 if (!stats
.disableBandwidthHists
) {
516 stats
.readBandwidthHist
.sample(stats
.readBytes
/ samplePeriod
);
517 stats
.writeBandwidthHist
.sample(stats
.writtenBytes
/ samplePeriod
);
520 if (!stats
.disableOutstandingHists
) {
521 stats
.outstandingReadsHist
.sample(stats
.outstandingReadReqs
);
522 stats
.outstandingWritesHist
.sample(stats
.outstandingWriteReqs
);
526 // reset the sampled values
528 stats
.writeTrans
= 0;
531 stats
.writtenBytes
= 0;
533 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);
537 CommMonitor::startup()
539 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);