diff options
Diffstat (limited to 'src/mem/qos/mem_ctrl.cc')
-rw-r--r-- | src/mem/qos/mem_ctrl.cc | 355 |
1 files changed, 355 insertions, 0 deletions
diff --git a/src/mem/qos/mem_ctrl.cc b/src/mem/qos/mem_ctrl.cc new file mode 100644 index 000000000..ce15fd779 --- /dev/null +++ b/src/mem/qos/mem_ctrl.cc @@ -0,0 +1,355 @@ +/* + * Copyright (c) 2017 ARM Limited + * 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: Matteo Andreozzi + */ + +#include "mem_ctrl.hh" + +#include "turnaround_policy.hh" + +namespace QoS { + +MemCtrl::MemCtrl(const QoSMemCtrlParams * p) + : AbstractMemory(p), + policy(p->qos_policy), + turnPolicy(p->qos_turnaround_policy), + queuePolicy(QueuePolicy::create(p)), + _numPriorities(p->qos_priorities), + qosPriorityEscalation(p->qos_priority_escalation), + qosSyncroScheduler(p->qos_syncro_scheduler), + totalReadQueueSize(0), totalWriteQueueSize(0), + busState(READ), busStateNext(READ) +{ + // Set the priority policy + if (policy) { + policy->setMemCtrl(this); + } + + // Set the queue priority policy + if (queuePolicy) { + queuePolicy->setMemCtrl(this); + } + + // Set the bus turnaround policy + if (turnPolicy) { + turnPolicy->setMemCtrl(this); + } + + readQueueSizes.resize(_numPriorities); + writeQueueSizes.resize(_numPriorities); + serviceTick.resize(_numPriorities); +} + +MemCtrl::~MemCtrl() +{} + +void +MemCtrl::init() +{ + AbstractMemory::init(); +} + +void +MemCtrl::logRequest(BusState dir, MasterID m_id, uint8_t qos, + Addr addr, uint64_t entries) +{ + // If needed, initialize all counters and statistics + // for this master + addMaster(m_id); + + DPRINTF(QOS, + "QoSMemCtrl::logRequest MASTER %s [id %d] address %d" + " prio %d this master q packets %d" + " - queue size %d - requested entries %d\n", + masters[m_id], m_id, addr, qos, packetPriorities[m_id][qos], + (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos], + entries); + + if (dir == READ) { + readQueueSizes[qos] += entries; + totalReadQueueSize += entries; + } else if (dir == WRITE) { + writeQueueSizes[qos] += entries; + totalWriteQueueSize += entries; + } + + packetPriorities[m_id][qos] += entries; + for (auto j = 0; j < entries; ++j) { + requestTimes[m_id][addr].push_back(curTick()); + } + + // Record statistics + avgPriority[m_id].sample(qos); + + // Compute avg priority distance + + for (uint8_t i = 0; i < packetPriorities[m_id].size(); ++i) { + uint8_t distance = + (abs(int(qos) - int(i))) * packetPriorities[m_id][i]; + + if (distance > 0) { + avgPriorityDistance[m_id].sample(distance); + DPRINTF(QOS, + "QoSMemCtrl::logRequest MASTER %s [id %d]" + " registering priority distance %d for priority %d" + " (packets %d)\n", + masters[m_id], m_id, distance, i, + packetPriorities[m_id][i]); + } + } + + DPRINTF(QOS, + "QoSMemCtrl::logRequest MASTER %s [id %d] prio %d " + "this master q packets %d - new queue size %d\n", + masters[m_id], m_id, qos, packetPriorities[m_id][qos], + (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos]); + +} + +void +MemCtrl::logResponse(BusState dir, MasterID m_id, uint8_t qos, + Addr addr, uint64_t entries, double delay) +{ + panic_if(!hasMaster(m_id), + "Logging response with invalid master\n"); + + DPRINTF(QOS, + "QoSMemCtrl::logResponse MASTER %s [id %d] address %d prio" + " %d this master q packets %d" + " - queue size %d - requested entries %d\n", + masters[m_id], m_id, addr, qos, packetPriorities[m_id][qos], + (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos], + entries); + + if (dir == READ) { + readQueueSizes[qos] -= entries; + totalReadQueueSize -= entries; + } else if (dir == WRITE) { + writeQueueSizes[qos] -= entries; + totalWriteQueueSize -= entries; + } + + panic_if(packetPriorities[m_id][qos] == 0, + "QoSMemCtrl::logResponse master %s negative packets for priority" + " %d", masters[m_id], qos); + + packetPriorities[m_id][qos] -= entries; + + for (auto j = 0; j < entries; ++j) { + auto it = requestTimes[m_id].find(addr); + panic_if(it == requestTimes[m_id].end(), + "QoSMemCtrl::logResponse master %s unmatched response for" + " address %d received", masters[m_id], addr); + + // Load request time + uint64_t requestTime = it->second.front(); + + // Remove request entry + it->second.pop_front(); + + // Remove whole address entry if last one + if (it->second.empty()) { + requestTimes[m_id].erase(it); + } + // Compute latency + double latency = (double) (curTick() + delay - requestTime) + / SimClock::Float::s; + + if (latency > 0) { + // Record per-priority latency stats + if (priorityMaxLatency[qos].value() < latency) { + priorityMaxLatency[qos] = latency; + } + + if (priorityMinLatency[qos].value() > latency + || priorityMinLatency[qos].value() == 0) { + priorityMinLatency[qos] = latency; + } + } + } + + DPRINTF(QOS, + "QoSMemCtrl::logResponse MASTER %s [id %d] prio %d " + "this master q packets %d - new queue size %d\n", + masters[m_id], m_id, qos, packetPriorities[m_id][qos], + (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos]); +} + +uint8_t +MemCtrl::schedule(MasterID m_id, uint64_t data) +{ + if (policy) { + return policy->schedule(m_id, data); + } else { + DPRINTF(QOS, + "QoSScheduler::schedule master ID [%d] " + "data received [%d], but QoS scheduler not initialized\n", + m_id,data); + return 0; + } +} + +uint8_t +MemCtrl::schedule(const PacketPtr pkt) +{ + assert(pkt->req); + + if (policy) { + return schedule(pkt->req->masterId(), pkt->getSize()); + } else { + DPRINTF(QOS, "QoSScheduler::schedule Packet received [Qv %d], " + "but QoS scheduler not initialized\n", + pkt->qosValue()); + return pkt->qosValue(); + } +} + +MemCtrl::BusState +MemCtrl::selectNextBusState() +{ + auto bus_state = getBusState(); + + if (turnPolicy) { + DPRINTF(QOS, + "QoSMemoryTurnaround::selectBusState running policy %s\n", + turnPolicy->name()); + + bus_state = turnPolicy->selectBusState(); + } else { + DPRINTF(QOS, + "QoSMemoryTurnaround::selectBusState running " + "default bus direction selection policy\n"); + + if ((!getTotalReadQueueSize() && bus_state == MemCtrl::READ) || + (!getTotalWriteQueueSize() && bus_state == MemCtrl::WRITE)) { + // READ/WRITE turnaround + bus_state = (bus_state == MemCtrl::READ) ? MemCtrl::WRITE : + MemCtrl::READ; + + } + } + + return bus_state; +} + +void +MemCtrl::addMaster(MasterID m_id) +{ + if (!hasMaster(m_id)) { + masters.emplace(m_id, _system->getMasterName(m_id)); + packetPriorities[m_id].resize(numPriorities(), 0); + + DPRINTF(QOS, + "QoSMemCtrl::addMaster registering" + " Master %s [id %d]\n", + masters[m_id], m_id); + } +} + +void +MemCtrl::regStats() +{ + AbstractMemory::regStats(); + + using namespace Stats; + + // Initializes per master statistics + avgPriority.init(_system->maxMasters()).name(name() + ".avgPriority") + .desc("Average QoS priority value for accepted requests") + .flags(nozero | nonan).precision(2); + + avgPriorityDistance.init(_system->maxMasters()) + .name(name() + ".avgPriorityDistance") + .desc("Average QoS priority distance between assigned and " + "queued values").flags(nozero | nonan); + + priorityMinLatency.init(numPriorities()) + .name(name() + ".priorityMinLatency") + .desc("per QoS priority minimum request to response latency (s)") + .precision(12); + + priorityMaxLatency.init(numPriorities()) + .name(name() + ".priorityMaxLatency") + .desc("per QoS priority maximum request to response latency (s)") + .precision(12); + + numReadWriteTurnArounds.name(name() + ".numReadWriteTurnArounds") + .desc("Number of turnarounds from READ to WRITE"); + + numWriteReadTurnArounds.name(name() + ".numWriteReadTurnArounds") + .desc("Number of turnarounds from WRITE to READ"); + + numStayReadState.name(name() + ".numStayReadState") + .desc("Number of times bus staying in READ state"); + + numStayWriteState.name(name() + ".numStayWriteState") + .desc("Number of times bus staying in WRITE state"); + + for (int i = 0; i < _system->maxMasters(); i++) { + const std::string master = _system->getMasterName(i); + avgPriority.subname(i, master); + avgPriorityDistance.subname(i, master); + } + + for (int j = 0; j < numPriorities(); ++j) { + priorityMinLatency.subname(j, std::to_string(j)); + priorityMaxLatency.subname(j, std::to_string(j)); + } + + if (policy) + policy->regStats(); +} + +void +MemCtrl::recordTurnaroundStats() +{ + if (busStateNext != busState) { + if (busState == READ) { + numWriteReadTurnArounds++; + } else if (busState == WRITE) { + numReadWriteTurnArounds++; + } + } else { + if (busState == READ) { + numStayReadState++; + } else if (busState == WRITE) { + numStayWriteState++; + } + } +} + +} // namespace QoS |