2 * Copyright (c) 2017-2018 ARM Limited
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder. You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
14 * Redistribution and use in source and binary forms, with or without
15 * modification, are permitted provided that the following conditions are
16 * met: redistributions of source code must retain the above copyright
17 * notice, this list of conditions and the following disclaimer;
18 * redistributions in binary form must reproduce the above copyright
19 * notice, this list of conditions and the following disclaimer in the
20 * documentation and/or other materials provided with the distribution;
21 * neither the name of the copyright holders nor the names of its
22 * contributors may be used to endorse or promote products derived from
23 * this software without specific prior written permission.
25 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
26 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
27 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
28 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
29 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
30 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
31 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
35 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37 * Authors: Matteo Andreozzi
40 #include "mem_ctrl.hh"
42 #include "turnaround_policy.hh"
46 MemCtrl::MemCtrl(const QoSMemCtrlParams
* p
)
48 policy(p
->qos_policy
),
49 turnPolicy(p
->qos_turnaround_policy
),
50 queuePolicy(QueuePolicy::create(p
)),
51 _numPriorities(p
->qos_priorities
),
52 qosPriorityEscalation(p
->qos_priority_escalation
),
53 qosSyncroScheduler(p
->qos_syncro_scheduler
),
54 totalReadQueueSize(0), totalWriteQueueSize(0),
55 busState(READ
), busStateNext(READ
)
57 // Set the priority policy
59 policy
->setMemCtrl(this);
62 // Set the queue priority policy
64 queuePolicy
->setMemCtrl(this);
67 // Set the bus turnaround policy
69 turnPolicy
->setMemCtrl(this);
72 readQueueSizes
.resize(_numPriorities
);
73 writeQueueSizes
.resize(_numPriorities
);
74 serviceTick
.resize(_numPriorities
);
83 AbstractMemory::init();
87 MemCtrl::logRequest(BusState dir
, MasterID m_id
, uint8_t qos
,
88 Addr addr
, uint64_t entries
)
90 // If needed, initialize all counters and statistics
95 "QoSMemCtrl::logRequest MASTER %s [id %d] address %d"
96 " prio %d this master q packets %d"
97 " - queue size %d - requested entries %d\n",
98 masters
[m_id
], m_id
, addr
, qos
, packetPriorities
[m_id
][qos
],
99 (dir
== READ
) ? readQueueSizes
[qos
]: writeQueueSizes
[qos
],
103 readQueueSizes
[qos
] += entries
;
104 totalReadQueueSize
+= entries
;
105 } else if (dir
== WRITE
) {
106 writeQueueSizes
[qos
] += entries
;
107 totalWriteQueueSize
+= entries
;
110 packetPriorities
[m_id
][qos
] += entries
;
111 for (auto j
= 0; j
< entries
; ++j
) {
112 requestTimes
[m_id
][addr
].push_back(curTick());
116 avgPriority
[m_id
].sample(qos
);
118 // Compute avg priority distance
120 for (uint8_t i
= 0; i
< packetPriorities
[m_id
].size(); ++i
) {
122 (abs(int(qos
) - int(i
))) * packetPriorities
[m_id
][i
];
125 avgPriorityDistance
[m_id
].sample(distance
);
127 "QoSMemCtrl::logRequest MASTER %s [id %d]"
128 " registering priority distance %d for priority %d"
130 masters
[m_id
], m_id
, distance
, i
,
131 packetPriorities
[m_id
][i
]);
136 "QoSMemCtrl::logRequest MASTER %s [id %d] prio %d "
137 "this master q packets %d - new queue size %d\n",
138 masters
[m_id
], m_id
, qos
, packetPriorities
[m_id
][qos
],
139 (dir
== READ
) ? readQueueSizes
[qos
]: writeQueueSizes
[qos
]);
144 MemCtrl::logResponse(BusState dir
, MasterID m_id
, uint8_t qos
,
145 Addr addr
, uint64_t entries
, double delay
)
147 panic_if(!hasMaster(m_id
),
148 "Logging response with invalid master\n");
151 "QoSMemCtrl::logResponse MASTER %s [id %d] address %d prio"
152 " %d this master q packets %d"
153 " - queue size %d - requested entries %d\n",
154 masters
[m_id
], m_id
, addr
, qos
, packetPriorities
[m_id
][qos
],
155 (dir
== READ
) ? readQueueSizes
[qos
]: writeQueueSizes
[qos
],
159 readQueueSizes
[qos
] -= entries
;
160 totalReadQueueSize
-= entries
;
161 } else if (dir
== WRITE
) {
162 writeQueueSizes
[qos
] -= entries
;
163 totalWriteQueueSize
-= entries
;
166 panic_if(packetPriorities
[m_id
][qos
] == 0,
167 "QoSMemCtrl::logResponse master %s negative packets for priority"
168 " %d", masters
[m_id
], qos
);
170 packetPriorities
[m_id
][qos
] -= entries
;
172 for (auto j
= 0; j
< entries
; ++j
) {
173 auto it
= requestTimes
[m_id
].find(addr
);
174 panic_if(it
== requestTimes
[m_id
].end(),
175 "QoSMemCtrl::logResponse master %s unmatched response for"
176 " address %d received", masters
[m_id
], addr
);
179 uint64_t requestTime
= it
->second
.front();
181 // Remove request entry
182 it
->second
.pop_front();
184 // Remove whole address entry if last one
185 if (it
->second
.empty()) {
186 requestTimes
[m_id
].erase(it
);
189 double latency
= (double) (curTick() + delay
- requestTime
)
190 / SimClock::Float::s
;
193 // Record per-priority latency stats
194 if (priorityMaxLatency
[qos
].value() < latency
) {
195 priorityMaxLatency
[qos
] = latency
;
198 if (priorityMinLatency
[qos
].value() > latency
199 || priorityMinLatency
[qos
].value() == 0) {
200 priorityMinLatency
[qos
] = latency
;
206 "QoSMemCtrl::logResponse MASTER %s [id %d] prio %d "
207 "this master q packets %d - new queue size %d\n",
208 masters
[m_id
], m_id
, qos
, packetPriorities
[m_id
][qos
],
209 (dir
== READ
) ? readQueueSizes
[qos
]: writeQueueSizes
[qos
]);
213 MemCtrl::schedule(MasterID m_id
, uint64_t data
)
216 return policy
->schedule(m_id
, data
);
219 "QoSScheduler::schedule master ID [%d] "
220 "data received [%d], but QoS scheduler not initialized\n",
227 MemCtrl::schedule(const PacketPtr pkt
)
232 return schedule(pkt
->req
->masterId(), pkt
->getSize());
234 DPRINTF(QOS
, "QoSScheduler::schedule Packet received [Qv %d], "
235 "but QoS scheduler not initialized\n",
237 return pkt
->qosValue();
242 MemCtrl::selectNextBusState()
244 auto bus_state
= getBusState();
248 "QoSMemoryTurnaround::selectBusState running policy %s\n",
251 bus_state
= turnPolicy
->selectBusState();
254 "QoSMemoryTurnaround::selectBusState running "
255 "default bus direction selection policy\n");
257 if ((!getTotalReadQueueSize() && bus_state
== MemCtrl::READ
) ||
258 (!getTotalWriteQueueSize() && bus_state
== MemCtrl::WRITE
)) {
259 // READ/WRITE turnaround
260 bus_state
= (bus_state
== MemCtrl::READ
) ? MemCtrl::WRITE
:
270 MemCtrl::addMaster(MasterID m_id
)
272 if (!hasMaster(m_id
)) {
273 masters
.emplace(m_id
, _system
->getMasterName(m_id
));
274 packetPriorities
[m_id
].resize(numPriorities(), 0);
277 "QoSMemCtrl::addMaster registering"
278 " Master %s [id %d]\n",
279 masters
[m_id
], m_id
);
286 AbstractMemory::regStats();
288 using namespace Stats
;
290 // Initializes per master statistics
291 avgPriority
.init(_system
->maxMasters()).name(name() + ".avgPriority")
292 .desc("Average QoS priority value for accepted requests")
293 .flags(nozero
| nonan
).precision(2);
295 avgPriorityDistance
.init(_system
->maxMasters())
296 .name(name() + ".avgPriorityDistance")
297 .desc("Average QoS priority distance between assigned and "
298 "queued values").flags(nozero
| nonan
);
300 priorityMinLatency
.init(numPriorities())
301 .name(name() + ".priorityMinLatency")
302 .desc("per QoS priority minimum request to response latency (s)")
305 priorityMaxLatency
.init(numPriorities())
306 .name(name() + ".priorityMaxLatency")
307 .desc("per QoS priority maximum request to response latency (s)")
310 numReadWriteTurnArounds
.name(name() + ".numReadWriteTurnArounds")
311 .desc("Number of turnarounds from READ to WRITE");
313 numWriteReadTurnArounds
.name(name() + ".numWriteReadTurnArounds")
314 .desc("Number of turnarounds from WRITE to READ");
316 numStayReadState
.name(name() + ".numStayReadState")
317 .desc("Number of times bus staying in READ state");
319 numStayWriteState
.name(name() + ".numStayWriteState")
320 .desc("Number of times bus staying in WRITE state");
322 for (int i
= 0; i
< _system
->maxMasters(); i
++) {
323 const std::string master
= _system
->getMasterName(i
);
324 avgPriority
.subname(i
, master
);
325 avgPriorityDistance
.subname(i
, master
);
328 for (int j
= 0; j
< numPriorities(); ++j
) {
329 priorityMinLatency
.subname(j
, std::to_string(j
));
330 priorityMaxLatency
.subname(j
, std::to_string(j
));
335 MemCtrl::recordTurnaroundStats()
337 if (busStateNext
!= busState
) {
338 if (busState
== READ
) {
339 numWriteReadTurnArounds
++;
340 } else if (busState
== WRITE
) {
341 numReadWriteTurnArounds
++;
344 if (busState
== READ
) {
346 } else if (busState
== WRITE
) {