comm_monitor.cc revision 11284:b3926db25371
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    ProbePoints::PacketInfo req_pkt_info(pkt);
119    ppPktReq->notify(req_pkt_info);
120
121    const Tick delay(masterPort.sendAtomic(pkt));
122    assert(pkt->isResponse());
123    ProbePoints::PacketInfo resp_pkt_info(pkt);
124    ppPktResp->notify(resp_pkt_info);
125    return delay;
126}
127
128Tick
129CommMonitor::recvAtomicSnoop(PacketPtr pkt)
130{
131    return slavePort.sendAtomicSnoop(pkt);
132}
133
134bool
135CommMonitor::recvTimingReq(PacketPtr pkt)
136{
137    // should always see a request
138    assert(pkt->isRequest());
139
140    // Store relevant fields of packet, because packet may be modified
141    // or even deleted when sendTiming() is called.
142    const ProbePoints::PacketInfo pkt_info(pkt);
143
144    const bool is_read = pkt->isRead();
145    const bool is_write = pkt->isWrite();
146    const bool expects_response(
147        pkt->needsResponse() && !pkt->cacheResponding());
148
149    // If a cache miss is served by a cache, a monitor near the memory
150    // would see a request which needs a response, but this response
151    // would not come back from the memory. Therefore we additionally
152    // have to check the cacheResponding flag
153    if (expects_response && !stats.disableLatencyHists) {
154        pkt->pushSenderState(new CommMonitorSenderState(curTick()));
155    }
156
157    // Attempt to send the packet
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        ppPktReq->notify(pkt_info);
167    }
168
169    if (successful && is_read) {
170        DPRINTF(CommMonitor, "Forwarded read request\n");
171
172        // Increment number of observed read transactions
173        if (!stats.disableTransactionHists) {
174            ++stats.readTrans;
175        }
176
177        // Get sample of burst length
178        if (!stats.disableBurstLengthHists) {
179            stats.readBurstLengthHist.sample(pkt_info.size);
180        }
181
182        // Sample the masked address
183        if (!stats.disableAddrDists) {
184            stats.readAddrDist.sample(pkt_info.addr & readAddrMask);
185        }
186
187        // If it needs a response increment number of outstanding read
188        // requests
189        if (!stats.disableOutstandingHists && expects_response) {
190            ++stats.outstandingReadReqs;
191        }
192
193        if (!stats.disableITTDists) {
194            // Sample value of read-read inter transaction time
195            if (stats.timeOfLastRead != 0) {
196                stats.ittReadRead.sample(curTick() - stats.timeOfLastRead);
197            }
198            stats.timeOfLastRead = curTick();
199
200            // Sample value of req-req inter transaction time
201            if (stats.timeOfLastReq != 0) {
202                stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
203            }
204            stats.timeOfLastReq = curTick();
205        }
206    } else if (successful && is_write) {
207        DPRINTF(CommMonitor, "Forwarded write request\n");
208
209        // Same as for reads
210        if (!stats.disableTransactionHists) {
211            ++stats.writeTrans;
212        }
213
214        if (!stats.disableBurstLengthHists) {
215            stats.writeBurstLengthHist.sample(pkt_info.size);
216        }
217
218        // Update the bandwidth stats on the request
219        if (!stats.disableBandwidthHists) {
220            stats.writtenBytes += pkt_info.size;
221            stats.totalWrittenBytes += pkt_info.size;
222        }
223
224        // Sample the masked write address
225        if (!stats.disableAddrDists) {
226            stats.writeAddrDist.sample(pkt_info.addr & writeAddrMask);
227        }
228
229        if (!stats.disableOutstandingHists && expects_response) {
230            ++stats.outstandingWriteReqs;
231        }
232
233        if (!stats.disableITTDists) {
234            // Sample value of write-to-write inter transaction time
235            if (stats.timeOfLastWrite != 0) {
236                stats.ittWriteWrite.sample(curTick() - stats.timeOfLastWrite);
237            }
238            stats.timeOfLastWrite = curTick();
239
240            // Sample value of req-to-req inter transaction time
241            if (stats.timeOfLastReq != 0) {
242                stats.ittReqReq.sample(curTick() - stats.timeOfLastReq);
243            }
244            stats.timeOfLastReq = curTick();
245        }
246    } else if (successful) {
247        DPRINTF(CommMonitor, "Forwarded non read/write request\n");
248    }
249
250    return successful;
251}
252
253bool
254CommMonitor::recvTimingResp(PacketPtr pkt)
255{
256    // should always see responses
257    assert(pkt->isResponse());
258
259    // Store relevant fields of packet, because packet may be modified
260    // or even deleted when sendTiming() is called.
261    const ProbePoints::PacketInfo pkt_info(pkt);
262
263    bool is_read = pkt->isRead();
264    bool is_write = pkt->isWrite();
265    Tick latency = 0;
266    CommMonitorSenderState* received_state =
267        dynamic_cast<CommMonitorSenderState*>(pkt->senderState);
268
269    if (!stats.disableLatencyHists) {
270        // Restore initial sender state
271        if (received_state == NULL)
272            panic("Monitor got a response without monitor sender state\n");
273
274        // Restore the sate
275        pkt->senderState = received_state->predecessor;
276    }
277
278    // Attempt to send the packet
279    bool successful = slavePort.sendTimingResp(pkt);
280
281    if (!stats.disableLatencyHists) {
282        // If packet successfully send, sample value of latency,
283        // afterwards delete sender state, otherwise restore state
284        if (successful) {
285            latency = curTick() - received_state->transmitTime;
286            DPRINTF(CommMonitor, "Latency: %d\n", latency);
287            delete received_state;
288        } else {
289            // Don't delete anything and let the packet look like we
290            // did not touch it
291            pkt->senderState = received_state;
292        }
293    }
294
295    if (successful) {
296        ppPktResp->notify(pkt_info);
297    }
298
299    if (successful && is_read) {
300        // Decrement number of outstanding read requests
301        DPRINTF(CommMonitor, "Received read response\n");
302        if (!stats.disableOutstandingHists) {
303            assert(stats.outstandingReadReqs != 0);
304            --stats.outstandingReadReqs;
305        }
306
307        if (!stats.disableLatencyHists) {
308            stats.readLatencyHist.sample(latency);
309        }
310
311        // Update the bandwidth stats based on responses for reads
312        if (!stats.disableBandwidthHists) {
313            stats.readBytes += pkt_info.size;
314            stats.totalReadBytes += pkt_info.size;
315        }
316
317    } else if (successful && is_write) {
318        // Decrement number of outstanding write requests
319        DPRINTF(CommMonitor, "Received write response\n");
320        if (!stats.disableOutstandingHists) {
321            assert(stats.outstandingWriteReqs != 0);
322            --stats.outstandingWriteReqs;
323        }
324
325        if (!stats.disableLatencyHists) {
326            stats.writeLatencyHist.sample(latency);
327        }
328    } else if (successful) {
329        DPRINTF(CommMonitor, "Received non read/write response\n");
330    }
331    return successful;
332}
333
334void
335CommMonitor::recvTimingSnoopReq(PacketPtr pkt)
336{
337    slavePort.sendTimingSnoopReq(pkt);
338}
339
340bool
341CommMonitor::recvTimingSnoopResp(PacketPtr pkt)
342{
343    return masterPort.sendTimingSnoopResp(pkt);
344}
345
346void
347CommMonitor::recvRetrySnoopResp()
348{
349    slavePort.sendRetrySnoopResp();
350}
351
352bool
353CommMonitor::isSnooping() const
354{
355    // check if the connected master port is snooping
356    return slavePort.isSnooping();
357}
358
359AddrRangeList
360CommMonitor::getAddrRanges() const
361{
362    // get the address ranges of the connected slave port
363    return masterPort.getAddrRanges();
364}
365
366void
367CommMonitor::recvReqRetry()
368{
369    slavePort.sendRetryReq();
370}
371
372void
373CommMonitor::recvRespRetry()
374{
375    masterPort.sendRetryResp();
376}
377
378void
379CommMonitor::recvRangeChange()
380{
381    slavePort.sendRangeChange();
382}
383
384void
385CommMonitor::regStats()
386{
387    // Initialise all the monitor stats
388    using namespace Stats;
389
390    stats.readBurstLengthHist
391        .init(params()->burst_length_bins)
392        .name(name() + ".readBurstLengthHist")
393        .desc("Histogram of burst lengths of transmitted packets")
394        .flags(stats.disableBurstLengthHists ? nozero : pdf);
395
396    stats.writeBurstLengthHist
397        .init(params()->burst_length_bins)
398        .name(name() + ".writeBurstLengthHist")
399        .desc("Histogram of burst lengths of transmitted packets")
400        .flags(stats.disableBurstLengthHists ? nozero : pdf);
401
402    // Stats based on received responses
403    stats.readBandwidthHist
404        .init(params()->bandwidth_bins)
405        .name(name() + ".readBandwidthHist")
406        .desc("Histogram of read bandwidth per sample period (bytes/s)")
407        .flags(stats.disableBandwidthHists ? nozero : pdf);
408
409    stats.averageReadBW
410        .name(name() + ".averageReadBandwidth")
411        .desc("Average read bandwidth (bytes/s)")
412        .flags(stats.disableBandwidthHists ? nozero : pdf);
413
414    stats.totalReadBytes
415        .name(name() + ".totalReadBytes")
416        .desc("Number of bytes read")
417        .flags(stats.disableBandwidthHists ? nozero : pdf);
418
419    stats.averageReadBW = stats.totalReadBytes / simSeconds;
420
421    // Stats based on successfully sent requests
422    stats.writeBandwidthHist
423        .init(params()->bandwidth_bins)
424        .name(name() + ".writeBandwidthHist")
425        .desc("Histogram of write bandwidth (bytes/s)")
426        .flags(stats.disableBandwidthHists ? (pdf | nozero) : pdf);
427
428    stats.averageWriteBW
429        .name(name() + ".averageWriteBandwidth")
430        .desc("Average write bandwidth (bytes/s)")
431        .flags(stats.disableBandwidthHists ? nozero : pdf);
432
433    stats.totalWrittenBytes
434        .name(name() + ".totalWrittenBytes")
435        .desc("Number of bytes written")
436        .flags(stats.disableBandwidthHists ? nozero : pdf);
437
438    stats.averageWriteBW = stats.totalWrittenBytes / simSeconds;
439
440    stats.readLatencyHist
441        .init(params()->latency_bins)
442        .name(name() + ".readLatencyHist")
443        .desc("Read request-response latency")
444        .flags(stats.disableLatencyHists ? nozero : pdf);
445
446    stats.writeLatencyHist
447        .init(params()->latency_bins)
448        .name(name() + ".writeLatencyHist")
449        .desc("Write request-response latency")
450        .flags(stats.disableLatencyHists ? nozero : pdf);
451
452    stats.ittReadRead
453        .init(1, params()->itt_max_bin, params()->itt_max_bin /
454              params()->itt_bins)
455        .name(name() + ".ittReadRead")
456        .desc("Read-to-read inter transaction time")
457        .flags(stats.disableITTDists ? nozero : pdf);
458
459    stats.ittWriteWrite
460        .init(1, params()->itt_max_bin, params()->itt_max_bin /
461              params()->itt_bins)
462        .name(name() + ".ittWriteWrite")
463        .desc("Write-to-write inter transaction time")
464        .flags(stats.disableITTDists ? nozero : pdf);
465
466    stats.ittReqReq
467        .init(1, params()->itt_max_bin, params()->itt_max_bin /
468              params()->itt_bins)
469        .name(name() + ".ittReqReq")
470        .desc("Request-to-request inter transaction time")
471        .flags(stats.disableITTDists ? nozero : pdf);
472
473    stats.outstandingReadsHist
474        .init(params()->outstanding_bins)
475        .name(name() + ".outstandingReadsHist")
476        .desc("Outstanding read transactions")
477        .flags(stats.disableOutstandingHists ? nozero : pdf);
478
479    stats.outstandingWritesHist
480        .init(params()->outstanding_bins)
481        .name(name() + ".outstandingWritesHist")
482        .desc("Outstanding write transactions")
483        .flags(stats.disableOutstandingHists ? nozero : pdf);
484
485    stats.readTransHist
486        .init(params()->transaction_bins)
487        .name(name() + ".readTransHist")
488        .desc("Histogram of read transactions per sample period")
489        .flags(stats.disableTransactionHists ? nozero : pdf);
490
491    stats.writeTransHist
492        .init(params()->transaction_bins)
493        .name(name() + ".writeTransHist")
494        .desc("Histogram of read transactions per sample period")
495        .flags(stats.disableTransactionHists ? nozero : pdf);
496
497    stats.readAddrDist
498        .init(0)
499        .name(name() + ".readAddrDist")
500        .desc("Read address distribution")
501        .flags(stats.disableAddrDists ? nozero : pdf);
502
503    stats.writeAddrDist
504        .init(0)
505        .name(name() + ".writeAddrDist")
506        .desc("Write address distribution")
507        .flags(stats.disableAddrDists ? nozero : pdf);
508}
509
510void
511CommMonitor::samplePeriodic()
512{
513    // the periodic stats update runs on the granularity of sample
514    // periods, but in combination with this there may also be a
515    // external resets and dumps of the stats (through schedStatEvent)
516    // causing the stats themselves to capture less than a sample
517    // period
518
519    // only capture if we have not reset the stats during the last
520    // sample period
521    if (simTicks.value() >= samplePeriodTicks) {
522        if (!stats.disableTransactionHists) {
523            stats.readTransHist.sample(stats.readTrans);
524            stats.writeTransHist.sample(stats.writeTrans);
525        }
526
527        if (!stats.disableBandwidthHists) {
528            stats.readBandwidthHist.sample(stats.readBytes / samplePeriod);
529            stats.writeBandwidthHist.sample(stats.writtenBytes / samplePeriod);
530        }
531
532        if (!stats.disableOutstandingHists) {
533            stats.outstandingReadsHist.sample(stats.outstandingReadReqs);
534            stats.outstandingWritesHist.sample(stats.outstandingWriteReqs);
535        }
536    }
537
538    // reset the sampled values
539    stats.readTrans = 0;
540    stats.writeTrans = 0;
541
542    stats.readBytes = 0;
543    stats.writtenBytes = 0;
544
545    schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
546}
547
548void
549CommMonitor::startup()
550{
551    schedule(samplePeriodicEvent, curTick() + samplePeriodTicks);
552}
553