Port: Add isSnooping to slave port (asking master port)
[gem5.git] / src / mem / comm_monitor.cc
1 /*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
24 *
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 *
37 * Authors: Thomas Grass
38 * Andreas Hansson
39 */
40
41 #include "debug/CommMonitor.hh"
42 #include "mem/comm_monitor.hh"
43 #include "sim/stats.hh"
44
45 CommMonitor::CommMonitor(Params* params)
46 : MemObject(params),
47 masterPort(name() + "-master", *this),
48 slavePort(name() + "-slave", *this),
49 samplePeriodicEvent(this),
50 samplePeriodTicks(params->sample_period),
51 readAddrMask(params->read_addr_mask),
52 writeAddrMask(params->write_addr_mask),
53 stats(params)
54 {
55 // keep track of the sample period both in ticks and absolute time
56 samplePeriod.setTick(params->sample_period);
57
58 DPRINTF(CommMonitor,
59 "Created monitor %s with sample period %d ticks (%f s)\n",
60 name(), samplePeriodTicks, samplePeriod);
61 }
62
63 CommMonitor*
64 CommMonitorParams::create()
65 {
66 return new CommMonitor(this);
67 }
68
69 void
70 CommMonitor::init()
71 {
72 // make sure both sides of the monitor are connected
73 if (!slavePort.isConnected() || !masterPort.isConnected())
74 fatal("Communication monitor is not connected on both sides.\n");
75 }
76
77 MasterPort&
78 CommMonitor::getMasterPort(const std::string& if_name, int idx)
79 {
80 if (if_name == "master") {
81 return masterPort;
82 } else {
83 return MemObject::getMasterPort(if_name, idx);
84 }
85 }
86
87 SlavePort&
88 CommMonitor::getSlavePort(const std::string& if_name, int idx)
89 {
90 if (if_name == "slave") {
91 return slavePort;
92 } else {
93 return MemObject::getSlavePort(if_name, idx);
94 }
95 }
96
97 void
98 CommMonitor::recvFunctional(PacketPtr pkt)
99 {
100 masterPort.sendFunctional(pkt);
101 }
102
103 void
104 CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
105 {
106 slavePort.sendFunctionalSnoop(pkt);
107 }
108
109 Tick
110 CommMonitor::recvAtomic(PacketPtr pkt)
111 {
112 return masterPort.sendAtomic(pkt);
113 }
114
115 Tick
116 CommMonitor::recvAtomicSnoop(PacketPtr pkt)
117 {
118 return slavePort.sendAtomicSnoop(pkt);
119 }
120
121 bool
122 CommMonitor::recvTimingReq(PacketPtr pkt)
123 {
124 // should always see a request
125 assert(pkt->isRequest());
126
127 // Store relevant fields of packet, because packet may be modified
128 // or even deleted when sendTiming() is called.
129 bool isRead = pkt->isRead();
130 bool isWrite = pkt->isWrite();
131 unsigned size = pkt->getSize();
132 Addr addr = pkt->getAddr();
133 bool needsResponse = pkt->needsResponse();
134 bool memInhibitAsserted = pkt->memInhibitAsserted();
135 Packet::SenderState* senderState = pkt->senderState;
136
137 // If a cache miss is served by a cache, a monitor near the memory
138 // would see a request which needs a response, but this response
139 // would be inhibited and not come back from the memory. Therefore
140 // we additionally have to check the inhibit flag.
141 if (needsResponse && !memInhibitAsserted && !stats.disableLatencyHists) {
142 pkt->senderState = new CommMonitorSenderState(senderState,
143 curTick());
144 }
145
146 // Attempt to send the packet (always succeeds for inhibited
147 // packets)
148 bool successful = masterPort.sendTimingReq(pkt);
149
150 // If not successful, restore the sender state
151 if (!successful && needsResponse && !stats.disableLatencyHists) {
152 delete pkt->senderState;
153 pkt->senderState = senderState;
154 }
155
156 if (successful && isRead) {
157 DPRINTF(CommMonitor, "Forwarded read request\n");
158
159 // Increment number of observed read transactions
160 if (!stats.disableTransactionHists) {
161 ++stats.readTrans;
162 }
163
164 // Get sample of burst length
165 if (!stats.disableBurstLengthHists) {
166 stats.readBurstLengthHist.sample(size);
167 }
168
169 // Sample the masked address
170 if (!stats.disableAddrDists) {
171 stats.readAddrDist.sample(addr & readAddrMask);
172 }
173
174 // If it needs a response increment number of outstanding read
175 // requests
176 if (!stats.disableOutstandingHists && needsResponse) {
177 ++stats.outstandingReadReqs;
178 }
179
180 if (!stats.disableITTDists) {
181 // Sample value of read-read inter transaction time
182 if (stats.timeOfLastRead != 0) {
183 stats.ittReadRead.sample(curTick() - stats.timeOfLastRead);
184 }
185 stats.timeOfLastRead = curTick();
186
187 // Sample value of req-req inter transaction time
188 if (stats.timeOfLastReq != 0) {
189 stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
190 }
191 stats.timeOfLastReq = curTick();
192 }
193 } else if (successful && isWrite) {
194 DPRINTF(CommMonitor, "Forwarded write request\n");
195
196 // Same as for reads
197 if (!stats.disableTransactionHists) {
198 ++stats.writeTrans;
199 }
200
201 if (!stats.disableBurstLengthHists) {
202 stats.writeBurstLengthHist.sample(size);
203 }
204
205 // Update the bandwidth stats on the request
206 if (!stats.disableBandwidthHists) {
207 stats.writtenBytes += size;
208 stats.totalWrittenBytes += size;
209 }
210
211 // Sample the masked write address
212 if (!stats.disableAddrDists) {
213 stats.writeAddrDist.sample(addr & writeAddrMask);
214 }
215
216 if (!stats.disableOutstandingHists && needsResponse) {
217 ++stats.outstandingWriteReqs;
218 }
219
220 if (!stats.disableITTDists) {
221 // Sample value of write-to-write inter transaction time
222 if (stats.timeOfLastWrite != 0) {
223 stats.ittWriteWrite.sample(curTick() - stats.timeOfLastWrite);
224 }
225 stats.timeOfLastWrite = curTick();
226
227 // Sample value of req-to-req inter transaction time
228 if (stats.timeOfLastReq != 0) {
229 stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
230 }
231 stats.timeOfLastReq = curTick();
232 }
233 } else if (successful) {
234 DPRINTF(CommMonitor, "Forwarded non read/write request\n");
235 }
236
237 return successful;
238 }
239
240 bool
241 CommMonitor::recvTimingResp(PacketPtr pkt)
242 {
243 // should always see responses
244 assert(pkt->isResponse());
245
246 // Store relevant fields of packet, because packet may be modified
247 // or even deleted when sendTiming() is called.
248 bool isRead = pkt->isRead();
249 bool isWrite = pkt->isWrite();
250 unsigned size = pkt->getSize();
251 Tick latency = 0;
252 CommMonitorSenderState* commReceivedState =
253 dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
254
255 if (!stats.disableLatencyHists) {
256 // Restore initial sender state
257 if (commReceivedState == NULL)
258 panic("Monitor got a response without monitor sender state\n");
259
260 // Restore the sate
261 pkt->senderState = commReceivedState->origSenderState;
262 }
263
264 // Attempt to send the packet
265 bool successful = slavePort.sendTimingResp(pkt);
266
267 if (!stats.disableLatencyHists) {
268 // If packet successfully send, sample value of latency,
269 // afterwards delete sender state, otherwise restore state
270 if (successful) {
271 latency = curTick() - commReceivedState->transmitTime;
272 DPRINTF(CommMonitor, "Latency: %d\n", latency);
273 delete commReceivedState;
274 } else {
275 // Don't delete anything and let the packet look like we
276 // did not touch it
277 pkt->senderState = commReceivedState;
278 }
279 }
280
281 if (successful && isRead) {
282 // Decrement number of outstanding read requests
283 DPRINTF(CommMonitor, "Received read response\n");
284 if (!stats.disableOutstandingHists) {
285 assert(stats.outstandingReadReqs != 0);
286 --stats.outstandingReadReqs;
287 }
288
289 if (!stats.disableLatencyHists) {
290 stats.readLatencyHist.sample(latency);
291 }
292
293 // Update the bandwidth stats based on responses for reads
294 if (!stats.disableBandwidthHists) {
295 stats.readBytes += size;
296 stats.totalReadBytes += size;
297 }
298
299 } else if (successful && isWrite) {
300 // Decrement number of outstanding write requests
301 DPRINTF(CommMonitor, "Received write response\n");
302 if (!stats.disableOutstandingHists) {
303 assert(stats.outstandingWriteReqs != 0);
304 --stats.outstandingWriteReqs;
305 }
306
307 if (!stats.disableLatencyHists) {
308 stats.writeLatencyHist.sample(latency);
309 }
310 } else if (successful) {
311 DPRINTF(CommMonitor, "Received non read/write response\n");
312 }
313 return successful;
314 }
315
316 void
317 CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
318 {
319 slavePort.sendTimingSnoopReq(pkt);
320 }
321
322 bool
323 CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
324 {
325 return masterPort.sendTimingSnoopResp(pkt);
326 }
327
328 bool
329 CommMonitor::isSnooping() const
330 {
331 // check if the connected master port is snooping
332 return slavePort.isSnooping();
333 }
334
335 unsigned
336 CommMonitor::deviceBlockSizeMaster()
337 {
338 return slavePort.peerBlockSize();
339 }
340
341 unsigned
342 CommMonitor::deviceBlockSizeSlave()
343 {
344 return masterPort.peerBlockSize();
345 }
346
347 AddrRangeList
348 CommMonitor::getAddrRanges()
349 {
350 return masterPort.getSlavePort().getAddrRanges();
351 }
352
353 void
354 CommMonitor::recvRetryMaster()
355 {
356 slavePort.sendRetry();
357 }
358
359 void
360 CommMonitor::recvRetrySlave()
361 {
362 masterPort.sendRetry();
363 }
364
365 void
366 CommMonitor::recvRangeChange()
367 {
368 slavePort.sendRangeChange();
369 }
370
371 void
372 CommMonitor::regStats()
373 {
374 // Initialise all the monitor stats
375 using namespace Stats;
376
377 stats.readBurstLengthHist
378 .init(params()->burst_length_bins)
379 .name(name() + ".readBurstLengthHist")
380 .desc("Histogram of burst lengths of transmitted packets")
381 .flags(stats.disableBurstLengthHists ? nozero : pdf);
382
383 stats.writeBurstLengthHist
384 .init(params()->burst_length_bins)
385 .name(name() + ".writeBurstLengthHist")
386 .desc("Histogram of burst lengths of transmitted packets")
387 .flags(stats.disableBurstLengthHists ? nozero : pdf);
388
389 // Stats based on received responses
390 stats.readBandwidthHist
391 .init(params()->bandwidth_bins)
392 .name(name() + ".readBandwidthHist")
393 .desc("Histogram of read bandwidth per sample period (bytes/s)")
394 .flags(stats.disableBandwidthHists ? nozero : pdf);
395
396 stats.averageReadBW
397 .name(name() + ".averageReadBandwidth")
398 .desc("Average read bandwidth (bytes/s)")
399 .flags(stats.disableBandwidthHists ? nozero : pdf);
400
401 stats.totalReadBytes
402 .name(name() + ".totalReadBytes")
403 .desc("Number of bytes read")
404 .flags(stats.disableBandwidthHists ? nozero : pdf);
405
406 stats.averageReadBW = stats.totalReadBytes / simSeconds;
407
408 // Stats based on successfully sent requests
409 stats.writeBandwidthHist
410 .init(params()->bandwidth_bins)
411 .name(name() + ".writeBandwidthHist")
412 .desc("Histogram of write bandwidth (bytes/s)")
413 .flags(stats.disableBandwidthHists ? (pdf | nozero) : pdf);
414
415 stats.averageWriteBW
416 .name(name() + ".averageWriteBandwidth")
417 .desc("Average write bandwidth (bytes/s)")
418 .flags(stats.disableBandwidthHists ? nozero : pdf);
419
420 stats.totalWrittenBytes
421 .name(name() + ".totalWrittenBytes")
422 .desc("Number of bytes written")
423 .flags(stats.disableBandwidthHists ? nozero : pdf);
424
425 stats.averageWriteBW = stats.totalWrittenBytes / simSeconds;
426
427 stats.readLatencyHist
428 .init(params()->latency_bins)
429 .name(name() + ".readLatencyHist")
430 .desc("Read request-response latency")
431 .flags(stats.disableLatencyHists ? nozero : pdf);
432
433 stats.writeLatencyHist
434 .init(params()->latency_bins)
435 .name(name() + ".writeLatencyHist")
436 .desc("Write request-response latency")
437 .flags(stats.disableLatencyHists ? nozero : pdf);
438
439 stats.ittReadRead
440 .init(1, params()->itt_max_bin, params()->itt_max_bin /
441 params()->itt_bins)
442 .name(name() + ".ittReadRead")
443 .desc("Read-to-read inter transaction time")
444 .flags(stats.disableITTDists ? nozero : pdf);
445
446 stats.ittWriteWrite
447 .init(1, params()->itt_max_bin, params()->itt_max_bin /
448 params()->itt_bins)
449 .name(name() + ".ittWriteWrite")
450 .desc("Write-to-write inter transaction time")
451 .flags(stats.disableITTDists ? nozero : pdf);
452
453 stats.ittReqReq
454 .init(1, params()->itt_max_bin, params()->itt_max_bin /
455 params()->itt_bins)
456 .name(name() + ".ittReqReq")
457 .desc("Request-to-request inter transaction time")
458 .flags(stats.disableITTDists ? nozero : pdf);
459
460 stats.outstandingReadsHist
461 .init(params()->outstanding_bins)
462 .name(name() + ".outstandingReadsHist")
463 .desc("Outstanding read transactions")
464 .flags(stats.disableOutstandingHists ? nozero : pdf);
465
466 stats.outstandingWritesHist
467 .init(params()->outstanding_bins)
468 .name(name() + ".outstandingWritesHist")
469 .desc("Outstanding write transactions")
470 .flags(stats.disableOutstandingHists ? nozero : pdf);
471
472 stats.readTransHist
473 .init(params()->transaction_bins)
474 .name(name() + ".readTransHist")
475 .desc("Histogram of read transactions per sample period")
476 .flags(stats.disableTransactionHists ? nozero : pdf);
477
478 stats.writeTransHist
479 .init(params()->transaction_bins)
480 .name(name() + ".writeTransHist")
481 .desc("Histogram of read transactions per sample period")
482 .flags(stats.disableTransactionHists ? nozero : pdf);
483
484 stats.readAddrDist
485 .init(0)
486 .name(name() + ".readAddrDist")
487 .desc("Read address distribution")
488 .flags(stats.disableAddrDists ? nozero : pdf);
489
490 stats.writeAddrDist
491 .init(0)
492 .name(name() + ".writeAddrDist")
493 .desc("Write address distribution")
494 .flags(stats.disableAddrDists ? nozero : pdf);
495 }
496
497 void
498 CommMonitor::samplePeriodic()
499 {
500 // the periodic stats update runs on the granularity of sample
501 // periods, but in combination with this there may also be a
502 // external resets and dumps of the stats (through schedStatEvent)
503 // causing the stats themselves to capture less than a sample
504 // period
505
506 // only capture if we have not reset the stats during the last
507 // sample period
508 if (simTicks.value() >= samplePeriodTicks) {
509 if (!stats.disableTransactionHists) {
510 stats.readTransHist.sample(stats.readTrans);
511 stats.writeTransHist.sample(stats.writeTrans);
512 }
513
514 if (!stats.disableBandwidthHists) {
515 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
516 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
517 }
518
519 if (!stats.disableOutstandingHists) {
520 stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
521 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
522 }
523 }
524
525 // reset the sampled values
526 stats.readTrans = 0;
527 stats.writeTrans = 0;
528
529 stats.readBytes = 0;
530 stats.writtenBytes = 0;
531
532 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
533 }
534
535 void
536 CommMonitor::startup()
537 {
538 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
539 }