comm_monitor.cc revision 8981:6f4ec692716f
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
45CommMonitor::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
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
77MasterPort&
78CommMonitor::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
87SlavePort&
88CommMonitor::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
97void
98CommMonitor::recvFunctional(PacketPtr pkt)
99{
100    masterPort.sendFunctional(pkt);
101}
102
103void
104CommMonitor::recvFunctionalSnoop(PacketPtr pkt)
105{
106    slavePort.sendFunctionalSnoop(pkt);
107}
108
109Tick
110CommMonitor::recvAtomic(PacketPtr pkt)
111{
112    return masterPort.sendAtomic(pkt);
113}
114
115Tick
116CommMonitor::recvAtomicSnoop(PacketPtr pkt)
117{
118    return slavePort.sendAtomicSnoop(pkt);
119}
120
121bool
122CommMonitor::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
240bool
241CommMonitor::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
316void
317CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
318{
319    slavePort.sendTimingSnoopReq(pkt);
320}
321
322bool
323CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
324{
325    return masterPort.sendTimingSnoopResp(pkt);
326}
327
328bool
329CommMonitor::isSnooping() const
330{
331    return slavePort.getMasterPort().isSnooping();
332}
333
334unsigned
335CommMonitor::deviceBlockSizeMaster()
336{
337    return slavePort.peerBlockSize();
338}
339
340unsigned
341CommMonitor::deviceBlockSizeSlave()
342{
343    return masterPort.peerBlockSize();
344}
345
346AddrRangeList
347CommMonitor::getAddrRanges()
348{
349    return masterPort.getSlavePort().getAddrRanges();
350}
351
352void
353CommMonitor::recvRetryMaster()
354{
355    slavePort.sendRetry();
356}
357
358void
359CommMonitor::recvRetrySlave()
360{
361    masterPort.sendRetry();
362}
363
364void
365CommMonitor::recvRangeChange()
366{
367    slavePort.sendRangeChange();
368}
369
370void
371CommMonitor::regStats()
372{
373    // Initialise all the monitor stats
374    using namespace Stats;
375
376    stats.readBurstLengthHist
377        .init(params()->burst_length_bins)
378        .name(name() + ".readBurstLengthHist")
379        .desc("Histogram of burst lengths of transmitted packets")
380        .flags(stats.disableBurstLengthHists ? nozero : pdf);
381
382    stats.writeBurstLengthHist
383        .init(params()->burst_length_bins)
384        .name(name() + ".writeBurstLengthHist")
385        .desc("Histogram of burst lengths of transmitted packets")
386        .flags(stats.disableBurstLengthHists ? nozero : pdf);
387
388    // Stats based on received responses
389    stats.readBandwidthHist
390        .init(params()->bandwidth_bins)
391        .name(name() + ".readBandwidthHist")
392        .desc("Histogram of read bandwidth per sample period (bytes/s)")
393        .flags(stats.disableBandwidthHists ? nozero : pdf);
394
395    stats.averageReadBW
396        .name(name() + ".averageReadBandwidth")
397        .desc("Average read bandwidth (bytes/s)")
398        .flags(stats.disableBandwidthHists ? nozero : pdf);
399
400    stats.totalReadBytes
401        .name(name() + ".totalReadBytes")
402        .desc("Number of bytes read")
403        .flags(stats.disableBandwidthHists ? nozero : pdf);
404
405    stats.averageReadBW = stats.totalReadBytes / simSeconds;
406
407    // Stats based on successfully sent requests
408    stats.writeBandwidthHist
409        .init(params()->bandwidth_bins)
410        .name(name() + ".writeBandwidthHist")
411        .desc("Histogram of write bandwidth (bytes/s)")
412        .flags(stats.disableBandwidthHists ? (pdf | nozero) : pdf);
413
414    stats.averageWriteBW
415        .name(name() + ".averageWriteBandwidth")
416        .desc("Average write bandwidth (bytes/s)")
417        .flags(stats.disableBandwidthHists ? nozero : pdf);
418
419    stats.totalWrittenBytes
420        .name(name() + ".totalWrittenBytes")
421        .desc("Number of bytes written")
422        .flags(stats.disableBandwidthHists ? nozero : pdf);
423
424    stats.averageWriteBW = stats.totalWrittenBytes / simSeconds;
425
426    stats.readLatencyHist
427        .init(params()->latency_bins)
428        .name(name() + ".readLatencyHist")
429        .desc("Read request-response latency")
430        .flags(stats.disableLatencyHists ? nozero : pdf);
431
432    stats.writeLatencyHist
433        .init(params()->latency_bins)
434        .name(name() + ".writeLatencyHist")
435        .desc("Write request-response latency")
436        .flags(stats.disableLatencyHists ? nozero : pdf);
437
438    stats.ittReadRead
439        .init(1, params()->itt_max_bin, params()->itt_max_bin /
440              params()->itt_bins)
441        .name(name() + ".ittReadRead")
442        .desc("Read-to-read inter transaction time")
443        .flags(stats.disableITTDists ? nozero : pdf);
444
445    stats.ittWriteWrite
446        .init(1, params()->itt_max_bin, params()->itt_max_bin /
447              params()->itt_bins)
448        .name(name() + ".ittWriteWrite")
449        .desc("Write-to-write inter transaction time")
450        .flags(stats.disableITTDists ? nozero : pdf);
451
452    stats.ittReqReq
453        .init(1, params()->itt_max_bin, params()->itt_max_bin /
454              params()->itt_bins)
455        .name(name() + ".ittReqReq")
456        .desc("Request-to-request inter transaction time")
457        .flags(stats.disableITTDists ? nozero : pdf);
458
459    stats.outstandingReadsHist
460        .init(params()->outstanding_bins)
461        .name(name() + ".outstandingReadsHist")
462        .desc("Outstanding read transactions")
463        .flags(stats.disableOutstandingHists ? nozero : pdf);
464
465    stats.outstandingWritesHist
466        .init(params()->outstanding_bins)
467        .name(name() + ".outstandingWritesHist")
468        .desc("Outstanding write transactions")
469        .flags(stats.disableOutstandingHists ? nozero : pdf);
470
471    stats.readTransHist
472        .init(params()->transaction_bins)
473        .name(name() + ".readTransHist")
474        .desc("Histogram of read transactions per sample period")
475        .flags(stats.disableTransactionHists ? nozero : pdf);
476
477    stats.writeTransHist
478        .init(params()->transaction_bins)
479        .name(name() + ".writeTransHist")
480        .desc("Histogram of read transactions per sample period")
481        .flags(stats.disableTransactionHists ? nozero : pdf);
482
483    stats.readAddrDist
484        .init(0)
485        .name(name() + ".readAddrDist")
486        .desc("Read address distribution")
487        .flags(stats.disableAddrDists ? nozero : pdf);
488
489    stats.writeAddrDist
490        .init(0)
491        .name(name() + ".writeAddrDist")
492        .desc("Write address distribution")
493        .flags(stats.disableAddrDists ? nozero : pdf);
494}
495
496void
497CommMonitor::samplePeriodic()
498{
499    // the periodic stats update runs on the granularity of sample
500    // periods, but in combination with this there may also be a
501    // external resets and dumps of the stats (through schedStatEvent)
502    // causing the stats themselves to capture less than a sample
503    // period
504
505    // only capture if we have not reset the stats during the last
506    // sample period
507    if (simTicks.value() >= samplePeriodTicks) {
508        if (!stats.disableTransactionHists) {
509            stats.readTransHist.sample(stats.readTrans);
510            stats.writeTransHist.sample(stats.writeTrans);
511        }
512
513        if (!stats.disableBandwidthHists) {
514            stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
515            stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
516        }
517
518        if (!stats.disableOutstandingHists) {
519            stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
520            stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
521        }
522    }
523
524    // reset the sampled values
525    stats.readTrans = 0;
526    stats.writeTrans = 0;
527
528    stats.readBytes = 0;
529    stats.writtenBytes = 0;
530
531    schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
532}
533
534void
535CommMonitor::startup()
536{
537    schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
538}
539