comm_monitor.cc revision 10996:d48fda705f4d
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
46CommMonitor::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
62CommMonitor*
63CommMonitorParams::create()
64{
65    return new CommMonitor(this);
66}
67
68void
69CommMonitor::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
76void
77CommMonitor::regProbePoints()
78{
79    ppPktReq.reset(new ProbePoints::Packet(getProbeManager(), "PktRequest"));
80    ppPktResp.reset(new ProbePoints::Packet(getProbeManager(), "PktResponse"));
81}
82
83BaseMasterPort&
84CommMonitor::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
93BaseSlavePort&
94CommMonitor::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
103void
104CommMonitor::recvFunctional(PacketPtr pkt)
105{
106    masterPort.sendFunctional(pkt);
107}
108
109void
110CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
111{
112    slavePort.sendFunctionalSnoop(pkt);
113}
114
115Tick
116CommMonitor::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
126Tick
127CommMonitor::recvAtomicSnoop(PacketPtr pkt)
128{
129    return slavePort.sendAtomicSnoop(pkt);
130}
131
132bool
133CommMonitor::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
260bool
261CommMonitor::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
341void
342CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
343{
344    slavePort.sendTimingSnoopReq(pkt);
345}
346
347bool
348CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
349{
350    return masterPort.sendTimingSnoopResp(pkt);
351}
352
353bool
354CommMonitor::isSnooping() const
355{
356    // check if the connected master port is snooping
357    return slavePort.isSnooping();
358}
359
360AddrRangeList
361CommMonitor::getAddrRanges() const
362{
363    // get the address ranges of the connected slave port
364    return masterPort.getAddrRanges();
365}
366
367void
368CommMonitor::recvReqRetry()
369{
370    slavePort.sendRetryReq();
371}
372
373void
374CommMonitor::recvRespRetry()
375{
376    masterPort.sendRetryResp();
377}
378
379void
380CommMonitor::recvRangeChange()
381{
382    slavePort.sendRangeChange();
383}
384
385void
386CommMonitor::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
511void
512CommMonitor::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
549void
550CommMonitor::startup()
551{
552    schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
553}
554