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