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
, UNIT_BYTE
,
105 "Histogram of burst lengths of transmitted packets"),
106 ADD_STAT(writeBurstLengthHist
, UNIT_BYTE
,
107 "Histogram of burst lengths of transmitted packets"),
109 disableBandwidthHists(params
.disable_bandwidth_hists
),
111 ADD_STAT(readBandwidthHist
,
112 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
113 "Histogram of read bandwidth per sample period (bytes/s)"),
114 ADD_STAT(totalReadBytes
, UNIT_BYTE
, "Number of bytes read"),
115 ADD_STAT(averageReadBandwidth
,
116 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
117 "Average read bandwidth (bytes/s)",
118 totalReadBytes
/ simSeconds
),
121 ADD_STAT(writeBandwidthHist
,
122 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
123 "Histogram of write bandwidth (bytes/s)"),
124 ADD_STAT(totalWrittenBytes
,
125 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
126 "Number of bytes written"),
127 ADD_STAT(averageWriteBandwidth
,
128 UNIT_RATE(Stats::Units::Byte
, Stats::Units::Second
),
129 "Average write bandwidth (bytes/s)",
130 totalWrittenBytes
/ simSeconds
),
132 disableLatencyHists(params
.disable_latency_hists
),
133 ADD_STAT(readLatencyHist
, UNIT_TICK
, "Read request-response latency"),
134 ADD_STAT(writeLatencyHist
, UNIT_TICK
, "Write request-response latency"),
136 disableITTDists(params
.disable_itt_dists
),
137 ADD_STAT(ittReadRead
, UNIT_TICK
, "Read-to-read inter transaction time"),
138 ADD_STAT(ittWriteWrite
, UNIT_TICK
,
139 "Write-to-write inter transaction time"),
140 ADD_STAT(ittReqReq
, UNIT_TICK
,
141 "Request-to-request inter transaction time"),
142 timeOfLastRead(0), timeOfLastWrite(0), timeOfLastReq(0),
144 disableOutstandingHists(params
.disable_outstanding_hists
),
145 ADD_STAT(outstandingReadsHist
, UNIT_COUNT
,
146 "Outstanding read transactions"),
147 outstandingReadReqs(0),
148 ADD_STAT(outstandingWritesHist
, UNIT_COUNT
,
149 "Outstanding write transactions"),
150 outstandingWriteReqs(0),
152 disableTransactionHists(params
.disable_transaction_hists
),
153 ADD_STAT(readTransHist
, UNIT_COUNT
,
154 "Histogram of read transactions per sample period"),
156 ADD_STAT(writeTransHist
, UNIT_COUNT
,
157 "Histogram of write transactions per sample period"),
160 disableAddrDists(params
.disable_addr_dists
),
161 readAddrMask(params
.read_addr_mask
),
162 writeAddrMask(params
.write_addr_mask
),
163 ADD_STAT(readAddrDist
, UNIT_COUNT
, "Read address distribution"),
164 ADD_STAT(writeAddrDist
, UNIT_COUNT
, "Write address distribution")
166 using namespace Stats
;
169 .init(params
.burst_length_bins
)
170 .flags(disableBurstLengthHists
? nozero
: pdf
);
173 .init(params
.burst_length_bins
)
174 .flags(disableBurstLengthHists
? nozero
: pdf
);
176 // Stats based on received responses
178 .init(params
.bandwidth_bins
)
179 .flags(disableBandwidthHists
? nozero
: pdf
);
182 .flags(disableBandwidthHists
? nozero
: pdf
);
185 .flags(disableBandwidthHists
? nozero
: pdf
);
187 // Stats based on successfully sent requests
189 .init(params
.bandwidth_bins
)
190 .flags(disableBandwidthHists
? (pdf
| nozero
) : pdf
);
192 averageWriteBandwidth
193 .flags(disableBandwidthHists
? nozero
: pdf
);
196 .flags(disableBandwidthHists
? nozero
: pdf
);
200 .init(params
.latency_bins
)
201 .flags(disableLatencyHists
? nozero
: pdf
);
204 .init(params
.latency_bins
)
205 .flags(disableLatencyHists
? nozero
: pdf
);
208 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
210 .flags(disableITTDists
? nozero
: pdf
);
213 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
215 .flags(disableITTDists
? nozero
: pdf
);
218 .init(1, params
.itt_max_bin
, params
.itt_max_bin
/
220 .flags(disableITTDists
? nozero
: pdf
);
223 .init(params
.outstanding_bins
)
224 .flags(disableOutstandingHists
? nozero
: pdf
);
226 outstandingWritesHist
227 .init(params
.outstanding_bins
)
228 .flags(disableOutstandingHists
? nozero
: pdf
);
231 .init(params
.transaction_bins
)
232 .flags(disableTransactionHists
? nozero
: pdf
);
235 .init(params
.transaction_bins
)
236 .flags(disableTransactionHists
? nozero
: pdf
);
240 .flags(disableAddrDists
? nozero
: pdf
);
244 .flags(disableAddrDists
? nozero
: pdf
);
248 CommMonitor::MonitorStats::updateReqStats(
249 const ProbePoints::PacketInfo
& pkt_info
, bool is_atomic
,
250 bool expects_response
)
252 if (pkt_info
.cmd
.isRead()) {
253 // Increment number of observed read transactions
254 if (!disableTransactionHists
)
257 // Get sample of burst length
258 if (!disableBurstLengthHists
)
259 readBurstLengthHist
.sample(pkt_info
.size
);
261 // Sample the masked address
262 if (!disableAddrDists
)
263 readAddrDist
.sample(pkt_info
.addr
& readAddrMask
);
265 if (!disableITTDists
) {
266 // Sample value of read-read inter transaction time
267 if (timeOfLastRead
!= 0)
268 ittReadRead
.sample(curTick() - timeOfLastRead
);
269 timeOfLastRead
= curTick();
271 // Sample value of req-req inter transaction time
272 if (timeOfLastReq
!= 0)
273 ittReqReq
.sample(curTick() - timeOfLastReq
);
274 timeOfLastReq
= curTick();
276 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
277 ++outstandingReadReqs
;
279 } else if (pkt_info
.cmd
.isWrite()) {
281 if (!disableTransactionHists
)
284 if (!disableBurstLengthHists
)
285 writeBurstLengthHist
.sample(pkt_info
.size
);
287 // Update the bandwidth stats on the request
288 if (!disableBandwidthHists
) {
289 writtenBytes
+= pkt_info
.size
;
290 totalWrittenBytes
+= pkt_info
.size
;
293 // Sample the masked write address
294 if (!disableAddrDists
)
295 writeAddrDist
.sample(pkt_info
.addr
& writeAddrMask
);
297 if (!disableITTDists
) {
298 // Sample value of write-to-write inter transaction time
299 if (timeOfLastWrite
!= 0)
300 ittWriteWrite
.sample(curTick() - timeOfLastWrite
);
301 timeOfLastWrite
= curTick();
303 // Sample value of req-to-req inter transaction time
304 if (timeOfLastReq
!= 0)
305 ittReqReq
.sample(curTick() - timeOfLastReq
);
306 timeOfLastReq
= curTick();
309 if (!is_atomic
&& !disableOutstandingHists
&& expects_response
)
310 ++outstandingWriteReqs
;
315 CommMonitor::MonitorStats::updateRespStats(
316 const ProbePoints::PacketInfo
& pkt_info
, Tick latency
, bool is_atomic
)
318 if (pkt_info
.cmd
.isRead()) {
319 // Decrement number of outstanding read requests
320 if (!is_atomic
&& !disableOutstandingHists
) {
321 assert(outstandingReadReqs
!= 0);
322 --outstandingReadReqs
;
325 if (!disableLatencyHists
)
326 readLatencyHist
.sample(latency
);
328 // Update the bandwidth stats based on responses for reads
329 if (!disableBandwidthHists
) {
330 readBytes
+= pkt_info
.size
;
331 totalReadBytes
+= pkt_info
.size
;
334 } else if (pkt_info
.cmd
.isWrite()) {
335 // Decrement number of outstanding write requests
336 if (!is_atomic
&& !disableOutstandingHists
) {
337 assert(outstandingWriteReqs
!= 0);
338 --outstandingWriteReqs
;
341 if (!disableLatencyHists
)
342 writeLatencyHist
.sample(latency
);
347 CommMonitor::recvAtomic(PacketPtr pkt
)
349 const bool expects_response(pkt
->needsResponse() &&
350 !pkt
->cacheResponding());
351 ProbePoints::PacketInfo
req_pkt_info(pkt
);
352 ppPktReq
->notify(req_pkt_info
);
354 const Tick
delay(memSidePort
.sendAtomic(pkt
));
356 stats
.updateReqStats(req_pkt_info
, true, expects_response
);
357 if (expects_response
)
358 stats
.updateRespStats(req_pkt_info
, delay
, true);
360 // Some packets, such as WritebackDirty, don't need response.
361 assert(pkt
->isResponse() || !expects_response
);
362 ProbePoints::PacketInfo
resp_pkt_info(pkt
);
363 ppPktResp
->notify(resp_pkt_info
);
368 CommMonitor::recvAtomicSnoop(PacketPtr pkt
)
370 return cpuSidePort
.sendAtomicSnoop(pkt
);
374 CommMonitor::recvTimingReq(PacketPtr pkt
)
376 // should always see a request
377 assert(pkt
->isRequest());
379 // Store relevant fields of packet, because packet may be modified
380 // or even deleted when sendTiming() is called.
381 const ProbePoints::PacketInfo
pkt_info(pkt
);
383 const bool expects_response(pkt
->needsResponse() &&
384 !pkt
->cacheResponding());
386 // If a cache miss is served by a cache, a monitor near the memory
387 // would see a request which needs a response, but this response
388 // would not come back from the memory. Therefore we additionally
389 // have to check the cacheResponding flag
390 if (expects_response
&& !stats
.disableLatencyHists
) {
391 pkt
->pushSenderState(new CommMonitorSenderState(curTick()));
394 // Attempt to send the packet
395 bool successful
= memSidePort
.sendTimingReq(pkt
);
397 // If not successful, restore the sender state
398 if (!successful
&& expects_response
&& !stats
.disableLatencyHists
) {
399 delete pkt
->popSenderState();
403 ppPktReq
->notify(pkt_info
);
407 DPRINTF(CommMonitor
, "Forwarded %s request\n", pkt
->isRead() ? "read" :
408 pkt
->isWrite() ? "write" : "non read/write");
409 stats
.updateReqStats(pkt_info
, false, expects_response
);
415 CommMonitor::recvTimingResp(PacketPtr pkt
)
417 // should always see responses
418 assert(pkt
->isResponse());
420 // Store relevant fields of packet, because packet may be modified
421 // or even deleted when sendTiming() is called.
422 const ProbePoints::PacketInfo
pkt_info(pkt
);
425 CommMonitorSenderState
* received_state
=
426 dynamic_cast<CommMonitorSenderState
*>(pkt
->senderState
);
428 if (!stats
.disableLatencyHists
) {
429 // Restore initial sender state
430 if (received_state
== NULL
)
431 panic("Monitor got a response without monitor sender state\n");
434 pkt
->senderState
= received_state
->predecessor
;
437 // Attempt to send the packet
438 bool successful
= cpuSidePort
.sendTimingResp(pkt
);
440 if (!stats
.disableLatencyHists
) {
441 // If packet successfully send, sample value of latency,
442 // afterwards delete sender state, otherwise restore state
444 latency
= curTick() - received_state
->transmitTime
;
445 DPRINTF(CommMonitor
, "Latency: %d\n", latency
);
446 delete received_state
;
448 // Don't delete anything and let the packet look like we
450 pkt
->senderState
= received_state
;
455 ppPktResp
->notify(pkt_info
);
456 DPRINTF(CommMonitor
, "Received %s response\n", pkt
->isRead() ? "read" :
457 pkt
->isWrite() ? "write" : "non read/write");
458 stats
.updateRespStats(pkt_info
, latency
, false);
464 CommMonitor::recvTimingSnoopReq(PacketPtr pkt
)
466 cpuSidePort
.sendTimingSnoopReq(pkt
);
470 CommMonitor::recvTimingSnoopResp(PacketPtr pkt
)
472 return memSidePort
.sendTimingSnoopResp(pkt
);
476 CommMonitor::recvRetrySnoopResp()
478 cpuSidePort
.sendRetrySnoopResp();
482 CommMonitor::isSnooping() const
484 // check if the connected request port is snooping
485 return cpuSidePort
.isSnooping();
489 CommMonitor::getAddrRanges() const
491 // get the address ranges of the connected CPU-side port
492 return memSidePort
.getAddrRanges();
496 CommMonitor::recvReqRetry()
498 cpuSidePort
.sendRetryReq();
502 CommMonitor::recvRespRetry()
504 memSidePort
.sendRetryResp();
508 CommMonitor::tryTiming(PacketPtr pkt
)
510 return memSidePort
.tryTiming(pkt
);
514 CommMonitor::recvRangeChange()
516 cpuSidePort
.sendRangeChange();
520 CommMonitor::samplePeriodic()
522 // the periodic stats update runs on the granularity of sample
523 // periods, but in combination with this there may also be a
524 // external resets and dumps of the stats (through schedStatEvent)
525 // causing the stats themselves to capture less than a sample
528 // only capture if we have not reset the stats during the last
530 if (simTicks
.value() >= samplePeriodTicks
) {
531 if (!stats
.disableTransactionHists
) {
532 stats
.readTransHist
.sample(stats
.readTrans
);
533 stats
.writeTransHist
.sample(stats
.writeTrans
);
536 if (!stats
.disableBandwidthHists
) {
537 stats
.readBandwidthHist
.sample(stats
.readBytes
/ samplePeriod
);
538 stats
.writeBandwidthHist
.sample(stats
.writtenBytes
/ samplePeriod
);
541 if (!stats
.disableOutstandingHists
) {
542 stats
.outstandingReadsHist
.sample(stats
.outstandingReadReqs
);
543 stats
.outstandingWritesHist
.sample(stats
.outstandingWriteReqs
);
547 // reset the sampled values
549 stats
.writeTrans
= 0;
552 stats
.writtenBytes
= 0;
554 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);
558 CommMonitor::startup()
560 schedule(samplePeriodicEvent
, curTick() + samplePeriodTicks
);