beb7fe32c08eb3c5f681eeb273f2d07edbc638e6
[gem5.git] / src / mem / comm_monitor.cc
1 /*
2 * Copyright (c) 2012-2013, 2015 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 "base/trace.hh"
42 #include "debug/CommMonitor.hh"
43 #include "mem/comm_monitor.hh"
44 #include "sim/stats.hh"
45
46 CommMonitor::CommMonitor(Params* params)
47 : MemObject(params),
48 masterPort(name() + "-master", *this),
49 slavePort(name() + "-slave", *this),
50 samplePeriodicEvent(this),
51 samplePeriodTicks(params->sample_period),
52 samplePeriod(params->sample_period / SimClock::Float::s),
53 readAddrMask(params->read_addr_mask),
54 writeAddrMask(params->write_addr_mask),
55 stats(params)
56 {
57 DPRINTF(CommMonitor,
58 "Created monitor %s with sample period %d ticks (%f ms)\n",
59 name(), samplePeriodTicks, samplePeriod * 1E3);
60 }
61
62 CommMonitor*
63 CommMonitorParams::create()
64 {
65 return new CommMonitor(this);
66 }
67
68 void
69 CommMonitor::init()
70 {
71 // make sure both sides of the monitor are connected
72 if (!slavePort.isConnected() || !masterPort.isConnected())
73 fatal("Communication monitor is not connected on both sides.\n");
74 }
75
76 void
77 CommMonitor::regProbePoints()
78 {
79 ppPktReq.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
80 ppPktResp.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
81 }
82
83 BaseMasterPort&
84 CommMonitor::getMasterPort(const std::string& if_name, PortID idx)
85 {
86 if (if_name == "master") {
87 return masterPort;
88 } else {
89 return MemObject::getMasterPort(if_name, idx);
90 }
91 }
92
93 BaseSlavePort&
94 CommMonitor::getSlavePort(const std::string& if_name, PortID idx)
95 {
96 if (if_name == "slave") {
97 return slavePort;
98 } else {
99 return MemObject::getSlavePort(if_name, idx);
100 }
101 }
102
103 void
104 CommMonitor::recvFunctional(PacketPtr pkt)
105 {
106 masterPort.sendFunctional(pkt);
107 }
108
109 void
110 CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
111 {
112 slavePort.sendFunctionalSnoop(pkt);
113 }
114
115 Tick
116 CommMonitor::recvAtomic(PacketPtr pkt)
117 {
118 ppPktReq->notify(pkt);
119
120 const Tick delay(masterPort.sendAtomic(pkt));
121 assert(pkt->isResponse());
122 ppPktResp->notify(pkt);
123 return delay;
124 }
125
126 Tick
127 CommMonitor::recvAtomicSnoop(PacketPtr pkt)
128 {
129 return slavePort.sendAtomicSnoop(pkt);
130 }
131
132 bool
133 CommMonitor::recvTimingReq(PacketPtr pkt)
134 {
135 // should always see a request
136 assert(pkt->isRequest());
137
138 // Store relevant fields of packet, because packet may be modified
139 // or even deleted when sendTiming() is called.
140 const bool is_read = pkt->isRead();
141 const bool is_write = pkt->isWrite();
142 const MemCmd cmd = pkt->cmd;
143 const unsigned size = pkt->getSize();
144 const Addr addr = pkt->getAddr();
145 const bool expects_response(
146 pkt->needsResponse() && !pkt->memInhibitAsserted());
147
148 // If a cache miss is served by a cache, a monitor near the memory
149 // would see a request which needs a response, but this response
150 // would be inhibited and not come back from the memory. Therefore
151 // we additionally have to check the inhibit flag.
152 if (expects_response && !stats.disableLatencyHists) {
153 pkt->pushSenderState(new CommMonitorSenderState(curTick()));
154 }
155
156 // Attempt to send the packet (always succeeds for inhibited
157 // packets)
158 bool successful = masterPort.sendTimingReq(pkt);
159
160 // If not successful, restore the sender state
161 if (!successful && expects_response && !stats.disableLatencyHists) {
162 delete pkt->popSenderState();
163 }
164
165 if (successful) {
166 // The receiver might already have modified the packet. We
167 // want to give the probe access to the original packet, which
168 // means we need to fake the original packet by temporarily
169 // restoring the command.
170 const MemCmd response_cmd(pkt->cmd);
171 pkt->cmd = cmd;
172 ppPktReq->notify(pkt);
173 pkt->cmd = response_cmd;
174 }
175
176 if (successful && is_read) {
177 DPRINTF(CommMonitor, "Forwarded read request\n");
178
179 // Increment number of observed read transactions
180 if (!stats.disableTransactionHists) {
181 ++stats.readTrans;
182 }
183
184 // Get sample of burst length
185 if (!stats.disableBurstLengthHists) {
186 stats.readBurstLengthHist.sample(size);
187 }
188
189 // Sample the masked address
190 if (!stats.disableAddrDists) {
191 stats.readAddrDist.sample(addr & readAddrMask);
192 }
193
194 // If it needs a response increment number of outstanding read
195 // requests
196 if (!stats.disableOutstandingHists && expects_response) {
197 ++stats.outstandingReadReqs;
198 }
199
200 if (!stats.disableITTDists) {
201 // Sample value of read-read inter transaction time
202 if (stats.timeOfLastRead != 0) {
203 stats.ittReadRead.sample(curTick() - stats.timeOfLastRead);
204 }
205 stats.timeOfLastRead = curTick();
206
207 // Sample value of req-req inter transaction time
208 if (stats.timeOfLastReq != 0) {
209 stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
210 }
211 stats.timeOfLastReq = curTick();
212 }
213 } else if (successful && is_write) {
214 DPRINTF(CommMonitor, "Forwarded write request\n");
215
216 // Same as for reads
217 if (!stats.disableTransactionHists) {
218 ++stats.writeTrans;
219 }
220
221 if (!stats.disableBurstLengthHists) {
222 stats.writeBurstLengthHist.sample(size);
223 }
224
225 // Update the bandwidth stats on the request
226 if (!stats.disableBandwidthHists) {
227 stats.writtenBytes += size;
228 stats.totalWrittenBytes += size;
229 }
230
231 // Sample the masked write address
232 if (!stats.disableAddrDists) {
233 stats.writeAddrDist.sample(addr & writeAddrMask);
234 }
235
236 if (!stats.disableOutstandingHists && expects_response) {
237 ++stats.outstandingWriteReqs;
238 }
239
240 if (!stats.disableITTDists) {
241 // Sample value of write-to-write inter transaction time
242 if (stats.timeOfLastWrite != 0) {
243 stats.ittWriteWrite.sample(curTick() - stats.timeOfLastWrite);
244 }
245 stats.timeOfLastWrite = curTick();
246
247 // Sample value of req-to-req inter transaction time
248 if (stats.timeOfLastReq != 0) {
249 stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
250 }
251 stats.timeOfLastReq = curTick();
252 }
253 } else if (successful) {
254 DPRINTF(CommMonitor, "Forwarded non read/write request\n");
255 }
256
257 return successful;
258 }
259
260 bool
261 CommMonitor::recvTimingResp(PacketPtr pkt)
262 {
263 // should always see responses
264 assert(pkt->isResponse());
265
266 // Store relevant fields of packet, because packet may be modified
267 // or even deleted when sendTiming() is called.
268 bool is_read = pkt->isRead();
269 bool is_write = pkt->isWrite();
270 unsigned size = pkt->getSize();
271 Tick latency = 0;
272 CommMonitorSenderState* received_state =
273 dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
274
275 if (!stats.disableLatencyHists) {
276 // Restore initial sender state
277 if (received_state == NULL)
278 panic("Monitor got a response without monitor sender state\n");
279
280 // Restore the sate
281 pkt->senderState = received_state->predecessor;
282 }
283
284 // Attempt to send the packet
285 bool successful = slavePort.sendTimingResp(pkt);
286
287 if (!stats.disableLatencyHists) {
288 // If packet successfully send, sample value of latency,
289 // afterwards delete sender state, otherwise restore state
290 if (successful) {
291 latency = curTick() - received_state->transmitTime;
292 DPRINTF(CommMonitor, "Latency: %d\n", latency);
293 delete received_state;
294 } else {
295 // Don't delete anything and let the packet look like we
296 // did not touch it
297 pkt->senderState = received_state;
298 }
299 }
300
301 if (successful) {
302 assert(pkt->isResponse());
303 ppPktResp->notify(pkt);
304 }
305
306 if (successful && is_read) {
307 // Decrement number of outstanding read requests
308 DPRINTF(CommMonitor, "Received read response\n");
309 if (!stats.disableOutstandingHists) {
310 assert(stats.outstandingReadReqs != 0);
311 --stats.outstandingReadReqs;
312 }
313
314 if (!stats.disableLatencyHists) {
315 stats.readLatencyHist.sample(latency);
316 }
317
318 // Update the bandwidth stats based on responses for reads
319 if (!stats.disableBandwidthHists) {
320 stats.readBytes += size;
321 stats.totalReadBytes += size;
322 }
323
324 } else if (successful && is_write) {
325 // Decrement number of outstanding write requests
326 DPRINTF(CommMonitor, "Received write response\n");
327 if (!stats.disableOutstandingHists) {
328 assert(stats.outstandingWriteReqs != 0);
329 --stats.outstandingWriteReqs;
330 }
331
332 if (!stats.disableLatencyHists) {
333 stats.writeLatencyHist.sample(latency);
334 }
335 } else if (successful) {
336 DPRINTF(CommMonitor, "Received non read/write response\n");
337 }
338 return successful;
339 }
340
341 void
342 CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
343 {
344 slavePort.sendTimingSnoopReq(pkt);
345 }
346
347 bool
348 CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
349 {
350 return masterPort.sendTimingSnoopResp(pkt);
351 }
352
353 bool
354 CommMonitor::isSnooping() const
355 {
356 // check if the connected master port is snooping
357 return slavePort.isSnooping();
358 }
359
360 AddrRangeList
361 CommMonitor::getAddrRanges() const
362 {
363 // get the address ranges of the connected slave port
364 return masterPort.getAddrRanges();
365 }
366
367 void
368 CommMonitor::recvReqRetry()
369 {
370 slavePort.sendRetryReq();
371 }
372
373 void
374 CommMonitor::recvRespRetry()
375 {
376 masterPort.sendRetryResp();
377 }
378
379 void
380 CommMonitor::recvRangeChange()
381 {
382 slavePort.sendRangeChange();
383 }
384
385 void
386 CommMonitor::regStats()
387 {
388 // Initialise all the monitor stats
389 using namespace Stats;
390
391 stats.readBurstLengthHist
392 .init(params()->burst_length_bins)
393 .name(name() + ".readBurstLengthHist")
394 .desc("Histogram of burst lengths of transmitted packets")
395 .flags(stats.disableBurstLengthHists ? nozero : pdf);
396
397 stats.writeBurstLengthHist
398 .init(params()->burst_length_bins)
399 .name(name() + ".writeBurstLengthHist")
400 .desc("Histogram of burst lengths of transmitted packets")
401 .flags(stats.disableBurstLengthHists ? nozero : pdf);
402
403 // Stats based on received responses
404 stats.readBandwidthHist
405 .init(params()->bandwidth_bins)
406 .name(name() + ".readBandwidthHist")
407 .desc("Histogram of read bandwidth per sample period (bytes/s)")
408 .flags(stats.disableBandwidthHists ? nozero : pdf);
409
410 stats.averageReadBW
411 .name(name() + ".averageReadBandwidth")
412 .desc("Average read bandwidth (bytes/s)")
413 .flags(stats.disableBandwidthHists ? nozero : pdf);
414
415 stats.totalReadBytes
416 .name(name() + ".totalReadBytes")
417 .desc("Number of bytes read")
418 .flags(stats.disableBandwidthHists ? nozero : pdf);
419
420 stats.averageReadBW = stats.totalReadBytes / simSeconds;
421
422 // Stats based on successfully sent requests
423 stats.writeBandwidthHist
424 .init(params()->bandwidth_bins)
425 .name(name() + ".writeBandwidthHist")
426 .desc("Histogram of write bandwidth (bytes/s)")
427 .flags(stats.disableBandwidthHists ? (pdf | nozero) : pdf);
428
429 stats.averageWriteBW
430 .name(name() + ".averageWriteBandwidth")
431 .desc("Average write bandwidth (bytes/s)")
432 .flags(stats.disableBandwidthHists ? nozero : pdf);
433
434 stats.totalWrittenBytes
435 .name(name() + ".totalWrittenBytes")
436 .desc("Number of bytes written")
437 .flags(stats.disableBandwidthHists ? nozero : pdf);
438
439 stats.averageWriteBW = stats.totalWrittenBytes / simSeconds;
440
441 stats.readLatencyHist
442 .init(params()->latency_bins)
443 .name(name() + ".readLatencyHist")
444 .desc("Read request-response latency")
445 .flags(stats.disableLatencyHists ? nozero : pdf);
446
447 stats.writeLatencyHist
448 .init(params()->latency_bins)
449 .name(name() + ".writeLatencyHist")
450 .desc("Write request-response latency")
451 .flags(stats.disableLatencyHists ? nozero : pdf);
452
453 stats.ittReadRead
454 .init(1, params()->itt_max_bin, params()->itt_max_bin /
455 params()->itt_bins)
456 .name(name() + ".ittReadRead")
457 .desc("Read-to-read inter transaction time")
458 .flags(stats.disableITTDists ? nozero : pdf);
459
460 stats.ittWriteWrite
461 .init(1, params()->itt_max_bin, params()->itt_max_bin /
462 params()->itt_bins)
463 .name(name() + ".ittWriteWrite")
464 .desc("Write-to-write inter transaction time")
465 .flags(stats.disableITTDists ? nozero : pdf);
466
467 stats.ittReqReq
468 .init(1, params()->itt_max_bin, params()->itt_max_bin /
469 params()->itt_bins)
470 .name(name() + ".ittReqReq")
471 .desc("Request-to-request inter transaction time")
472 .flags(stats.disableITTDists ? nozero : pdf);
473
474 stats.outstandingReadsHist
475 .init(params()->outstanding_bins)
476 .name(name() + ".outstandingReadsHist")
477 .desc("Outstanding read transactions")
478 .flags(stats.disableOutstandingHists ? nozero : pdf);
479
480 stats.outstandingWritesHist
481 .init(params()->outstanding_bins)
482 .name(name() + ".outstandingWritesHist")
483 .desc("Outstanding write transactions")
484 .flags(stats.disableOutstandingHists ? nozero : pdf);
485
486 stats.readTransHist
487 .init(params()->transaction_bins)
488 .name(name() + ".readTransHist")
489 .desc("Histogram of read transactions per sample period")
490 .flags(stats.disableTransactionHists ? nozero : pdf);
491
492 stats.writeTransHist
493 .init(params()->transaction_bins)
494 .name(name() + ".writeTransHist")
495 .desc("Histogram of read transactions per sample period")
496 .flags(stats.disableTransactionHists ? nozero : pdf);
497
498 stats.readAddrDist
499 .init(0)
500 .name(name() + ".readAddrDist")
501 .desc("Read address distribution")
502 .flags(stats.disableAddrDists ? nozero : pdf);
503
504 stats.writeAddrDist
505 .init(0)
506 .name(name() + ".writeAddrDist")
507 .desc("Write address distribution")
508 .flags(stats.disableAddrDists ? nozero : pdf);
509 }
510
511 void
512 CommMonitor::samplePeriodic()
513 {
514 // the periodic stats update runs on the granularity of sample
515 // periods, but in combination with this there may also be a
516 // external resets and dumps of the stats (through schedStatEvent)
517 // causing the stats themselves to capture less than a sample
518 // period
519
520 // only capture if we have not reset the stats during the last
521 // sample period
522 if (simTicks.value() >= samplePeriodTicks) {
523 if (!stats.disableTransactionHists) {
524 stats.readTransHist.sample(stats.readTrans);
525 stats.writeTransHist.sample(stats.writeTrans);
526 }
527
528 if (!stats.disableBandwidthHists) {
529 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
530 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
531 }
532
533 if (!stats.disableOutstandingHists) {
534 stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
535 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
536 }
537 }
538
539 // reset the sampled values
540 stats.readTrans = 0;
541 stats.writeTrans = 0;
542
543 stats.readBytes = 0;
544 stats.writtenBytes = 0;
545
546 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
547 }
548
549 void
550 CommMonitor::startup()
551 {
552 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
553 }