misc: Replaced master/slave terminology
[gem5.git] / src / mem / comm_monitor.cc
1 /*
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
5 * All rights reserved.
6 *
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.
15 *
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.
26 *
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.
38 */
39
40 #include "mem/comm_monitor.hh"
41
42 #include "base/trace.hh"
43 #include "debug/CommMonitor.hh"
44 #include "sim/stats.hh"
45
46 CommMonitor::CommMonitor(Params* params)
47 : SimObject(params),
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),
53 stats(this, params)
54 {
55 DPRINTF(CommMonitor,
56 "Created monitor %s with sample period %d ticks (%f ms)\n",
57 name(), samplePeriodTicks, samplePeriod * 1E3);
58 }
59
60 CommMonitor*
61 CommMonitorParams::create()
62 {
63 return new CommMonitor(this);
64 }
65
66 void
67 CommMonitor::init()
68 {
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");
72 }
73
74 void
75 CommMonitor::regProbePoints()
76 {
77 ppPktReq.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
78 ppPktResp.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
79 }
80
81 Port &
82 CommMonitor::getPort(const std::string &if_name, PortID idx)
83 {
84 if (if_name == "mem_side_port") {
85 return memSidePort;
86 } else if (if_name == "cpu_side_port") {
87 return cpuSidePort;
88 } else {
89 return SimObject::getPort(if_name, idx);
90 }
91 }
92
93 void
94 CommMonitor::recvFunctional(PacketPtr pkt)
95 {
96 memSidePort.sendFunctional(pkt);
97 }
98
99 void
100 CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
101 {
102 cpuSidePort.sendFunctionalSnoop(pkt);
103 }
104
105 CommMonitor::MonitorStats::MonitorStats(Stats::Group *parent,
106 const CommMonitorParams *params)
107 : Stats::Group(parent),
108
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"),
114
115 disableBandwidthHists(params->disable_bandwidth_hists),
116 readBytes(0),
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),
122
123 writtenBytes(0),
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),
128
129 disableLatencyHists(params->disable_latency_hists),
130 ADD_STAT(readLatencyHist, "Read request-response latency"),
131 ADD_STAT(writeLatencyHist, "Write request-response latency"),
132
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),
138
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),
144
145 disableTransactionHists(params->disable_transaction_hists),
146 ADD_STAT(readTransHist,
147 "Histogram of read transactions per sample period"),
148 readTrans(0),
149 ADD_STAT(writeTransHist,
150 "Histogram of write transactions per sample period"),
151 writeTrans(0),
152
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")
158 {
159 using namespace Stats;
160
161 readBurstLengthHist
162 .init(params->burst_length_bins)
163 .flags(disableBurstLengthHists ? nozero : pdf);
164
165 writeBurstLengthHist
166 .init(params->burst_length_bins)
167 .flags(disableBurstLengthHists ? nozero : pdf);
168
169 // Stats based on received responses
170 readBandwidthHist
171 .init(params->bandwidth_bins)
172 .flags(disableBandwidthHists ? nozero : pdf);
173
174 averageReadBandwidth
175 .flags(disableBandwidthHists ? nozero : pdf);
176
177 totalReadBytes
178 .flags(disableBandwidthHists ? nozero : pdf);
179
180 // Stats based on successfully sent requests
181 writeBandwidthHist
182 .init(params->bandwidth_bins)
183 .flags(disableBandwidthHists ? (pdf | nozero) : pdf);
184
185 averageWriteBandwidth
186 .flags(disableBandwidthHists ? nozero : pdf);
187
188 totalWrittenBytes
189 .flags(disableBandwidthHists ? nozero : pdf);
190
191
192 readLatencyHist
193 .init(params->latency_bins)
194 .flags(disableLatencyHists ? nozero : pdf);
195
196 writeLatencyHist
197 .init(params->latency_bins)
198 .flags(disableLatencyHists ? nozero : pdf);
199
200 ittReadRead
201 .init(1, params->itt_max_bin, params->itt_max_bin /
202 params->itt_bins)
203 .flags(disableITTDists ? nozero : pdf);
204
205 ittWriteWrite
206 .init(1, params->itt_max_bin, params->itt_max_bin /
207 params->itt_bins)
208 .flags(disableITTDists ? nozero : pdf);
209
210 ittReqReq
211 .init(1, params->itt_max_bin, params->itt_max_bin /
212 params->itt_bins)
213 .flags(disableITTDists ? nozero : pdf);
214
215 outstandingReadsHist
216 .init(params->outstanding_bins)
217 .flags(disableOutstandingHists ? nozero : pdf);
218
219 outstandingWritesHist
220 .init(params->outstanding_bins)
221 .flags(disableOutstandingHists ? nozero : pdf);
222
223 readTransHist
224 .init(params->transaction_bins)
225 .flags(disableTransactionHists ? nozero : pdf);
226
227 writeTransHist
228 .init(params->transaction_bins)
229 .flags(disableTransactionHists ? nozero : pdf);
230
231 readAddrDist
232 .init(0)
233 .flags(disableAddrDists ? nozero : pdf);
234
235 writeAddrDist
236 .init(0)
237 .flags(disableAddrDists ? nozero : pdf);
238 }
239
240 void
241 CommMonitor::MonitorStats::updateReqStats(
242 const ProbePoints::PacketInfo& pkt_info, bool is_atomic,
243 bool expects_response)
244 {
245 if (pkt_info.cmd.isRead()) {
246 // Increment number of observed read transactions
247 if (!disableTransactionHists)
248 ++readTrans;
249
250 // Get sample of burst length
251 if (!disableBurstLengthHists)
252 readBurstLengthHist.sample(pkt_info.size);
253
254 // Sample the masked address
255 if (!disableAddrDists)
256 readAddrDist.sample(pkt_info.addr & readAddrMask);
257
258 if (!disableITTDists) {
259 // Sample value of read-read inter transaction time
260 if (timeOfLastRead != 0)
261 ittReadRead.sample(curTick() - timeOfLastRead);
262 timeOfLastRead = curTick();
263
264 // Sample value of req-req inter transaction time
265 if (timeOfLastReq != 0)
266 ittReqReq.sample(curTick() - timeOfLastReq);
267 timeOfLastReq = curTick();
268 }
269 if (!is_atomic && !disableOutstandingHists && expects_response)
270 ++outstandingReadReqs;
271
272 } else if (pkt_info.cmd.isWrite()) {
273 // Same as for reads
274 if (!disableTransactionHists)
275 ++writeTrans;
276
277 if (!disableBurstLengthHists)
278 writeBurstLengthHist.sample(pkt_info.size);
279
280 // Update the bandwidth stats on the request
281 if (!disableBandwidthHists) {
282 writtenBytes += pkt_info.size;
283 totalWrittenBytes += pkt_info.size;
284 }
285
286 // Sample the masked write address
287 if (!disableAddrDists)
288 writeAddrDist.sample(pkt_info.addr & writeAddrMask);
289
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();
295
296 // Sample value of req-to-req inter transaction time
297 if (timeOfLastReq != 0)
298 ittReqReq.sample(curTick() - timeOfLastReq);
299 timeOfLastReq = curTick();
300 }
301
302 if (!is_atomic && !disableOutstandingHists && expects_response)
303 ++outstandingWriteReqs;
304 }
305 }
306
307 void
308 CommMonitor::MonitorStats::updateRespStats(
309 const ProbePoints::PacketInfo& pkt_info, Tick latency, bool is_atomic)
310 {
311 if (pkt_info.cmd.isRead()) {
312 // Decrement number of outstanding read requests
313 if (!is_atomic && !disableOutstandingHists) {
314 assert(outstandingReadReqs != 0);
315 --outstandingReadReqs;
316 }
317
318 if (!disableLatencyHists)
319 readLatencyHist.sample(latency);
320
321 // Update the bandwidth stats based on responses for reads
322 if (!disableBandwidthHists) {
323 readBytes += pkt_info.size;
324 totalReadBytes += pkt_info.size;
325 }
326
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;
332 }
333
334 if (!disableLatencyHists)
335 writeLatencyHist.sample(latency);
336 }
337 }
338
339 Tick
340 CommMonitor::recvAtomic(PacketPtr pkt)
341 {
342 const bool expects_response(pkt->needsResponse() &&
343 !pkt->cacheResponding());
344 ProbePoints::PacketInfo req_pkt_info(pkt);
345 ppPktReq->notify(req_pkt_info);
346
347 const Tick delay(memSidePort.sendAtomic(pkt));
348
349 stats.updateReqStats(req_pkt_info, true, expects_response);
350 if (expects_response)
351 stats.updateRespStats(req_pkt_info, delay, true);
352
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);
357 return delay;
358 }
359
360 Tick
361 CommMonitor::recvAtomicSnoop(PacketPtr pkt)
362 {
363 return cpuSidePort.sendAtomicSnoop(pkt);
364 }
365
366 bool
367 CommMonitor::recvTimingReq(PacketPtr pkt)
368 {
369 // should always see a request
370 assert(pkt->isRequest());
371
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);
375
376 const bool expects_response(pkt->needsResponse() &&
377 !pkt->cacheResponding());
378
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()));
385 }
386
387 // Attempt to send the packet
388 bool successful = memSidePort.sendTimingReq(pkt);
389
390 // If not successful, restore the sender state
391 if (!successful && expects_response && !stats.disableLatencyHists) {
392 delete pkt->popSenderState();
393 }
394
395 if (successful) {
396 ppPktReq->notify(pkt_info);
397 }
398
399 if (successful) {
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);
403 }
404 return successful;
405 }
406
407 bool
408 CommMonitor::recvTimingResp(PacketPtr pkt)
409 {
410 // should always see responses
411 assert(pkt->isResponse());
412
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);
416
417 Tick latency = 0;
418 CommMonitorSenderState* received_state =
419 dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
420
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");
425
426 // Restore the sate
427 pkt->senderState = received_state->predecessor;
428 }
429
430 // Attempt to send the packet
431 bool successful = cpuSidePort.sendTimingResp(pkt);
432
433 if (!stats.disableLatencyHists) {
434 // If packet successfully send, sample value of latency,
435 // afterwards delete sender state, otherwise restore state
436 if (successful) {
437 latency = curTick() - received_state->transmitTime;
438 DPRINTF(CommMonitor, "Latency: %d\n", latency);
439 delete received_state;
440 } else {
441 // Don't delete anything and let the packet look like we
442 // did not touch it
443 pkt->senderState = received_state;
444 }
445 }
446
447 if (successful) {
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);
452 }
453 return successful;
454 }
455
456 void
457 CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
458 {
459 cpuSidePort.sendTimingSnoopReq(pkt);
460 }
461
462 bool
463 CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
464 {
465 return memSidePort.sendTimingSnoopResp(pkt);
466 }
467
468 void
469 CommMonitor::recvRetrySnoopResp()
470 {
471 cpuSidePort.sendRetrySnoopResp();
472 }
473
474 bool
475 CommMonitor::isSnooping() const
476 {
477 // check if the connected request port is snooping
478 return cpuSidePort.isSnooping();
479 }
480
481 AddrRangeList
482 CommMonitor::getAddrRanges() const
483 {
484 // get the address ranges of the connected CPU-side port
485 return memSidePort.getAddrRanges();
486 }
487
488 void
489 CommMonitor::recvReqRetry()
490 {
491 cpuSidePort.sendRetryReq();
492 }
493
494 void
495 CommMonitor::recvRespRetry()
496 {
497 memSidePort.sendRetryResp();
498 }
499
500 bool
501 CommMonitor::tryTiming(PacketPtr pkt)
502 {
503 return memSidePort.tryTiming(pkt);
504 }
505
506 void
507 CommMonitor::recvRangeChange()
508 {
509 cpuSidePort.sendRangeChange();
510 }
511
512 void
513 CommMonitor::samplePeriodic()
514 {
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
519 // period
520
521 // only capture if we have not reset the stats during the last
522 // sample period
523 if (simTicks.value() >= samplePeriodTicks) {
524 if (!stats.disableTransactionHists) {
525 stats.readTransHist.sample(stats.readTrans);
526 stats.writeTransHist.sample(stats.writeTrans);
527 }
528
529 if (!stats.disableBandwidthHists) {
530 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
531 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
532 }
533
534 if (!stats.disableOutstandingHists) {
535 stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
536 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
537 }
538 }
539
540 // reset the sampled values
541 stats.readTrans = 0;
542 stats.writeTrans = 0;
543
544 stats.readBytes = 0;
545 stats.writtenBytes = 0;
546
547 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
548 }
549
550 void
551 CommMonitor::startup()
552 {
553 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
554 }