# -*- 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.
#
DebugFlag("MemChecker")
DebugFlag("MemCheckerMonitor")
+DebugFlag("QOS")
*/
std::vector<bool> bytesValid;
+ // Quality of Service priority value
+ uint8_t _qosValue;
+
public:
/**
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.)
* 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()) {
*/
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()) {
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),
--- /dev/null
+# 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")
--- /dev/null
+# 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'
--- /dev/null
+# 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
--- /dev/null
+# 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')
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+/*
+ * 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__ */