/* * Copyright (c) 2012-2013, 2015 ARM Limited * Copyright (c) 2016 Google Inc. * Copyright (c) 2017, Centre National de la Recherche Scientifique * All rights reserved. * * The license below extends only to copyright in the software and shall * not be construed as granting a license to any other intellectual * property including but not limited to intellectual property relating * to a hardware implementation of the functionality of the software * licensed hereunder. You may use the software subject to the license * terms below provided that you ensure that this notice is replicated * unmodified and in its entirety in all distributions of the software, * modified or unmodified, in source code or in binary form. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer; * redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution; * neither the name of the copyright holders nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * * Authors: Thomas Grass * Andreas Hansson * Rahul Thakur * Pierre-Yves Peneau */ #ifndef __MEM_COMM_MONITOR_HH__ #define __MEM_COMM_MONITOR_HH__ #include "base/statistics.hh" #include "mem/mem_object.hh" #include "params/CommMonitor.hh" #include "sim/probe/mem.hh" /** * The communication monitor is a MemObject which can monitor statistics of * the communication happening between two ports in the memory system. * * Currently the following stats are implemented: Histograms of read/write * transactions, read/write burst lengths, read/write bandwidth, * outstanding read/write requests, read latency and inter transaction time * (read-read, write-write, read/write-read/write). Furthermore it allows * to capture the number of accesses to an address over time ("heat map"). * All stats can be disabled from Python. */ class CommMonitor : public MemObject { public: // Construction & SimObject interfaces /** Parameters of communication monitor */ typedef CommMonitorParams Params; const Params* params() const { return reinterpret_cast(_params); } /** * Constructor based on the Python params * * @param params Python parameters */ CommMonitor(Params* params); void init() override; void regStats() override; void startup() override; void regProbePoints() override; public: // MemObject interfaces BaseMasterPort& getMasterPort(const std::string& if_name, PortID idx = InvalidPortID) override; BaseSlavePort& getSlavePort(const std::string& if_name, PortID idx = InvalidPortID) override; private: /** * Sender state class for the monitor so that we can annotate * packets with a transmit time and receive time. */ class CommMonitorSenderState : public Packet::SenderState { public: /** * Construct a new sender state and store the time so we can * calculate round-trip latency. * * @param _transmitTime Time of packet transmission */ CommMonitorSenderState(Tick _transmitTime) : transmitTime(_transmitTime) { } /** Destructor */ ~CommMonitorSenderState() { } /** Tick when request is transmitted */ Tick transmitTime; }; /** * This is the master port of the communication monitor. All recv * functions call a function in CommMonitor, where the * send function of the slave port is called. Besides this, these * functions can also perform actions for capturing statistics. */ class MonitorMasterPort : public MasterPort { public: MonitorMasterPort(const std::string& _name, CommMonitor& _mon) : MasterPort(_name, &_mon), mon(_mon) { } protected: void recvFunctionalSnoop(PacketPtr pkt) { mon.recvFunctionalSnoop(pkt); } Tick recvAtomicSnoop(PacketPtr pkt) { return mon.recvAtomicSnoop(pkt); } bool recvTimingResp(PacketPtr pkt) { return mon.recvTimingResp(pkt); } void recvTimingSnoopReq(PacketPtr pkt) { mon.recvTimingSnoopReq(pkt); } void recvRangeChange() { mon.recvRangeChange(); } bool isSnooping() const { return mon.isSnooping(); } void recvReqRetry() { mon.recvReqRetry(); } void recvRetrySnoopResp() { mon.recvRetrySnoopResp(); } private: CommMonitor& mon; }; /** Instance of master port, facing the memory side */ MonitorMasterPort masterPort; /** * This is the slave port of the communication monitor. All recv * functions call a function in CommMonitor, where the * send function of the master port is called. Besides this, these * functions can also perform actions for capturing statistics. */ class MonitorSlavePort : public SlavePort { public: MonitorSlavePort(const std::string& _name, CommMonitor& _mon) : SlavePort(_name, &_mon), mon(_mon) { } protected: void recvFunctional(PacketPtr pkt) { mon.recvFunctional(pkt); } Tick recvAtomic(PacketPtr pkt) { return mon.recvAtomic(pkt); } bool recvTimingReq(PacketPtr pkt) { return mon.recvTimingReq(pkt); } bool recvTimingSnoopResp(PacketPtr pkt) { return mon.recvTimingSnoopResp(pkt); } AddrRangeList getAddrRanges() const { return mon.getAddrRanges(); } void recvRespRetry() { mon.recvRespRetry(); } private: CommMonitor& mon; }; /** Instance of slave port, i.e. on the CPU side */ MonitorSlavePort slavePort; void recvFunctional(PacketPtr pkt); void recvFunctionalSnoop(PacketPtr pkt); Tick recvAtomic(PacketPtr pkt); Tick recvAtomicSnoop(PacketPtr pkt); bool recvTimingReq(PacketPtr pkt); bool recvTimingResp(PacketPtr pkt); void recvTimingSnoopReq(PacketPtr pkt); bool recvTimingSnoopResp(PacketPtr pkt); void recvRetrySnoopResp(); AddrRangeList getAddrRanges() const; bool isSnooping() const; void recvReqRetry(); void recvRespRetry(); void recvRangeChange(); /** Stats declarations, all in a struct for convenience. */ struct MonitorStats { /** Disable flag for burst length histograms **/ bool disableBurstLengthHists; /** Histogram of read burst lengths */ Stats::Histogram readBurstLengthHist; /** Histogram of write burst lengths */ Stats::Histogram writeBurstLengthHist; /** Disable flag for the bandwidth histograms */ bool disableBandwidthHists; /** * Histogram for read bandwidth per sample window. The * internal counter is an unsigned int rather than a stat. */ unsigned int readBytes; Stats::Histogram readBandwidthHist; Stats::Formula averageReadBW; Stats::Scalar totalReadBytes; /** * Histogram for write bandwidth per sample window. The * internal counter is an unsigned int rather than a stat. */ unsigned int writtenBytes; Stats::Histogram writeBandwidthHist; Stats::Formula averageWriteBW; Stats::Scalar totalWrittenBytes; /** Disable flag for latency histograms. */ bool disableLatencyHists; /** Histogram of read request-to-response latencies */ Stats::Histogram readLatencyHist; /** Histogram of write request-to-response latencies */ Stats::Histogram writeLatencyHist; /** Disable flag for ITT distributions. */ bool disableITTDists; /** * Inter transaction time (ITT) distributions. There are * histograms of the time between two read, write or arbitrary * accesses. The time of a request is the tick at which the * request is forwarded by the monitor. */ Stats::Distribution ittReadRead; Stats::Distribution ittWriteWrite; Stats::Distribution ittReqReq; Tick timeOfLastRead; Tick timeOfLastWrite; Tick timeOfLastReq; /** Disable flag for outstanding histograms. */ bool disableOutstandingHists; /** * Histogram of outstanding read requests. Counter for * outstanding read requests is an unsigned integer because * it should not be reset when stats are reset. */ Stats::Histogram outstandingReadsHist; unsigned int outstandingReadReqs; /** * Histogram of outstanding write requests. Counter for * outstanding write requests is an unsigned integer because * it should not be reset when stats are reset. */ Stats::Histogram outstandingWritesHist; unsigned int outstandingWriteReqs; /** Disable flag for transaction histograms. */ bool disableTransactionHists; /** Histogram of number of read transactions per time bin */ Stats::Histogram readTransHist; unsigned int readTrans; /** Histogram of number of timing write transactions per time bin */ Stats::Histogram writeTransHist; unsigned int writeTrans; /** Disable flag for address distributions. */ bool disableAddrDists; /** Address mask for sources of read accesses to be captured */ const Addr readAddrMask; /** Address mask for sources of write accesses to be captured */ const Addr writeAddrMask; /** * Histogram of number of read accesses to addresses over * time. */ Stats::SparseHistogram readAddrDist; /** * Histogram of number of write accesses to addresses over * time. */ Stats::SparseHistogram writeAddrDist; /** * Create the monitor stats and initialise all the members * that are not statistics themselves, but used to control the * stats or track values during a sample period. */ MonitorStats(const CommMonitorParams* params) : disableBurstLengthHists(params->disable_burst_length_hists), disableBandwidthHists(params->disable_bandwidth_hists), readBytes(0), writtenBytes(0), disableLatencyHists(params->disable_latency_hists), disableITTDists(params->disable_itt_dists), timeOfLastRead(0), timeOfLastWrite(0), timeOfLastReq(0), disableOutstandingHists(params->disable_outstanding_hists), outstandingReadReqs(0), outstandingWriteReqs(0), disableTransactionHists(params->disable_transaction_hists), readTrans(0), writeTrans(0), disableAddrDists(params->disable_addr_dists), readAddrMask(params->read_addr_mask), writeAddrMask(params->write_addr_mask) { } void updateReqStats(const ProbePoints::PacketInfo& pkt, bool is_atomic, bool expects_response); void updateRespStats(const ProbePoints::PacketInfo& pkt, Tick latency, bool is_atomic); }; /** This function is called periodically at the end of each time bin */ void samplePeriodic(); /** Periodic event called at the end of each simulation time bin */ EventFunctionWrapper samplePeriodicEvent; /** *@{ * @name Configuration */ /** Length of simulation time bin*/ const Tick samplePeriodTicks; /** Sample period in seconds */ const double samplePeriod; /** @} */ /** Instantiate stats */ MonitorStats stats; protected: // Probe points /** * @{ * @name Memory system probe points */ /** Successfully forwarded request packet */ ProbePoints::PacketUPtr ppPktReq; /** Successfully forwarded response packet */ ProbePoints::PacketUPtr ppPktResp; /** @} */ }; #endif //__MEM_COMM_MONITOR_HH__