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