misc: Re-remove Authors lines from source files.
[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(const 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 void
61 CommMonitor::init()
62 {
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");
66 }
67
68 void
69 CommMonitor::regProbePoints()
70 {
71 ppPktReq.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
72 ppPktResp.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
73 }
74
75 Port &
76 CommMonitor::getPort(const std::string &if_name, PortID idx)
77 {
78 if (if_name == "mem_side_port") {
79 return memSidePort;
80 } else if (if_name == "cpu_side_port") {
81 return cpuSidePort;
82 } else {
83 return SimObject::getPort(if_name, idx);
84 }
85 }
86
87 void
88 CommMonitor::recvFunctional(PacketPtr pkt)
89 {
90 memSidePort.sendFunctional(pkt);
91 }
92
93 void
94 CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
95 {
96 cpuSidePort.sendFunctionalSnoop(pkt);
97 }
98
99 CommMonitor::MonitorStats::MonitorStats(Stats::Group *parent,
100 const CommMonitorParams &params)
101 : Stats::Group(parent),
102
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"),
108
109 disableBandwidthHists(params.disable_bandwidth_hists),
110 readBytes(0),
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),
116
117 writtenBytes(0),
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),
122
123 disableLatencyHists(params.disable_latency_hists),
124 ADD_STAT(readLatencyHist, "Read request-response latency"),
125 ADD_STAT(writeLatencyHist, "Write request-response latency"),
126
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),
132
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),
138
139 disableTransactionHists(params.disable_transaction_hists),
140 ADD_STAT(readTransHist,
141 "Histogram of read transactions per sample period"),
142 readTrans(0),
143 ADD_STAT(writeTransHist,
144 "Histogram of write transactions per sample period"),
145 writeTrans(0),
146
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")
152 {
153 using namespace Stats;
154
155 readBurstLengthHist
156 .init(params.burst_length_bins)
157 .flags(disableBurstLengthHists ? nozero : pdf);
158
159 writeBurstLengthHist
160 .init(params.burst_length_bins)
161 .flags(disableBurstLengthHists ? nozero : pdf);
162
163 // Stats based on received responses
164 readBandwidthHist
165 .init(params.bandwidth_bins)
166 .flags(disableBandwidthHists ? nozero : pdf);
167
168 averageReadBandwidth
169 .flags(disableBandwidthHists ? nozero : pdf);
170
171 totalReadBytes
172 .flags(disableBandwidthHists ? nozero : pdf);
173
174 // Stats based on successfully sent requests
175 writeBandwidthHist
176 .init(params.bandwidth_bins)
177 .flags(disableBandwidthHists ? (pdf | nozero) : pdf);
178
179 averageWriteBandwidth
180 .flags(disableBandwidthHists ? nozero : pdf);
181
182 totalWrittenBytes
183 .flags(disableBandwidthHists ? nozero : pdf);
184
185
186 readLatencyHist
187 .init(params.latency_bins)
188 .flags(disableLatencyHists ? nozero : pdf);
189
190 writeLatencyHist
191 .init(params.latency_bins)
192 .flags(disableLatencyHists ? nozero : pdf);
193
194 ittReadRead
195 .init(1, params.itt_max_bin, params.itt_max_bin /
196 params.itt_bins)
197 .flags(disableITTDists ? nozero : pdf);
198
199 ittWriteWrite
200 .init(1, params.itt_max_bin, params.itt_max_bin /
201 params.itt_bins)
202 .flags(disableITTDists ? nozero : pdf);
203
204 ittReqReq
205 .init(1, params.itt_max_bin, params.itt_max_bin /
206 params.itt_bins)
207 .flags(disableITTDists ? nozero : pdf);
208
209 outstandingReadsHist
210 .init(params.outstanding_bins)
211 .flags(disableOutstandingHists ? nozero : pdf);
212
213 outstandingWritesHist
214 .init(params.outstanding_bins)
215 .flags(disableOutstandingHists ? nozero : pdf);
216
217 readTransHist
218 .init(params.transaction_bins)
219 .flags(disableTransactionHists ? nozero : pdf);
220
221 writeTransHist
222 .init(params.transaction_bins)
223 .flags(disableTransactionHists ? nozero : pdf);
224
225 readAddrDist
226 .init(0)
227 .flags(disableAddrDists ? nozero : pdf);
228
229 writeAddrDist
230 .init(0)
231 .flags(disableAddrDists ? nozero : pdf);
232 }
233
234 void
235 CommMonitor::MonitorStats::updateReqStats(
236 const ProbePoints::PacketInfo& pkt_info, bool is_atomic,
237 bool expects_response)
238 {
239 if (pkt_info.cmd.isRead()) {
240 // Increment number of observed read transactions
241 if (!disableTransactionHists)
242 ++readTrans;
243
244 // Get sample of burst length
245 if (!disableBurstLengthHists)
246 readBurstLengthHist.sample(pkt_info.size);
247
248 // Sample the masked address
249 if (!disableAddrDists)
250 readAddrDist.sample(pkt_info.addr & readAddrMask);
251
252 if (!disableITTDists) {
253 // Sample value of read-read inter transaction time
254 if (timeOfLastRead != 0)
255 ittReadRead.sample(curTick() - timeOfLastRead);
256 timeOfLastRead = curTick();
257
258 // Sample value of req-req inter transaction time
259 if (timeOfLastReq != 0)
260 ittReqReq.sample(curTick() - timeOfLastReq);
261 timeOfLastReq = curTick();
262 }
263 if (!is_atomic && !disableOutstandingHists && expects_response)
264 ++outstandingReadReqs;
265
266 } else if (pkt_info.cmd.isWrite()) {
267 // Same as for reads
268 if (!disableTransactionHists)
269 ++writeTrans;
270
271 if (!disableBurstLengthHists)
272 writeBurstLengthHist.sample(pkt_info.size);
273
274 // Update the bandwidth stats on the request
275 if (!disableBandwidthHists) {
276 writtenBytes += pkt_info.size;
277 totalWrittenBytes += pkt_info.size;
278 }
279
280 // Sample the masked write address
281 if (!disableAddrDists)
282 writeAddrDist.sample(pkt_info.addr & writeAddrMask);
283
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();
289
290 // Sample value of req-to-req inter transaction time
291 if (timeOfLastReq != 0)
292 ittReqReq.sample(curTick() - timeOfLastReq);
293 timeOfLastReq = curTick();
294 }
295
296 if (!is_atomic && !disableOutstandingHists && expects_response)
297 ++outstandingWriteReqs;
298 }
299 }
300
301 void
302 CommMonitor::MonitorStats::updateRespStats(
303 const ProbePoints::PacketInfo& pkt_info, Tick latency, bool is_atomic)
304 {
305 if (pkt_info.cmd.isRead()) {
306 // Decrement number of outstanding read requests
307 if (!is_atomic && !disableOutstandingHists) {
308 assert(outstandingReadReqs != 0);
309 --outstandingReadReqs;
310 }
311
312 if (!disableLatencyHists)
313 readLatencyHist.sample(latency);
314
315 // Update the bandwidth stats based on responses for reads
316 if (!disableBandwidthHists) {
317 readBytes += pkt_info.size;
318 totalReadBytes += pkt_info.size;
319 }
320
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;
326 }
327
328 if (!disableLatencyHists)
329 writeLatencyHist.sample(latency);
330 }
331 }
332
333 Tick
334 CommMonitor::recvAtomic(PacketPtr pkt)
335 {
336 const bool expects_response(pkt->needsResponse() &&
337 !pkt->cacheResponding());
338 ProbePoints::PacketInfo req_pkt_info(pkt);
339 ppPktReq->notify(req_pkt_info);
340
341 const Tick delay(memSidePort.sendAtomic(pkt));
342
343 stats.updateReqStats(req_pkt_info, true, expects_response);
344 if (expects_response)
345 stats.updateRespStats(req_pkt_info, delay, true);
346
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);
351 return delay;
352 }
353
354 Tick
355 CommMonitor::recvAtomicSnoop(PacketPtr pkt)
356 {
357 return cpuSidePort.sendAtomicSnoop(pkt);
358 }
359
360 bool
361 CommMonitor::recvTimingReq(PacketPtr pkt)
362 {
363 // should always see a request
364 assert(pkt->isRequest());
365
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);
369
370 const bool expects_response(pkt->needsResponse() &&
371 !pkt->cacheResponding());
372
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()));
379 }
380
381 // Attempt to send the packet
382 bool successful = memSidePort.sendTimingReq(pkt);
383
384 // If not successful, restore the sender state
385 if (!successful && expects_response && !stats.disableLatencyHists) {
386 delete pkt->popSenderState();
387 }
388
389 if (successful) {
390 ppPktReq->notify(pkt_info);
391 }
392
393 if (successful) {
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);
397 }
398 return successful;
399 }
400
401 bool
402 CommMonitor::recvTimingResp(PacketPtr pkt)
403 {
404 // should always see responses
405 assert(pkt->isResponse());
406
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);
410
411 Tick latency = 0;
412 CommMonitorSenderState* received_state =
413 dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
414
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");
419
420 // Restore the sate
421 pkt->senderState = received_state->predecessor;
422 }
423
424 // Attempt to send the packet
425 bool successful = cpuSidePort.sendTimingResp(pkt);
426
427 if (!stats.disableLatencyHists) {
428 // If packet successfully send, sample value of latency,
429 // afterwards delete sender state, otherwise restore state
430 if (successful) {
431 latency = curTick() - received_state->transmitTime;
432 DPRINTF(CommMonitor, "Latency: %d\n", latency);
433 delete received_state;
434 } else {
435 // Don't delete anything and let the packet look like we
436 // did not touch it
437 pkt->senderState = received_state;
438 }
439 }
440
441 if (successful) {
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);
446 }
447 return successful;
448 }
449
450 void
451 CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
452 {
453 cpuSidePort.sendTimingSnoopReq(pkt);
454 }
455
456 bool
457 CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
458 {
459 return memSidePort.sendTimingSnoopResp(pkt);
460 }
461
462 void
463 CommMonitor::recvRetrySnoopResp()
464 {
465 cpuSidePort.sendRetrySnoopResp();
466 }
467
468 bool
469 CommMonitor::isSnooping() const
470 {
471 // check if the connected request port is snooping
472 return cpuSidePort.isSnooping();
473 }
474
475 AddrRangeList
476 CommMonitor::getAddrRanges() const
477 {
478 // get the address ranges of the connected CPU-side port
479 return memSidePort.getAddrRanges();
480 }
481
482 void
483 CommMonitor::recvReqRetry()
484 {
485 cpuSidePort.sendRetryReq();
486 }
487
488 void
489 CommMonitor::recvRespRetry()
490 {
491 memSidePort.sendRetryResp();
492 }
493
494 bool
495 CommMonitor::tryTiming(PacketPtr pkt)
496 {
497 return memSidePort.tryTiming(pkt);
498 }
499
500 void
501 CommMonitor::recvRangeChange()
502 {
503 cpuSidePort.sendRangeChange();
504 }
505
506 void
507 CommMonitor::samplePeriodic()
508 {
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
513 // period
514
515 // only capture if we have not reset the stats during the last
516 // sample period
517 if (simTicks.value() >= samplePeriodTicks) {
518 if (!stats.disableTransactionHists) {
519 stats.readTransHist.sample(stats.readTrans);
520 stats.writeTransHist.sample(stats.writeTrans);
521 }
522
523 if (!stats.disableBandwidthHists) {
524 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
525 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
526 }
527
528 if (!stats.disableOutstandingHists) {
529 stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
530 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
531 }
532 }
533
534 // reset the sampled values
535 stats.readTrans = 0;
536 stats.writeTrans = 0;
537
538 stats.readBytes = 0;
539 stats.writtenBytes = 0;
540
541 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
542 }
543
544 void
545 CommMonitor::startup()
546 {
547 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
548 }