From 66f80b5a731e2fac5d9e4f841804d87a1267b76a Mon Sep 17 00:00:00 2001 From: Matteo Andreozzi Date: Wed, 10 Jan 2018 13:38:47 +0000 Subject: [PATCH] mem: Add a QoS-aware Memory Controller type This is the implementation of QoS algorithms support for gem5 memory objects. This change-list provides a framework for specifying QoS algorithm which can be used to prioritise service to specific masters in the memory controller. The QoS support implemented here is designed to be extendable so that new QoS algorithms can be easily plugged into the memory controller as "QoS Policies". Change-Id: I0b611f13fce54dd1dd444eb806f8e98afd248bd5 Signed-off-by: Giacomo Travaglini Reviewed-on: https://gem5-review.googlesource.com/11970 Maintainer: Nikos Nikoleris Reviewed-by: Nikos Nikoleris --- src/mem/SConscript | 15 +- src/mem/packet.hh | 31 +- src/mem/qos/QoSMemCtrl.py | 81 +++++ src/mem/qos/QoSPolicy.py | 45 +++ src/mem/qos/QoSTurnaround.py | 45 +++ src/mem/qos/SConscript | 46 +++ src/mem/qos/mem_ctrl.cc | 355 +++++++++++++++++++++ src/mem/qos/mem_ctrl.hh | 514 +++++++++++++++++++++++++++++++ src/mem/qos/policy.cc | 57 ++++ src/mem/qos/policy.hh | 131 ++++++++ src/mem/qos/q_policy.cc | 147 +++++++++ src/mem/qos/q_policy.hh | 188 +++++++++++ src/mem/qos/turnaround_policy.hh | 80 +++++ 13 files changed, 1731 insertions(+), 4 deletions(-) create mode 100644 src/mem/qos/QoSMemCtrl.py create mode 100644 src/mem/qos/QoSPolicy.py create mode 100644 src/mem/qos/QoSTurnaround.py create mode 100644 src/mem/qos/SConscript create mode 100644 src/mem/qos/mem_ctrl.cc create mode 100644 src/mem/qos/mem_ctrl.hh create mode 100644 src/mem/qos/policy.cc create mode 100644 src/mem/qos/policy.hh create mode 100644 src/mem/qos/q_policy.cc create mode 100644 src/mem/qos/q_policy.hh create mode 100644 src/mem/qos/turnaround_policy.hh 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 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 +#include +#include + +#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; + + /** QoS Bus Turnaround Policy: selects the bus direction (READ/WRITE) */ + const std::unique_ptr turnPolicy; + + /** QoS Queue Policy: selects packet among same-priority queue */ + const std::unique_ptr 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 masters; + + /** Hash of masters - number of packets queued per priority */ + std::unordered_map > packetPriorities; + + /** Hash of masters - address of request - queue of times of request */ + std::unordered_map> > requestTimes; + + /** + * Vector of QoS priorities/last service time. Refreshed at every + * qosSchedule call. + */ + std::vector serviceTick; + + /** Read request packets queue length in #packets, per QoS priority */ + std::vector readQueueSizes; + + /** Write request packets queue length in #packets, per QoS priority */ + std::vector 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 + uint8_t qosSchedule(std::initializer_list 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 + void escalate(std::initializer_list 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 + 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 +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 +void +MemCtrl::escalate(std::initializer_list 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 +uint8_t +MemCtrl::qosSchedule(std::initializer_list 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 + std::pair 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 +std::pair +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(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 +#include + +#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 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 +#include + +#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 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 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__ */ -- 2.30.2