mem: Add Units to mem stats
[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, UNIT_BYTE,
105 "Histogram of burst lengths of transmitted packets"),
106 ADD_STAT(writeBurstLengthHist, UNIT_BYTE,
107 "Histogram of burst lengths of transmitted packets"),
108
109 disableBandwidthHists(params.disable_bandwidth_hists),
110 readBytes(0),
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),
119
120 writtenBytes(0),
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),
131
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"),
135
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),
143
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),
151
152 disableTransactionHists(params.disable_transaction_hists),
153 ADD_STAT(readTransHist, UNIT_COUNT,
154 "Histogram of read transactions per sample period"),
155 readTrans(0),
156 ADD_STAT(writeTransHist, UNIT_COUNT,
157 "Histogram of write transactions per sample period"),
158 writeTrans(0),
159
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")
165 {
166 using namespace Stats;
167
168 readBurstLengthHist
169 .init(params.burst_length_bins)
170 .flags(disableBurstLengthHists ? nozero : pdf);
171
172 writeBurstLengthHist
173 .init(params.burst_length_bins)
174 .flags(disableBurstLengthHists ? nozero : pdf);
175
176 // Stats based on received responses
177 readBandwidthHist
178 .init(params.bandwidth_bins)
179 .flags(disableBandwidthHists ? nozero : pdf);
180
181 averageReadBandwidth
182 .flags(disableBandwidthHists ? nozero : pdf);
183
184 totalReadBytes
185 .flags(disableBandwidthHists ? nozero : pdf);
186
187 // Stats based on successfully sent requests
188 writeBandwidthHist
189 .init(params.bandwidth_bins)
190 .flags(disableBandwidthHists ? (pdf | nozero) : pdf);
191
192 averageWriteBandwidth
193 .flags(disableBandwidthHists ? nozero : pdf);
194
195 totalWrittenBytes
196 .flags(disableBandwidthHists ? nozero : pdf);
197
198
199 readLatencyHist
200 .init(params.latency_bins)
201 .flags(disableLatencyHists ? nozero : pdf);
202
203 writeLatencyHist
204 .init(params.latency_bins)
205 .flags(disableLatencyHists ? nozero : pdf);
206
207 ittReadRead
208 .init(1, params.itt_max_bin, params.itt_max_bin /
209 params.itt_bins)
210 .flags(disableITTDists ? nozero : pdf);
211
212 ittWriteWrite
213 .init(1, params.itt_max_bin, params.itt_max_bin /
214 params.itt_bins)
215 .flags(disableITTDists ? nozero : pdf);
216
217 ittReqReq
218 .init(1, params.itt_max_bin, params.itt_max_bin /
219 params.itt_bins)
220 .flags(disableITTDists ? nozero : pdf);
221
222 outstandingReadsHist
223 .init(params.outstanding_bins)
224 .flags(disableOutstandingHists ? nozero : pdf);
225
226 outstandingWritesHist
227 .init(params.outstanding_bins)
228 .flags(disableOutstandingHists ? nozero : pdf);
229
230 readTransHist
231 .init(params.transaction_bins)
232 .flags(disableTransactionHists ? nozero : pdf);
233
234 writeTransHist
235 .init(params.transaction_bins)
236 .flags(disableTransactionHists ? nozero : pdf);
237
238 readAddrDist
239 .init(0)
240 .flags(disableAddrDists ? nozero : pdf);
241
242 writeAddrDist
243 .init(0)
244 .flags(disableAddrDists ? nozero : pdf);
245 }
246
247 void
248 CommMonitor::MonitorStats::updateReqStats(
249 const ProbePoints::PacketInfo& pkt_info, bool is_atomic,
250 bool expects_response)
251 {
252 if (pkt_info.cmd.isRead()) {
253 // Increment number of observed read transactions
254 if (!disableTransactionHists)
255 ++readTrans;
256
257 // Get sample of burst length
258 if (!disableBurstLengthHists)
259 readBurstLengthHist.sample(pkt_info.size);
260
261 // Sample the masked address
262 if (!disableAddrDists)
263 readAddrDist.sample(pkt_info.addr & readAddrMask);
264
265 if (!disableITTDists) {
266 // Sample value of read-read inter transaction time
267 if (timeOfLastRead != 0)
268 ittReadRead.sample(curTick() - timeOfLastRead);
269 timeOfLastRead = curTick();
270
271 // Sample value of req-req inter transaction time
272 if (timeOfLastReq != 0)
273 ittReqReq.sample(curTick() - timeOfLastReq);
274 timeOfLastReq = curTick();
275 }
276 if (!is_atomic && !disableOutstandingHists && expects_response)
277 ++outstandingReadReqs;
278
279 } else if (pkt_info.cmd.isWrite()) {
280 // Same as for reads
281 if (!disableTransactionHists)
282 ++writeTrans;
283
284 if (!disableBurstLengthHists)
285 writeBurstLengthHist.sample(pkt_info.size);
286
287 // Update the bandwidth stats on the request
288 if (!disableBandwidthHists) {
289 writtenBytes += pkt_info.size;
290 totalWrittenBytes += pkt_info.size;
291 }
292
293 // Sample the masked write address
294 if (!disableAddrDists)
295 writeAddrDist.sample(pkt_info.addr & writeAddrMask);
296
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();
302
303 // Sample value of req-to-req inter transaction time
304 if (timeOfLastReq != 0)
305 ittReqReq.sample(curTick() - timeOfLastReq);
306 timeOfLastReq = curTick();
307 }
308
309 if (!is_atomic && !disableOutstandingHists && expects_response)
310 ++outstandingWriteReqs;
311 }
312 }
313
314 void
315 CommMonitor::MonitorStats::updateRespStats(
316 const ProbePoints::PacketInfo& pkt_info, Tick latency, bool is_atomic)
317 {
318 if (pkt_info.cmd.isRead()) {
319 // Decrement number of outstanding read requests
320 if (!is_atomic && !disableOutstandingHists) {
321 assert(outstandingReadReqs != 0);
322 --outstandingReadReqs;
323 }
324
325 if (!disableLatencyHists)
326 readLatencyHist.sample(latency);
327
328 // Update the bandwidth stats based on responses for reads
329 if (!disableBandwidthHists) {
330 readBytes += pkt_info.size;
331 totalReadBytes += pkt_info.size;
332 }
333
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;
339 }
340
341 if (!disableLatencyHists)
342 writeLatencyHist.sample(latency);
343 }
344 }
345
346 Tick
347 CommMonitor::recvAtomic(PacketPtr pkt)
348 {
349 const bool expects_response(pkt->needsResponse() &&
350 !pkt->cacheResponding());
351 ProbePoints::PacketInfo req_pkt_info(pkt);
352 ppPktReq->notify(req_pkt_info);
353
354 const Tick delay(memSidePort.sendAtomic(pkt));
355
356 stats.updateReqStats(req_pkt_info, true, expects_response);
357 if (expects_response)
358 stats.updateRespStats(req_pkt_info, delay, true);
359
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);
364 return delay;
365 }
366
367 Tick
368 CommMonitor::recvAtomicSnoop(PacketPtr pkt)
369 {
370 return cpuSidePort.sendAtomicSnoop(pkt);
371 }
372
373 bool
374 CommMonitor::recvTimingReq(PacketPtr pkt)
375 {
376 // should always see a request
377 assert(pkt->isRequest());
378
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);
382
383 const bool expects_response(pkt->needsResponse() &&
384 !pkt->cacheResponding());
385
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()));
392 }
393
394 // Attempt to send the packet
395 bool successful = memSidePort.sendTimingReq(pkt);
396
397 // If not successful, restore the sender state
398 if (!successful && expects_response && !stats.disableLatencyHists) {
399 delete pkt->popSenderState();
400 }
401
402 if (successful) {
403 ppPktReq->notify(pkt_info);
404 }
405
406 if (successful) {
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);
410 }
411 return successful;
412 }
413
414 bool
415 CommMonitor::recvTimingResp(PacketPtr pkt)
416 {
417 // should always see responses
418 assert(pkt->isResponse());
419
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);
423
424 Tick latency = 0;
425 CommMonitorSenderState* received_state =
426 dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
427
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");
432
433 // Restore the sate
434 pkt->senderState = received_state->predecessor;
435 }
436
437 // Attempt to send the packet
438 bool successful = cpuSidePort.sendTimingResp(pkt);
439
440 if (!stats.disableLatencyHists) {
441 // If packet successfully send, sample value of latency,
442 // afterwards delete sender state, otherwise restore state
443 if (successful) {
444 latency = curTick() - received_state->transmitTime;
445 DPRINTF(CommMonitor, "Latency: %d\n", latency);
446 delete received_state;
447 } else {
448 // Don't delete anything and let the packet look like we
449 // did not touch it
450 pkt->senderState = received_state;
451 }
452 }
453
454 if (successful) {
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);
459 }
460 return successful;
461 }
462
463 void
464 CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
465 {
466 cpuSidePort.sendTimingSnoopReq(pkt);
467 }
468
469 bool
470 CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
471 {
472 return memSidePort.sendTimingSnoopResp(pkt);
473 }
474
475 void
476 CommMonitor::recvRetrySnoopResp()
477 {
478 cpuSidePort.sendRetrySnoopResp();
479 }
480
481 bool
482 CommMonitor::isSnooping() const
483 {
484 // check if the connected request port is snooping
485 return cpuSidePort.isSnooping();
486 }
487
488 AddrRangeList
489 CommMonitor::getAddrRanges() const
490 {
491 // get the address ranges of the connected CPU-side port
492 return memSidePort.getAddrRanges();
493 }
494
495 void
496 CommMonitor::recvReqRetry()
497 {
498 cpuSidePort.sendRetryReq();
499 }
500
501 void
502 CommMonitor::recvRespRetry()
503 {
504 memSidePort.sendRetryResp();
505 }
506
507 bool
508 CommMonitor::tryTiming(PacketPtr pkt)
509 {
510 return memSidePort.tryTiming(pkt);
511 }
512
513 void
514 CommMonitor::recvRangeChange()
515 {
516 cpuSidePort.sendRangeChange();
517 }
518
519 void
520 CommMonitor::samplePeriodic()
521 {
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
526 // period
527
528 // only capture if we have not reset the stats during the last
529 // sample period
530 if (simTicks.value() >= samplePeriodTicks) {
531 if (!stats.disableTransactionHists) {
532 stats.readTransHist.sample(stats.readTrans);
533 stats.writeTransHist.sample(stats.writeTrans);
534 }
535
536 if (!stats.disableBandwidthHists) {
537 stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
538 stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
539 }
540
541 if (!stats.disableOutstandingHists) {
542 stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
543 stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
544 }
545 }
546
547 // reset the sampled values
548 stats.readTrans = 0;
549 stats.writeTrans = 0;
550
551 stats.readBytes = 0;
552 stats.writtenBytes = 0;
553
554 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
555 }
556
557 void
558 CommMonitor::startup()
559 {
560 schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
561 }