diff options
-rw-r--r-- | src/mem/SConscript | 15 | ||||
-rw-r--r-- | src/mem/packet.hh | 31 | ||||
-rw-r--r-- | src/mem/qos/QoSMemCtrl.py | 81 | ||||
-rw-r--r-- | src/mem/qos/QoSPolicy.py | 45 | ||||
-rw-r--r-- | src/mem/qos/QoSTurnaround.py | 45 | ||||
-rw-r--r-- | src/mem/qos/SConscript | 46 | ||||
-rw-r--r-- | src/mem/qos/mem_ctrl.cc | 355 | ||||
-rw-r--r-- | src/mem/qos/mem_ctrl.hh | 514 | ||||
-rw-r--r-- | src/mem/qos/policy.cc | 57 | ||||
-rw-r--r-- | src/mem/qos/policy.hh | 131 | ||||
-rw-r--r-- | src/mem/qos/q_policy.cc | 147 | ||||
-rw-r--r-- | src/mem/qos/q_policy.hh | 188 | ||||
-rw-r--r-- | src/mem/qos/turnaround_policy.hh | 80 |
13 files changed, 1731 insertions, 4 deletions
diff --git a/src/mem/SConscript b/src/mem/SConscript index 7c0d426d7..b9d5672a6 100644 --- a/src/mem/SConscript +++ b/src/mem/SConscript @@ -1,5 +1,17 @@ # -*- mode:python -*- - +# +# Copyright (c) 2018 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. +# # Copyright (c) 2006 The Regents of The University of Michigan # All rights reserved. # @@ -110,3 +122,4 @@ DebugFlag('SerialLink') DebugFlag("MemChecker") DebugFlag("MemCheckerMonitor") +DebugFlag("QOS") diff --git a/src/mem/packet.hh b/src/mem/packet.hh index 36a46438a..0f45a7bae 100644 --- a/src/mem/packet.hh +++ b/src/mem/packet.hh @@ -347,6 +347,9 @@ class Packet : public Printable */ std::vector<bool> bytesValid; + // Quality of Service priority value + uint8_t _qosValue; + public: /** @@ -670,6 +673,25 @@ class Packet : public Printable bool isBlockCached() const { return flags.isSet(BLOCK_CACHED); } void clearBlockCached() { flags.clear(BLOCK_CACHED); } + /** + * QoS Value getter + * Returns 0 if QoS value was never set (constructor default). + * + * @return QoS priority value of the packet + */ + inline uint8_t qosValue() const { return _qosValue; } + + /** + * QoS Value setter + * Interface for setting QoS priority value of the packet. + * + * @param qos_value QoS priority value + */ + inline void qosValue(const uint8_t qos_value) + { _qosValue = qos_value; } + + inline MasterID masterId() const { return req->masterId(); } + // Network error conditions... encapsulate them as methods since // their encoding keeps changing (from result field to command // field, etc.) @@ -746,8 +768,9 @@ class Packet : public Printable * not be valid. The command must be supplied. */ Packet(const RequestPtr &_req, MemCmd _cmd) - : cmd(_cmd), id((PacketId)_req.get()), req(_req), data(nullptr), - addr(0), _isSecure(false), size(0), headerDelay(0), snoopDelay(0), + : cmd(_cmd), id((PacketId)_req.get()), req(_req), + data(nullptr), addr(0), _isSecure(false), size(0), + _qosValue(0), headerDelay(0), snoopDelay(0), payloadDelay(0), senderState(NULL) { if (req->hasPaddr()) { @@ -768,7 +791,8 @@ class Packet : public Printable */ Packet(const RequestPtr &_req, MemCmd _cmd, int _blkSize, PacketId _id = 0) : cmd(_cmd), id(_id ? _id : (PacketId)_req.get()), req(_req), - data(nullptr), addr(0), _isSecure(false), headerDelay(0), + data(nullptr), addr(0), _isSecure(false), + _qosValue(0), headerDelay(0), snoopDelay(0), payloadDelay(0), senderState(NULL) { if (req->hasPaddr()) { @@ -792,6 +816,7 @@ class Packet : public Printable data(nullptr), addr(pkt->addr), _isSecure(pkt->_isSecure), size(pkt->size), bytesValid(pkt->bytesValid), + _qosValue(pkt->qosValue()), headerDelay(pkt->headerDelay), snoopDelay(0), payloadDelay(pkt->payloadDelay), diff --git a/src/mem/qos/QoSMemCtrl.py b/src/mem/qos/QoSMemCtrl.py new file mode 100644 index 000000000..185856553 --- /dev/null +++ b/src/mem/qos/QoSMemCtrl.py @@ -0,0 +1,81 @@ +# Copyright (c) 2018 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 + +from m5.params import * +from AbstractMemory import AbstractMemory +from QoSTurnaround import * + +# QoS Queue Selection policy used to select packets among same-QoS queues +class QoSQPolicy(Enum): vals = ["fifo", "lifo", "lrg"] + +class QoSMemCtrl(AbstractMemory): + type = 'QoSMemCtrl' + cxx_header = "mem/qos/mem_ctrl.hh" + cxx_class = 'QoS::MemCtrl' + abstract = True + + ##### QoS support parameters #### + + # Number of priorities in the system + qos_priorities = Param.Unsigned(1, "QoS priorities") + + # QoS scheduler policy: tags request with QoS priority value + qos_policy = Param.QoSPolicy(NULL, + "Memory Controller Requests QoS arbitration policy") + + # Select QoS driven turnaround policy + # (direction switch triggered by highest priority buffer content) + qos_turnaround_policy = Param.QoSTurnaroundPolicy(NULL, + "Selects QoS driven turnaround policy") + + # QoS Queue Select policy: selects packets among same priority level + # (only supported in QoSMemSinkCtrl) + qos_q_policy = Param.QoSQPolicy('fifo', + "Memory Controller Requests same-QoS selection policy") + + # flag to select QoS syncronised scheduling + # (calls the scheduler on all masters at every packet arrival) + qos_syncro_scheduler = Param.Bool(False, + "Enables QoS syncronized scheduling") + + # flag to enable QoS priority escalation + qos_priority_escalation = Param.Bool(False, + "Enables QoS priority escalation") + + # Master ID to be mapped to service parameters in QoS schedulers + qos_masters = VectorParam.String(['']* 16, + "Master Names to be mapped to service parameters in QoS scheduler") diff --git a/src/mem/qos/QoSPolicy.py b/src/mem/qos/QoSPolicy.py new file mode 100644 index 000000000..f2218a725 --- /dev/null +++ b/src/mem/qos/QoSPolicy.py @@ -0,0 +1,45 @@ +# Copyright (c) 2018 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: Giacomo Travaglini + +from m5.SimObject import * + +# QoS scheduler policy used to serve incoming transaction +class QoSPolicy(SimObject): + type = 'QoSPolicy' + abstract = True + cxx_header = "mem/qos/policy.hh" + cxx_class = 'QoS::Policy' diff --git a/src/mem/qos/QoSTurnaround.py b/src/mem/qos/QoSTurnaround.py new file mode 100644 index 000000000..8f9c94296 --- /dev/null +++ b/src/mem/qos/QoSTurnaround.py @@ -0,0 +1,45 @@ +# Copyright (c) 2018 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: Giacomo Travaglini + +from m5.SimObject import SimObject + +#QoS Turnaround policy used to select bus state - READ or WRITE +class QoSTurnaroundPolicy(SimObject): + type = 'QoSTurnaroundPolicy' + cxx_header = "mem/qos/turnaround_policy.hh" + cxx_class = 'QoS::TurnaroundPolicy' + abstract = True diff --git a/src/mem/qos/SConscript b/src/mem/qos/SConscript new file mode 100644 index 000000000..9d44337ab --- /dev/null +++ b/src/mem/qos/SConscript @@ -0,0 +1,46 @@ +# Copyright (c) 2018 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: Giacomo Travaglini + +Import('*') + +SimObject('QoSMemCtrl.py') +SimObject('QoSPolicy.py') +SimObject('QoSTurnaround.py') + +Source('policy.cc') +Source('q_policy.cc') +Source('mem_ctrl.cc') 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 diff --git a/src/mem/qos/mem_ctrl.hh b/src/mem/qos/mem_ctrl.hh new file mode 100644 index 000000000..db85f276d --- /dev/null +++ b/src/mem/qos/mem_ctrl.hh @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2018 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 "debug/QOS.hh" +#include "mem/abstract_mem.hh" +#include "mem/qos/q_policy.hh" +#include "mem/qos/policy.hh" +#include "params/QoSMemCtrl.hh" +#include "sim/system.hh" + +#include <unordered_map> +#include <vector> +#include <deque> + +#ifndef __MEM_QOS_MEM_CTRL_HH__ +#define __MEM_QOS_MEM_CTRL_HH__ + +namespace QoS { + +/** + * The QoS::MemCtrl is a base class for Memory objects + * which support QoS - it provides access to a set of QoS + * scheduling policies + */ +class MemCtrl: public AbstractMemory +{ + public: + /** Bus Direction */ + enum BusState { READ, WRITE }; + + protected: + /** QoS Policy, assigns QoS priority to the incoming packets */ + const std::unique_ptr<Policy> policy; + + /** QoS Bus Turnaround Policy: selects the bus direction (READ/WRITE) */ + const std::unique_ptr<TurnaroundPolicy> turnPolicy; + + /** QoS Queue Policy: selects packet among same-priority queue */ + const std::unique_ptr<QueuePolicy> queuePolicy; + + /** Number of configured QoS priorities */ + const uint8_t _numPriorities; + + /** Enables QoS priority escalation */ + const bool qosPriorityEscalation; + + /** + * Enables QoS synchronized scheduling invokes the QoS scheduler + * on all masters, at every packet arrival. + */ + const bool qosSyncroScheduler; + + /** Hash of master ID - master name */ + std::unordered_map<MasterID, const std::string> masters; + + /** Hash of masters - number of packets queued per priority */ + std::unordered_map<MasterID, std::vector<uint64_t> > packetPriorities; + + /** Hash of masters - address of request - queue of times of request */ + std::unordered_map<MasterID, + std::unordered_map<uint64_t, std::deque<uint64_t>> > requestTimes; + + /** + * Vector of QoS priorities/last service time. Refreshed at every + * qosSchedule call. + */ + std::vector<Tick> serviceTick; + + /** Read request packets queue length in #packets, per QoS priority */ + std::vector<uint64_t> readQueueSizes; + + /** Write request packets queue length in #packets, per QoS priority */ + std::vector<uint64_t> writeQueueSizes; + + /** Total read request packets queue length in #packets */ + uint64_t totalReadQueueSize; + + /** Total write request packets queue length in #packets */ + uint64_t totalWriteQueueSize; + + /** + * Bus state used to control the read/write switching and drive + * the scheduling of the next request. + */ + BusState busState; + + /** bus state for next request event triggered */ + BusState busStateNext; + + /** per-master average QoS priority */ + Stats::VectorStandardDeviation avgPriority; + /** per-master average QoS distance between assigned and queued values */ + Stats::VectorStandardDeviation avgPriorityDistance; + + /** per-priority minimum latency */ + Stats::Vector priorityMinLatency; + /** per-priority maximum latency */ + Stats::Vector priorityMaxLatency; + /** Count the number of turnarounds READ to WRITE */ + Stats::Scalar numReadWriteTurnArounds; + /** Count the number of turnarounds WRITE to READ */ + Stats::Scalar numWriteReadTurnArounds; + /** Count the number of times bus staying in READ state */ + Stats::Scalar numStayReadState; + /** Count the number of times bus staying in WRITE state */ + Stats::Scalar numStayWriteState; + + /** registers statistics */ + void regStats() override; + + /** + * Initializes dynamically counters and + * statistics for a given Master + * + * @param m_id the master ID + */ + void addMaster(const MasterID m_id); + + /** + * Called upon receiving a request or + * updates statistics and updates queues status + * + * @param dir request direction + * @param m_id master id + * @param qos packet qos value + * @param addr packet address + * @param entries number of entries to record + */ + void logRequest(BusState dir, MasterID m_id, uint8_t qos, + Addr addr, uint64_t entries); + + /** + * Called upon receiving a response, + * updates statistics and updates queues status + * + * @param dir response direction + * @param m_id master id + * @param qos packet qos value + * @param addr packet address + * @param entries number of entries to record + * @param delay response delay + */ + void logResponse(BusState dir, MasterID m_id, uint8_t qos, + Addr addr, uint64_t entries, double delay); + + /** + * Assign priority to a packet by executing + * the configured QoS policy. + * + * @param queues_ptr list of pointers to packet queues + * @param queue_entry_size size in bytes per each packet in the queue + * @param pkt pointer to the Packet + * @return a QoS priority value + */ + template<typename Queues> + uint8_t qosSchedule(std::initializer_list<Queues*> queues_ptr, + uint64_t queue_entry_size, const PacketPtr pkt); + + using SimObject::schedule; + uint8_t schedule(MasterID m_id, uint64_t data); + uint8_t schedule(const PacketPtr pkt); + + /** + * Returns next bus direction (READ or WRITE) + * based on configured policy. + */ + BusState selectNextBusState(); + + /** + * Set current bus direction (READ or WRITE) + * from next selected one + */ + void setCurrentBusState() { busState = busStateNext; } + + /** + * Record statistics on turnarounds based on + * busStateNext and busState values + */ + void recordTurnaroundStats(); + + /** + * Escalates/demotes priority of all packets + * belonging to the passed master to given + * priority value + * + * @param queues list of pointers to packet queues + * @param queue_entry_size size of an entry in the queue + * @param m_id master whose packets priority will change + * @param tgt_prio target priority value + */ + template<typename Queues> + void escalate(std::initializer_list<Queues*> queues, + uint64_t queue_entry_size, + MasterID m_id, uint8_t tgt_prio); + + /** + * Escalates/demotes priority of all packets + * belonging to the passed master to given + * priority value in a specified cluster of queues + * (e.g. read queues or write queues) which is passed + * as an argument to the function. + * The curr_prio/tgt_prio parameters are queue selectors in the + * queue cluster. + * + * @param queues reference to packet queues + * @param queue_entry_size size of an entry in the queue + * @param m_id master whose packets priority will change + * @param curr_prio source queue priority value + * @param tgt_prio target queue priority value + */ + template<typename Queues> + void escalateQueues(Queues& queues, uint64_t queue_entry_size, + MasterID m_id, uint8_t curr_prio, uint8_t tgt_prio); + + public: + /** + * QoS Memory base class + * + * @param p pointer to QoSMemCtrl parameters + */ + MemCtrl(const QoSMemCtrlParams*); + + virtual ~MemCtrl(); + + /** + * Initializes this object + */ + void init() override; + + /** + * Gets the current bus state + * + * @return current bus state + */ + BusState getBusState() const { return busState; } + + /** + * Gets the next bus state + * + * @return next bus state + */ + BusState getBusStateNext() const { return busStateNext; } + + /** + * hasMaster returns true if the selected master(ID) has + * been registered in the memory controller, which happens if + * the memory controller has received at least a packet from + * that master. + * + * @param m_id master id to lookup + * @return true if the memory controller has received a packet + * from the master, false otherwise. + */ + bool hasMaster(MasterID m_id) const + { + return masters.find(m_id) != masters.end(); + } + + /** + * Gets a READ queue size + * + * @param prio QoS Priority of the queue + * @return queue size in packets + */ + uint64_t getReadQueueSize(const uint8_t prio) const + { return readQueueSizes[prio]; } + + /** + * Gets a WRITE queue size + * + * @param prio QoS Priority of the queue + * @return queue size in packets + */ + uint64_t getWriteQueueSize(const uint8_t prio) const + { return writeQueueSizes[prio]; } + + /** + * Gets the total combined READ queues size + * + * @return total queues size in packets + */ + uint64_t getTotalReadQueueSize() const { return totalReadQueueSize; } + + /** + * Gets the total combined WRITE queues size + * + * @return total queues size in packets + */ + uint64_t getTotalWriteQueueSize() const { return totalWriteQueueSize; } + + /** + * Gets the last service tick related to a QoS Priority + * + * @param prio QoS Priority + * @return tick + */ + Tick getServiceTick(const uint8_t prio) const { return serviceTick[prio]; } + + /** + * Gets the total number of priority levels in the + * QoS memory controller. + * + * @return total number of priority levels + */ + uint8_t numPriorities() const { return _numPriorities; } +}; + +template<typename Queues> +void +MemCtrl::escalateQueues(Queues& queues, uint64_t queue_entry_size, + MasterID m_id, uint8_t curr_prio, uint8_t tgt_prio) +{ + auto it = queues[curr_prio].begin(); + while (it != queues[curr_prio].end()) { + // No packets left to move + if (packetPriorities[m_id][curr_prio] == 0) + break; + + auto pkt = *it; + + DPRINTF(QOS, + "QoSMemCtrl::escalate checking priority %d packet " + "m_id %d address %d\n", curr_prio, + pkt->masterId(), pkt->getAddr()); + + // Found a packet to move + if (pkt->masterId() == m_id) { + + uint64_t moved_entries = divCeil(pkt->getSize(), + queue_entry_size); + + DPRINTF(QOS, + "QoSMemCtrl::escalate Master %s [id %d] moving " + "packet addr %d size %d (p size %d) from priority %d " + "to priority %d - " + "this master packets %d (entries to move %d)\n", + masters[m_id], m_id, pkt->getAddr(), + pkt->getSize(), + queue_entry_size, curr_prio, tgt_prio, + packetPriorities[m_id][curr_prio], moved_entries); + + + if (pkt->isRead()) { + panic_if(readQueueSizes[curr_prio] < moved_entries, + "QoSMemCtrl::escalate master %s negative READ " + "packets for priority %d", + masters[m_id], tgt_prio); + readQueueSizes[curr_prio] -= moved_entries; + readQueueSizes[tgt_prio] += moved_entries; + } else if (pkt->isWrite()) { + panic_if(writeQueueSizes[curr_prio] < moved_entries, + "QoSMemCtrl::escalate master %s negative WRITE " + "packets for priority %d", + masters[m_id], tgt_prio); + writeQueueSizes[curr_prio] -= moved_entries; + writeQueueSizes[tgt_prio] += moved_entries; + } + + // Change QoS priority and move packet + pkt->qosValue(tgt_prio); + queues[tgt_prio].push_back(pkt); + + // Erase element from source packet queue, this will + // increment the iterator + it = queues[curr_prio].erase(it); + panic_if(packetPriorities[m_id][curr_prio] < moved_entries, + "QoSMemCtrl::escalate master %s negative packets " + "for priority %d", + masters[m_id], tgt_prio); + + packetPriorities[m_id][curr_prio] -= moved_entries; + packetPriorities[m_id][tgt_prio] += moved_entries; + } else { + // Increment iterator to next location in the queue + it++; + } + } +} + +template<typename Queues> +void +MemCtrl::escalate(std::initializer_list<Queues*> queues, + uint64_t queue_entry_size, + MasterID m_id, uint8_t tgt_prio) +{ + // If needed, initialize all counters and statistics + // for this master + addMaster(m_id); + + DPRINTF(QOS, + "QoSMemCtrl::escalate Master %s [id %d] to priority " + "%d (currently %d packets)\n",masters[m_id], m_id, tgt_prio, + packetPriorities[m_id][tgt_prio]); + + for (uint8_t curr_prio = 0; curr_prio < numPriorities(); ++curr_prio) { + // Skip target priority + if (curr_prio == tgt_prio) + continue; + + // Process other priority packet + while (packetPriorities[m_id][curr_prio] > 0) { + DPRINTF(QOS, + "QoSMemCtrl::escalate MID %d checking priority %d " + "(packets %d)- current packets in prio %d: %d\n" + "\t(source read %d source write %d target read %d, " + "target write %d)\n", + m_id, curr_prio, packetPriorities[m_id][curr_prio], + tgt_prio, packetPriorities[m_id][tgt_prio], + readQueueSizes[curr_prio], + writeQueueSizes[curr_prio], readQueueSizes[tgt_prio], + writeQueueSizes[tgt_prio]); + + // Check both read and write queue + for (auto q : queues) { + escalateQueues(*q, queue_entry_size, m_id, + curr_prio, tgt_prio); + } + } + } + + DPRINTF(QOS, + "QoSMemCtrl::escalate Completed master %s [id %d] to priority %d " + "(now %d packets)\n\t(total read %d, total write %d)\n", + masters[m_id], m_id, tgt_prio, packetPriorities[m_id][tgt_prio], + readQueueSizes[tgt_prio], writeQueueSizes[tgt_prio]); +} + +template<typename Queues> +uint8_t +MemCtrl::qosSchedule(std::initializer_list<Queues*> queues, + const uint64_t queue_entry_size, + const PacketPtr pkt) +{ + // Schedule packet. + uint8_t pkt_priority = schedule(pkt); + + assert(pkt_priority < numPriorities()); + + pkt->qosValue(pkt_priority); + + if (qosSyncroScheduler) { + // Call the scheduling function on all other masters. + for (const auto& m : masters) { + + if (m.first == pkt->masterId()) + continue; + + uint8_t prio = schedule(m.first, 0); + + if (qosPriorityEscalation) { + DPRINTF(QOS, + "QoSMemCtrl::qosSchedule: (syncro) escalating " + "MASTER %s to assigned priority %d\n", + _system->getMasterName(m.first), + prio); + escalate(queues, queue_entry_size, m.first, prio); + } + } + } + + if (qosPriorityEscalation) { + DPRINTF(QOS, + "QoSMemCtrl::qosSchedule: escalating " + "MASTER %s to assigned priority %d\n", + _system->getMasterName(pkt->masterId()), + pkt_priority); + escalate(queues, queue_entry_size, pkt->masterId(), pkt_priority); + } + + // Update last service tick for selected priority + serviceTick[pkt_priority] = curTick(); + + return pkt_priority; +} + +} // namespace QoS + +#endif /* __MEM_QOS_MEM_CTRL_HH__ */ diff --git a/src/mem/qos/policy.cc b/src/mem/qos/policy.cc new file mode 100644 index 000000000..b5431d283 --- /dev/null +++ b/src/mem/qos/policy.cc @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2018 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. + * + * Author: Matteo Andreozzi + */ + +#include "policy.hh" + +namespace QoS { + +Policy::Policy(const Params* p) + : SimObject(p) +{} + +Policy::~Policy() {} + +uint8_t +Policy::schedule(const PacketPtr pkt) +{ + assert(pkt->req); + return schedule(pkt->req->masterId(), pkt->getSize()); +} + +} // namespace QoS diff --git a/src/mem/qos/policy.hh b/src/mem/qos/policy.hh new file mode 100644 index 000000000..3ffe4811d --- /dev/null +++ b/src/mem/qos/policy.hh @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2018 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. + * + * Author: Matteo Andreozzi + */ + +#ifndef __MEM_QOS_POLICY_HH__ +#define __MEM_QOS_POLICY_HH__ + +#include "base/trace.hh" +#include "debug/QOS.hh" +#include "mem/qos/mem_ctrl.hh" +#include "mem/packet.hh" +#include "sim/system.hh" + +namespace QoS { + +/** + * QoS Policy base class + * + * QoS Policy base class: all QoS policies derive from this class to + * implement specific QoS scheduling algorithms + * + */ +class Policy : public SimObject +{ + public: + using Params = QoSPolicyParams; + Policy(const Params* p); + + virtual ~Policy(); + + virtual void regStats() override {}; + + virtual void init() override {}; + + /** + * Setting a pointer to the Memory Controller implementing + * the policy. + */ + void setMemCtrl(MemCtrl* mem) { memCtrl = mem; }; + + /** + * Builds a MasterID/value pair given a master input. + * This will be lookuped in the system list of masters in order + * to retrieve the associated MasterID. + * In case the master name/object cannot be resolved, the pairing + * method will panic. + * + * @param master Master to lookup in the system + * @param value Value to be associated with the MasterID + * @return A MasterID/Value pair. + */ + template <typename M, typename T> + std::pair<MasterID, T> pair(M master, T value); + + /** + * Schedules data - must be defined by derived class + * + * @param mId master id to schedule + * @param data data to schedule + * @return QoS priority value + */ + virtual uint8_t schedule(const MasterID mId, const uint64_t data) = 0; + + /** + * Schedules a packet. Non virtual interface for the scheduling + * method requiring a master ID. + * + * @param pkt pointer to packet to schedule + * @return QoS priority value + */ + uint8_t schedule(const PacketPtr pkt); + + protected: + /** Pointer to parent memory controller implementing the policy */ + MemCtrl* memCtrl; +}; + +template <typename M, typename T> +std::pair<MasterID, T> +Policy::pair(M master, T value) +{ + auto id = memCtrl->system()->lookupMasterId(master); + + panic_if(id == Request::invldMasterId, + "Unable to find master %s\n", master); + + DPRINTF(QOS, + "Master %s [id %d] associated with QoS data %d\n", + master, id, value); + + return std::pair<MasterID, T>(id, value); +} + +} // namespace QoS + +#endif /* __MEM_QOS_POLICY_HH__ */ diff --git a/src/mem/qos/q_policy.cc b/src/mem/qos/q_policy.cc new file mode 100644 index 000000000..88ce95d0a --- /dev/null +++ b/src/mem/qos/q_policy.cc @@ -0,0 +1,147 @@ +/* + * Copyright (c) 2018 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. + * + * Author: Matteo Andreozzi + */ + +#include "mem/qos/q_policy.hh" + +#include <unordered_map> +#include <utility> + +#include "debug/QOS.hh" +#include "enums/QoSQPolicy.hh" +#include "mem/qos/mem_ctrl.hh" + +namespace QoS { + +QueuePolicy* +QueuePolicy::create(const QoSMemCtrlParams* p) +{ + switch (p->qos_q_policy) { + case Enums::QoSQPolicy::fifo: + return new FifoQueuePolicy(p); + case Enums::QoSQPolicy::lrg: + return new LrgQueuePolicy(p); + case Enums::QoSQPolicy::lifo: + default: + return new LifoQueuePolicy(p); + } +} + +QueuePolicy::PacketQueue::iterator +LrgQueuePolicy::selectPacket(PacketQueue* q) +{ + QueuePolicy::PacketQueue::iterator ret = q->end(); + + // Tracks one packet per master in the queue + std::unordered_map<MasterID, QueuePolicy::PacketQueue::iterator> track; + + // Cycle queue only once + for (auto pkt_it = q->begin(); pkt_it != q->end(); ++pkt_it) { + + const auto& pkt = *pkt_it; + + panic_if(!pkt->req, + "QoSQPolicy::lrg detected packet without request"); + + // Get Request MasterID + MasterID m_id = pkt->req->masterId(); + DPRINTF(QOS, "QoSQPolicy::lrg checking packet " + "from queue with id %d\n", m_id); + + // Check if this is a known master. + panic_if(memCtrl->hasMaster(m_id), + "%s: Unrecognized Master\n", __func__); + + panic_if(toServe.size() > 0, + "%s: toServe list is empty\n", __func__); + + if (toServe.front() == m_id) { + DPRINTF(QOS, "QoSQPolicy::lrg matched to served " + "master id %d\n", m_id); + // This packet matches the MasterID to be served next + // move toServe front to back + toServe.push_back(m_id); + toServe.pop_front(); + + return pkt_it; + } + + // The master generating the packet is not first in the toServe list + // (Doesn't have the highest priority among masters) + // Check if this is the first packet seen with its master ID + // and remember it. Then keep looping over the remaining packets + // in the queue. + if (track.find(m_id) == track.end()) { + track[m_id] = pkt_it; + DPRINTF(QOS, "QoSQPolicy::lrg tracking a packet for " + "master id %d\n", m_id); + } + } + + // If here, the current master to be serviced doesn't have a pending + // packet in the queue: look for the next master in the list. + for (const auto& masterId : toServe) { + DPRINTF(QOS, "QoSQPolicy::lrg evaluating alternative " + "master id %d\n", masterId); + + if (track.find(masterId) != track.end()) { + ret = track[masterId]; + DPRINTF(QOS, "QoSQPolicy::lrg master id " + "%d selected for service\n", masterId); + + return ret; + } + } + + DPRINTF(QOS, "QoSQPolicy::lrg no packet was serviced\n"); + + // Ret will be : packet to serve if any found or queue begin + // (end if queue is empty) + return ret; +} + +void +LrgQueuePolicy::enqueuePacket(PacketPtr pkt) +{ + MasterID m_id = pkt->masterId(); + if (!memCtrl->hasMaster(m_id)) { + toServe.push_back(m_id); + } +}; + +} // namespace QoS diff --git a/src/mem/qos/q_policy.hh b/src/mem/qos/q_policy.hh new file mode 100644 index 000000000..3e455e89c --- /dev/null +++ b/src/mem/qos/q_policy.hh @@ -0,0 +1,188 @@ +/* + * Copyright (c) 2018 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. + * + * Author: Matteo Andreozzi + */ + +#ifndef __MEM_QOS_Q_POLICY_HH__ +#define __MEM_QOS_Q_POLICY_HH__ + +#include <deque> +#include <unordered_set> + +#include "mem/packet.hh" +#include "params/QoSMemCtrl.hh" + +namespace QoS { + +class MemCtrl; + +/** + * QoS Queue Policy + * + * The QoS Queue Policy class implements algorithms to schedule packets + * within the same QoS priority queue + */ +class QueuePolicy +{ + public: + typedef std::deque<PacketPtr> PacketQueue; + + /** + * This factory method is used for generating the queue policy. It takes + * the memory controller params as an argument and returns the related + * QueuePolicy object. If no particular QueuePolicy has been specified in + * the QoSMemCtrlParams, the method will default to a LIFO queue policy. + * + * @param p QoS::MemCtrl parameter variable + * @return Pointer to the QueuePolicy + */ + static QueuePolicy* create(const QoSMemCtrlParams* p); + + /** + * This method is called by the memory controller after it enqueues a + * packet. It is a way for the queue policy to hook into the packet + * enqueuing and update relevant metadata. This will then be used once + * the QueuePolicy::selectPacket will be called. + * + * @param pkt Enqueued packet + */ + virtual void enqueuePacket(PacketPtr pkt) {}; + + /** + * Policy selector. + * The implementation of this virtual method selects the packet + * to be serviced from the packet queue passed as an argument. + * + * @param queue Packet queue + * @return Iterator pointing to the packet in the queue to be + * serviced + */ + virtual PacketQueue::iterator selectPacket(PacketQueue* queue) = 0; + + /** + * Setting a pointer to the Memory Controller implementing + * the policy. + */ + void setMemCtrl(MemCtrl* mem) { memCtrl = mem; }; + + protected: + QueuePolicy(const QoSMemCtrlParams* p) + : memCtrl(nullptr) + {} + + /** Pointer to parent memory controller implementing the policy */ + MemCtrl* memCtrl; +}; + +/** Last In First Out Queue Policy */ +class LifoQueuePolicy : public QueuePolicy +{ + public: + LifoQueuePolicy(const QoSMemCtrlParams* p) + : QueuePolicy(p) + {} + + /** + * Implements LIFO packet select policy + * + * @param queue The queue in which to select a packet + * @return Iterator to the selected packet + */ + PacketQueue::iterator + selectPacket(PacketQueue* queue) override + { + return queue->end(); + } +}; + +/** First In First Out Queue Policy */ +class FifoQueuePolicy : public QueuePolicy +{ + public: + FifoQueuePolicy(const QoSMemCtrlParams* p) + : QueuePolicy(p) + {} + + /** + * Implements FCFS packet select policy + * + * @param queue The queue in which to select a packet + * @return Iterator to the selected packet + */ + PacketQueue::iterator + selectPacket(PacketQueue* queue) override + { + return queue->begin(); + } +}; + +/** + * Least Recently Granted Queue Policy + * It selects packets from the queue with a round + * robin-like policy: using the master id as a switching + * parameter rather than switching over a time quantum. + */ +class LrgQueuePolicy : public QueuePolicy +{ + public: + LrgQueuePolicy(const QoSMemCtrlParams* p) + : QueuePolicy(p) + {} + + void enqueuePacket(PacketPtr pkt) override; + + /** + * Implements LRG packet select policy + * + * @param queue The queue in which to select a packet + * @return Iterator to the selected packet + */ + PacketQueue::iterator + selectPacket(PacketQueue* queue) override; + + protected: + /** + * Support structure for lrg algorithms: + * keeps track of serviced masters, + * always serve the front element. + */ + std::list<MasterID> toServe; +}; + +} // namespace QoS + +#endif /* __MEM_QOS_Q_POLICY_HH__ */ diff --git a/src/mem/qos/turnaround_policy.hh b/src/mem/qos/turnaround_policy.hh new file mode 100644 index 000000000..ffafd8fea --- /dev/null +++ b/src/mem/qos/turnaround_policy.hh @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2018 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 + */ + +#ifndef __MEM_QOS_TURNAROUND_POLICY_HH__ +#define __MEM_QOS_TURNAROUND_POLICY_HH__ + +#include "mem_ctrl.hh" + +namespace QoS { + +/** + * Base class for QoS Bus Turnaround policies + */ +class TurnaroundPolicy : public SimObject +{ + protected: + using Params = QoSTurnaroundPolicyParams; + + public: + TurnaroundPolicy(const Params* p) : SimObject(p) {}; + + virtual ~TurnaroundPolicy() {}; + + /** + * Setting a pointer to the Memory Controller implementing + * the turnaround policy. + */ + void setMemCtrl(MemCtrl* mem) { memCtrl = mem; }; + + /** + * Bus Selection function + * + * @return selected bus state + */ + virtual MemCtrl::BusState selectBusState() = 0; + + protected: + /** Pointer to container object */ + MemCtrl* memCtrl; +}; + +} // namespace QoS + +#endif /* __MEM_QOS_TURNAROUND_POLICY_HH__ */ |