2 * Copyright (c) 2012-2013, 2015, 2018-2019 ARM Limited
3 * Copyright (c) 2016 Google Inc.
4 * Copyright (c) 2017, Centre National de la Recherche Scientifique
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.
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.
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.
40 #include "mem/comm_monitor.hh"
42 #include "base/trace.hh"
43 #include "debug/CommMonitor.hh"
44 #include "sim/stats.hh"
46 CommMonitor::CommMonitor(const Params
¶ms
)
48 memSidePort(name() + "-mem_side_port", *this),
49 cpuSidePort(name() + "-cpu_side_port", *this),
50 samplePeriodicEvent([this]{ samplePeriodic(); }, name()),
51 samplePeriodTicks(params
.sample_period
),
52 samplePeriod(params
.sample_period
/ SimClock::Float::s
),
56 "Created monitor %s with sample period %d ticks (%f ms)\n",
57 name(), samplePeriodTicks
, samplePeriod
* 1E3
);
63 // make sure both sides of the monitor are connected
64 if (!cpuSidePort
.isConnected() || !memSidePort
.isConnected())
65 fatal("Communication monitor is not connected on both sides.\n");
69 CommMonitor::regProbePoints()
71 ppPktReq
.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
72 ppPktResp
.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
76 CommMonitor::getPort(const std::string
&if_name
, PortID idx
)
78 if (if_name
== "mem_side_port") {
80 } else if (if_name
== "cpu_side_port") {
83 return SimObject::getPort(if_name
, idx
);
88 CommMonitor::recvFunctional(PacketPtr pkt
)
90 memSidePort
.sendFunctional(pkt
);
94 CommMonitor::recvFunctionalSnoop(PacketPtr pkt
)
96 cpuSidePort
.sendFunctionalSnoop(pkt
);
99 CommMonitor::MonitorStats::MonitorStats(Stats::Group
*parent
,
100 const CommMonitorParams
¶ms
)
101 : Stats::Group(parent
),
103 disableBurstLengthHists(params
.disable_burst_length_hists
),
104 ADD_STAT(readBurstLengthHist
,
105 "Histogram of burst lengths of transmitted packets"),
106 ADD_STAT(writeBurstLengthHist
,
107 "Histogram of burst lengths of transmitted packets"),
109 disableBandwidthHists(params
.disable_bandwidth_hists
),
111 ADD_STAT(readBandwidthHist
,
112 "Histogram of read bandwidth per sample period (bytes/s)"),
113 ADD_STAT(totalReadBytes
, "Number of bytes read"),
114 ADD_STAT(averageReadBandwidth
, "Average read bandwidth (bytes/s)",
115 totalReadBytes
/ simSeconds
),
118 ADD_STAT(writeBandwidthHist
, "Histogram of write bandwidth (bytes/s)"),
119 ADD_STAT(totalWrittenBytes
, "Number of bytes written"),
120 ADD_STAT(averageWriteBandwidth
, "Average write bandwidth (bytes/s)",
121 totalWrittenBytes
/ simSeconds
),
123 disableLatencyHists(params
.disable_latency_hists
),
124 ADD_STAT(readLatencyHist
, "Read request-response latency"),
125 ADD_STAT(writeLatencyHist
, "Write request-response latency"),
127 disableITTDists(params
.disable_itt_dists
),
128 ADD_STAT(ittReadRead
, "Read-to-read inter transaction time"),
129 ADD_STAT(ittWriteWrite
, "Write-to-write inter transaction time"),
130 ADD_STAT(ittReqReq
, "Request-to-request inter transaction time"),
131 timeOfLastRead(0), timeOfLastWrite(0), timeOfLastReq(0),
133 disableOutstandingHists(params
.disable_outstanding_hists
),
134 ADD_STAT(outstandingReadsHist
, "Outstanding read transactions"),
135 outstandingReadReqs(0),
136 ADD_STAT(outstandingWritesHist
, "Outstanding write transactions"),
137 outstandingWriteReqs(0),
139 disableTransactionHists(params
.disable_transaction_hists
),
140 ADD_STAT(readTransHist
,
141 "Histogram of read transactions per sample period"),
143 ADD_STAT(writeTransHist
,
144 "Histogram of write transactions per sample period"),
147 disableAddrDists(params
.disable_addr_dists
),
148 readAddrMask(params
.read_addr_mask
),
149 writeAddrMask(params
.write_addr_mask
),
150 ADD_STAT(readAddrDist
, "Read address distribution"),
151 ADD_STAT(writeAddrDist
, "Write address distribution")
153 using namespace Stats
;
156 .init(params
.burst_length_bins
)
157 .flags(disableBurstLengthHists
? nozero
: pdf
);
160 .init(params
.burst_length_bins
)
161 .flags(disableBurstLengthHists
? nozero
: pdf
);
163 // Stats based on received responses
165 .init(params
.bandwidth_bins
)
166 .flags(disableBandwidthHists
? nozero
: pdf
);
169 .flags(disableBandwidthHists
? nozero
: pdf
);
172 .flags(disableBandwidthHists
? nozero
: pdf
);
174 // Stats based on successfully sent requests
176 .init(params
.bandwidth_bins
)
177 .flags(disableBandwidthHists
? (pdf
| nozero
) : pdf
);
179 averageWriteBandwidth
180 .flags(disableBandwidthHists
? nozero
: pdf
);
183 .flags(disableBandwidthHists
? nozero
: pdf
);
187 .init(params
.latency_bins
)
188 .flags(disableLatencyHists
? nozero
: pdf
);
191 .init(params
.latency_bins
)
192 .flags(disableLatencyHists
? nozero
: pdf
);
195 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
197 .flags(disableITTDists
? nozero
: pdf
);
200 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
202 .flags(disableITTDists
? nozero
: pdf
);
205 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
207 .flags(disableITTDists
? nozero
: pdf
);
210 .init(params
.outstanding_bins
)
211 .flags(disableOutstandingHists
? nozero
: pdf
);
213 outstandingWritesHist
214 .init(params
.outstanding_bins
)
215 .flags(disableOutstandingHists
? nozero
: pdf
);
218 .init(params
.transaction_bins
)
219 .flags(disableTransactionHists
? nozero
: pdf
);
222 .init(params
.transaction_bins
)
223 .flags(disableTransactionHists
? nozero
: pdf
);
227 .flags(disableAddrDists
? nozero
: pdf
);
231 .flags(disableAddrDists
? nozero
: pdf
);
235 CommMonitor::MonitorStats::updateReqStats(
236 const ProbePoints::PacketInfo
& pkt_info
, bool is_atomic
,
237 bool expects_response
)
239 if (pkt_info
.cmd
.isRead()) {
240 // Increment number of observed read transactions
241 if (!disableTransactionHists
)
244 // Get sample of burst length
245 if (!disableBurstLengthHists
)
246 readBurstLengthHist
.sample(pkt_info
.size
);
248 // Sample the masked address
249 if (!disableAddrDists
)
250 readAddrDist
.sample(pkt_info
.addr
& readAddrMask
);
252 if (!disableITTDists
) {
253 // Sample value of read-read inter transaction time
254 if (timeOfLastRead
!= 0)
255 ittReadRead
.sample(curTick() - timeOfLastRead
);
256 timeOfLastRead
= curTick();
258 // Sample value of req-req inter transaction time
259 if (timeOfLastReq
!= 0)
260 ittReqReq
.sample(curTick() - timeOfLastReq
);
261 timeOfLastReq
= curTick();
263 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
264 ++outstandingReadReqs
;
266 } else if (pkt_info
.cmd
.isWrite()) {
268 if (!disableTransactionHists
)
271 if (!disableBurstLengthHists
)
272 writeBurstLengthHist
.sample(pkt_info
.size
);
274 // Update the bandwidth stats on the request
275 if (!disableBandwidthHists
) {
276 writtenBytes
+= pkt_info
.size
;
277 totalWrittenBytes
+= pkt_info
.size
;
280 // Sample the masked write address
281 if (!disableAddrDists
)
282 writeAddrDist
.sample(pkt_info
.addr
& writeAddrMask
);
284 if (!disableITTDists
) {
285 // Sample value of write-to-write inter transaction time
286 if (timeOfLastWrite
!= 0)
287 ittWriteWrite
.sample(curTick() - timeOfLastWrite
);
288 timeOfLastWrite
= curTick();
290 // Sample value of req-to-req inter transaction time
291 if (timeOfLastReq
!= 0)
292 ittReqReq
.sample(curTick() - timeOfLastReq
);
293 timeOfLastReq
= curTick();
296 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
297 ++outstandingWriteReqs
;
302 CommMonitor::MonitorStats::updateRespStats(
303 const ProbePoints::PacketInfo
& pkt_info
, Tick latency
, bool is_atomic
)
305 if (pkt_info
.cmd
.isRead()) {
306 // Decrement number of outstanding read requests
307 if (!is_atomic
&& !disableOutstandingHists
) {
308 assert(outstandingReadReqs
!= 0);
309 --outstandingReadReqs
;
312 if (!disableLatencyHists
)
313 readLatencyHist
.sample(latency
);
315 // Update the bandwidth stats based on responses for reads
316 if (!disableBandwidthHists
) {
317 readBytes
+= pkt_info
.size
;
318 totalReadBytes
+= pkt_info
.size
;
321 } else if (pkt_info
.cmd
.isWrite()) {
322 // Decrement number of outstanding write requests
323 if (!is_atomic
&& !disableOutstandingHists
) {
324 assert(outstandingWriteReqs
!= 0);
325 --outstandingWriteReqs
;
328 if (!disableLatencyHists
)
329 writeLatencyHist
.sample(latency
);
334 CommMonitor::recvAtomic(PacketPtr pkt
)
336 const bool expects_response(pkt
->needsResponse() &&
337 !pkt
->cacheResponding());
338 ProbePoints::PacketInfo
req_pkt_info(pkt
);
339 ppPktReq
->notify(req_pkt_info
);
341 const Tick
delay(memSidePort
.sendAtomic(pkt
));
343 stats
.updateReqStats(req_pkt_info
, true, expects_response
);
344 if (expects_response
)
345 stats
.updateRespStats(req_pkt_info
, delay
, true);
347 // Some packets, such as WritebackDirty, don't need response.
348 assert(pkt
->isResponse() || !expects_response
);
349 ProbePoints::PacketInfo
resp_pkt_info(pkt
);
350 ppPktResp
->notify(resp_pkt_info
);
355 CommMonitor::recvAtomicSnoop(PacketPtr pkt
)
357 return cpuSidePort
.sendAtomicSnoop(pkt
);
361 CommMonitor::recvTimingReq(PacketPtr pkt
)
363 // should always see a request
364 assert(pkt
->isRequest());
366 // Store relevant fields of packet, because packet may be modified
367 // or even deleted when sendTiming() is called.
368 const ProbePoints::PacketInfo
pkt_info(pkt
);
370 const bool expects_response(pkt
->needsResponse() &&
371 !pkt
->cacheResponding());
373 // If a cache miss is served by a cache, a monitor near the memory
374 // would see a request which needs a response, but this response
375 // would not come back from the memory. Therefore we additionally
376 // have to check the cacheResponding flag
377 if (expects_response
&& !stats
.disableLatencyHists
) {
378 pkt
->pushSenderState(new CommMonitorSenderState(curTick()));
381 // Attempt to send the packet
382 bool successful
= memSidePort
.sendTimingReq(pkt
);
384 // If not successful, restore the sender state
385 if (!successful
&& expects_response
&& !stats
.disableLatencyHists
) {
386 delete pkt
->popSenderState();
390 ppPktReq
->notify(pkt_info
);
394 DPRINTF(CommMonitor
, "Forwarded %s request\n", pkt
->isRead() ? "read" :
395 pkt
->isWrite() ? "write" : "non read/write");
396 stats
.updateReqStats(pkt_info
, false, expects_response
);
402 CommMonitor::recvTimingResp(PacketPtr pkt
)
404 // should always see responses
405 assert(pkt
->isResponse());
407 // Store relevant fields of packet, because packet may be modified
408 // or even deleted when sendTiming() is called.
409 const ProbePoints::PacketInfo
pkt_info(pkt
);
412 CommMonitorSenderState
* received_state
=
413 dynamic_cast<CommMonitorSenderState
*>(pkt
->senderState
);
415 if (!stats
.disableLatencyHists
) {
416 // Restore initial sender state
417 if (received_state
== NULL
)
418 panic("Monitor got a response without monitor sender state\n");
421 pkt
->senderState
= received_state
->predecessor
;
424 // Attempt to send the packet
425 bool successful
= cpuSidePort
.sendTimingResp(pkt
);
427 if (!stats
.disableLatencyHists
) {
428 // If packet successfully send, sample value of latency,
429 // afterwards delete sender state, otherwise restore state
431 latency
= curTick() - received_state
->transmitTime
;
432 DPRINTF(CommMonitor
, "Latency: %d\n", latency
);
433 delete received_state
;
435 // Don't delete anything and let the packet look like we
437 pkt
->senderState
= received_state
;
442 ppPktResp
->notify(pkt_info
);
443 DPRINTF(CommMonitor
, "Received %s response\n", pkt
->isRead() ? "read" :
444 pkt
->isWrite() ? "write" : "non read/write");
445 stats
.updateRespStats(pkt_info
, latency
, false);
451 CommMonitor::recvTimingSnoopReq(PacketPtr pkt
)
453 cpuSidePort
.sendTimingSnoopReq(pkt
);
457 CommMonitor::recvTimingSnoopResp(PacketPtr pkt
)
459 return memSidePort
.sendTimingSnoopResp(pkt
);
463 CommMonitor::recvRetrySnoopResp()
465 cpuSidePort
.sendRetrySnoopResp();
469 CommMonitor::isSnooping() const
471 // check if the connected request port is snooping
472 return cpuSidePort
.isSnooping();
476 CommMonitor::getAddrRanges() const
478 // get the address ranges of the connected CPU-side port
479 return memSidePort
.getAddrRanges();
483 CommMonitor::recvReqRetry()
485 cpuSidePort
.sendRetryReq();
489 CommMonitor::recvRespRetry()
491 memSidePort
.sendRetryResp();
495 CommMonitor::tryTiming(PacketPtr pkt
)
497 return memSidePort
.tryTiming(pkt
);
501 CommMonitor::recvRangeChange()
503 cpuSidePort
.sendRangeChange();
507 CommMonitor::samplePeriodic()
509 // the periodic stats update runs on the granularity of sample
510 // periods, but in combination with this there may also be a
511 // external resets and dumps of the stats (through schedStatEvent)
512 // causing the stats themselves to capture less than a sample
515 // only capture if we have not reset the stats during the last
517 if (simTicks
.value() >= samplePeriodTicks
) {
518 if (!stats
.disableTransactionHists
) {
519 stats
.readTransHist
.sample(stats
.readTrans
);
520 stats
.writeTransHist
.sample(stats
.writeTrans
);
523 if (!stats
.disableBandwidthHists
) {
524 stats
.readBandwidthHist
.sample(stats
.readBytes
/ samplePeriod
);
525 stats
.writeBandwidthHist
.sample(stats
.writtenBytes
/ samplePeriod
);
528 if (!stats
.disableOutstandingHists
) {
529 stats
.outstandingReadsHist
.sample(stats
.outstandingReadReqs
);
530 stats
.outstandingWritesHist
.sample(stats
.outstandingWriteReqs
);
534 // reset the sampled values
536 stats
.writeTrans
= 0;
539 stats
.writtenBytes
= 0;
541 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);
545 CommMonitor::startup()
547 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);