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
);
61 CommMonitorParams::create() const
63 return new CommMonitor(*this);
69 // make sure both sides of the monitor are connected
70 if (!cpuSidePort
.isConnected() || !memSidePort
.isConnected())
71 fatal("Communication monitor is not connected on both sides.\n");
75 CommMonitor::regProbePoints()
77 ppPktReq
.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
78 ppPktResp
.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
82 CommMonitor::getPort(const std::string
&if_name
, PortID idx
)
84 if (if_name
== "mem_side_port") {
86 } else if (if_name
== "cpu_side_port") {
89 return SimObject::getPort(if_name
, idx
);
94 CommMonitor::recvFunctional(PacketPtr pkt
)
96 memSidePort
.sendFunctional(pkt
);
100 CommMonitor::recvFunctionalSnoop(PacketPtr pkt
)
102 cpuSidePort
.sendFunctionalSnoop(pkt
);
105 CommMonitor::MonitorStats::MonitorStats(Stats::Group
*parent
,
106 const CommMonitorParams
¶ms
)
107 : Stats::Group(parent
),
109 disableBurstLengthHists(params
.disable_burst_length_hists
),
110 ADD_STAT(readBurstLengthHist
,
111 "Histogram of burst lengths of transmitted packets"),
112 ADD_STAT(writeBurstLengthHist
,
113 "Histogram of burst lengths of transmitted packets"),
115 disableBandwidthHists(params
.disable_bandwidth_hists
),
117 ADD_STAT(readBandwidthHist
,
118 "Histogram of read bandwidth per sample period (bytes/s)"),
119 ADD_STAT(totalReadBytes
, "Number of bytes read"),
120 ADD_STAT(averageReadBandwidth
, "Average read bandwidth (bytes/s)",
121 totalReadBytes
/ simSeconds
),
124 ADD_STAT(writeBandwidthHist
, "Histogram of write bandwidth (bytes/s)"),
125 ADD_STAT(totalWrittenBytes
, "Number of bytes written"),
126 ADD_STAT(averageWriteBandwidth
, "Average write bandwidth (bytes/s)",
127 totalWrittenBytes
/ simSeconds
),
129 disableLatencyHists(params
.disable_latency_hists
),
130 ADD_STAT(readLatencyHist
, "Read request-response latency"),
131 ADD_STAT(writeLatencyHist
, "Write request-response latency"),
133 disableITTDists(params
.disable_itt_dists
),
134 ADD_STAT(ittReadRead
, "Read-to-read inter transaction time"),
135 ADD_STAT(ittWriteWrite
, "Write-to-write inter transaction time"),
136 ADD_STAT(ittReqReq
, "Request-to-request inter transaction time"),
137 timeOfLastRead(0), timeOfLastWrite(0), timeOfLastReq(0),
139 disableOutstandingHists(params
.disable_outstanding_hists
),
140 ADD_STAT(outstandingReadsHist
, "Outstanding read transactions"),
141 outstandingReadReqs(0),
142 ADD_STAT(outstandingWritesHist
, "Outstanding write transactions"),
143 outstandingWriteReqs(0),
145 disableTransactionHists(params
.disable_transaction_hists
),
146 ADD_STAT(readTransHist
,
147 "Histogram of read transactions per sample period"),
149 ADD_STAT(writeTransHist
,
150 "Histogram of write transactions per sample period"),
153 disableAddrDists(params
.disable_addr_dists
),
154 readAddrMask(params
.read_addr_mask
),
155 writeAddrMask(params
.write_addr_mask
),
156 ADD_STAT(readAddrDist
, "Read address distribution"),
157 ADD_STAT(writeAddrDist
, "Write address distribution")
159 using namespace Stats
;
162 .init(params
.burst_length_bins
)
163 .flags(disableBurstLengthHists
? nozero
: pdf
);
166 .init(params
.burst_length_bins
)
167 .flags(disableBurstLengthHists
? nozero
: pdf
);
169 // Stats based on received responses
171 .init(params
.bandwidth_bins
)
172 .flags(disableBandwidthHists
? nozero
: pdf
);
175 .flags(disableBandwidthHists
? nozero
: pdf
);
178 .flags(disableBandwidthHists
? nozero
: pdf
);
180 // Stats based on successfully sent requests
182 .init(params
.bandwidth_bins
)
183 .flags(disableBandwidthHists
? (pdf
| nozero
) : pdf
);
185 averageWriteBandwidth
186 .flags(disableBandwidthHists
? nozero
: pdf
);
189 .flags(disableBandwidthHists
? nozero
: pdf
);
193 .init(params
.latency_bins
)
194 .flags(disableLatencyHists
? nozero
: pdf
);
197 .init(params
.latency_bins
)
198 .flags(disableLatencyHists
? nozero
: pdf
);
201 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
203 .flags(disableITTDists
? nozero
: pdf
);
206 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
208 .flags(disableITTDists
? nozero
: pdf
);
211 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
213 .flags(disableITTDists
? nozero
: pdf
);
216 .init(params
.outstanding_bins
)
217 .flags(disableOutstandingHists
? nozero
: pdf
);
219 outstandingWritesHist
220 .init(params
.outstanding_bins
)
221 .flags(disableOutstandingHists
? nozero
: pdf
);
224 .init(params
.transaction_bins
)
225 .flags(disableTransactionHists
? nozero
: pdf
);
228 .init(params
.transaction_bins
)
229 .flags(disableTransactionHists
? nozero
: pdf
);
233 .flags(disableAddrDists
? nozero
: pdf
);
237 .flags(disableAddrDists
? nozero
: pdf
);
241 CommMonitor::MonitorStats::updateReqStats(
242 const ProbePoints::PacketInfo
& pkt_info
, bool is_atomic
,
243 bool expects_response
)
245 if (pkt_info
.cmd
.isRead()) {
246 // Increment number of observed read transactions
247 if (!disableTransactionHists
)
250 // Get sample of burst length
251 if (!disableBurstLengthHists
)
252 readBurstLengthHist
.sample(pkt_info
.size
);
254 // Sample the masked address
255 if (!disableAddrDists
)
256 readAddrDist
.sample(pkt_info
.addr
& readAddrMask
);
258 if (!disableITTDists
) {
259 // Sample value of read-read inter transaction time
260 if (timeOfLastRead
!= 0)
261 ittReadRead
.sample(curTick() - timeOfLastRead
);
262 timeOfLastRead
= curTick();
264 // Sample value of req-req inter transaction time
265 if (timeOfLastReq
!= 0)
266 ittReqReq
.sample(curTick() - timeOfLastReq
);
267 timeOfLastReq
= curTick();
269 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
270 ++outstandingReadReqs
;
272 } else if (pkt_info
.cmd
.isWrite()) {
274 if (!disableTransactionHists
)
277 if (!disableBurstLengthHists
)
278 writeBurstLengthHist
.sample(pkt_info
.size
);
280 // Update the bandwidth stats on the request
281 if (!disableBandwidthHists
) {
282 writtenBytes
+= pkt_info
.size
;
283 totalWrittenBytes
+= pkt_info
.size
;
286 // Sample the masked write address
287 if (!disableAddrDists
)
288 writeAddrDist
.sample(pkt_info
.addr
& writeAddrMask
);
290 if (!disableITTDists
) {
291 // Sample value of write-to-write inter transaction time
292 if (timeOfLastWrite
!= 0)
293 ittWriteWrite
.sample(curTick() - timeOfLastWrite
);
294 timeOfLastWrite
= curTick();
296 // Sample value of req-to-req inter transaction time
297 if (timeOfLastReq
!= 0)
298 ittReqReq
.sample(curTick() - timeOfLastReq
);
299 timeOfLastReq
= curTick();
302 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
303 ++outstandingWriteReqs
;
308 CommMonitor::MonitorStats::updateRespStats(
309 const ProbePoints::PacketInfo
& pkt_info
, Tick latency
, bool is_atomic
)
311 if (pkt_info
.cmd
.isRead()) {
312 // Decrement number of outstanding read requests
313 if (!is_atomic
&& !disableOutstandingHists
) {
314 assert(outstandingReadReqs
!= 0);
315 --outstandingReadReqs
;
318 if (!disableLatencyHists
)
319 readLatencyHist
.sample(latency
);
321 // Update the bandwidth stats based on responses for reads
322 if (!disableBandwidthHists
) {
323 readBytes
+= pkt_info
.size
;
324 totalReadBytes
+= pkt_info
.size
;
327 } else if (pkt_info
.cmd
.isWrite()) {
328 // Decrement number of outstanding write requests
329 if (!is_atomic
&& !disableOutstandingHists
) {
330 assert(outstandingWriteReqs
!= 0);
331 --outstandingWriteReqs
;
334 if (!disableLatencyHists
)
335 writeLatencyHist
.sample(latency
);
340 CommMonitor::recvAtomic(PacketPtr pkt
)
342 const bool expects_response(pkt
->needsResponse() &&
343 !pkt
->cacheResponding());
344 ProbePoints::PacketInfo
req_pkt_info(pkt
);
345 ppPktReq
->notify(req_pkt_info
);
347 const Tick
delay(memSidePort
.sendAtomic(pkt
));
349 stats
.updateReqStats(req_pkt_info
, true, expects_response
);
350 if (expects_response
)
351 stats
.updateRespStats(req_pkt_info
, delay
, true);
353 // Some packets, such as WritebackDirty, don't need response.
354 assert(pkt
->isResponse() || !expects_response
);
355 ProbePoints::PacketInfo
resp_pkt_info(pkt
);
356 ppPktResp
->notify(resp_pkt_info
);
361 CommMonitor::recvAtomicSnoop(PacketPtr pkt
)
363 return cpuSidePort
.sendAtomicSnoop(pkt
);
367 CommMonitor::recvTimingReq(PacketPtr pkt
)
369 // should always see a request
370 assert(pkt
->isRequest());
372 // Store relevant fields of packet, because packet may be modified
373 // or even deleted when sendTiming() is called.
374 const ProbePoints::PacketInfo
pkt_info(pkt
);
376 const bool expects_response(pkt
->needsResponse() &&
377 !pkt
->cacheResponding());
379 // If a cache miss is served by a cache, a monitor near the memory
380 // would see a request which needs a response, but this response
381 // would not come back from the memory. Therefore we additionally
382 // have to check the cacheResponding flag
383 if (expects_response
&& !stats
.disableLatencyHists
) {
384 pkt
->pushSenderState(new CommMonitorSenderState(curTick()));
387 // Attempt to send the packet
388 bool successful
= memSidePort
.sendTimingReq(pkt
);
390 // If not successful, restore the sender state
391 if (!successful
&& expects_response
&& !stats
.disableLatencyHists
) {
392 delete pkt
->popSenderState();
396 ppPktReq
->notify(pkt_info
);
400 DPRINTF(CommMonitor
, "Forwarded %s request\n", pkt
->isRead() ? "read" :
401 pkt
->isWrite() ? "write" : "non read/write");
402 stats
.updateReqStats(pkt_info
, false, expects_response
);
408 CommMonitor::recvTimingResp(PacketPtr pkt
)
410 // should always see responses
411 assert(pkt
->isResponse());
413 // Store relevant fields of packet, because packet may be modified
414 // or even deleted when sendTiming() is called.
415 const ProbePoints::PacketInfo
pkt_info(pkt
);
418 CommMonitorSenderState
* received_state
=
419 dynamic_cast<CommMonitorSenderState
*>(pkt
->senderState
);
421 if (!stats
.disableLatencyHists
) {
422 // Restore initial sender state
423 if (received_state
== NULL
)
424 panic("Monitor got a response without monitor sender state\n");
427 pkt
->senderState
= received_state
->predecessor
;
430 // Attempt to send the packet
431 bool successful
= cpuSidePort
.sendTimingResp(pkt
);
433 if (!stats
.disableLatencyHists
) {
434 // If packet successfully send, sample value of latency,
435 // afterwards delete sender state, otherwise restore state
437 latency
= curTick() - received_state
->transmitTime
;
438 DPRINTF(CommMonitor
, "Latency: %d\n", latency
);
439 delete received_state
;
441 // Don't delete anything and let the packet look like we
443 pkt
->senderState
= received_state
;
448 ppPktResp
->notify(pkt_info
);
449 DPRINTF(CommMonitor
, "Received %s response\n", pkt
->isRead() ? "read" :
450 pkt
->isWrite() ? "write" : "non read/write");
451 stats
.updateRespStats(pkt_info
, latency
, false);
457 CommMonitor::recvTimingSnoopReq(PacketPtr pkt
)
459 cpuSidePort
.sendTimingSnoopReq(pkt
);
463 CommMonitor::recvTimingSnoopResp(PacketPtr pkt
)
465 return memSidePort
.sendTimingSnoopResp(pkt
);
469 CommMonitor::recvRetrySnoopResp()
471 cpuSidePort
.sendRetrySnoopResp();
475 CommMonitor::isSnooping() const
477 // check if the connected request port is snooping
478 return cpuSidePort
.isSnooping();
482 CommMonitor::getAddrRanges() const
484 // get the address ranges of the connected CPU-side port
485 return memSidePort
.getAddrRanges();
489 CommMonitor::recvReqRetry()
491 cpuSidePort
.sendRetryReq();
495 CommMonitor::recvRespRetry()
497 memSidePort
.sendRetryResp();
501 CommMonitor::tryTiming(PacketPtr pkt
)
503 return memSidePort
.tryTiming(pkt
);
507 CommMonitor::recvRangeChange()
509 cpuSidePort
.sendRangeChange();
513 CommMonitor::samplePeriodic()
515 // the periodic stats update runs on the granularity of sample
516 // periods, but in combination with this there may also be a
517 // external resets and dumps of the stats (through schedStatEvent)
518 // causing the stats themselves to capture less than a sample
521 // only capture if we have not reset the stats during the last
523 if (simTicks
.value() >= samplePeriodTicks
) {
524 if (!stats
.disableTransactionHists
) {
525 stats
.readTransHist
.sample(stats
.readTrans
);
526 stats
.writeTransHist
.sample(stats
.writeTrans
);
529 if (!stats
.disableBandwidthHists
) {
530 stats
.readBandwidthHist
.sample(stats
.readBytes
/ samplePeriod
);
531 stats
.writeBandwidthHist
.sample(stats
.writtenBytes
/ samplePeriod
);
534 if (!stats
.disableOutstandingHists
) {
535 stats
.outstandingReadsHist
.sample(stats
.outstandingReadReqs
);
536 stats
.outstandingWritesHist
.sample(stats
.outstandingWriteReqs
);
540 // reset the sampled values
542 stats
.writeTrans
= 0;
545 stats
.writtenBytes
= 0;
547 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);
551 CommMonitor::startup()
553 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);