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