mem-cache: Add match functions to QueueEntry
[gem5.git] / src / mem / qos / mem_ctrl.cc
1 /*
2 * Copyright (c) 2017-2018 ARM Limited
3 * All rights reserved
4 *
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.
13 *
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.
24 *
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.
36 *
37 * Authors: Matteo Andreozzi
38 */
39
40 #include "mem_ctrl.hh"
41
42 #include "turnaround_policy.hh"
43
44 namespace QoS {
45
46 MemCtrl::MemCtrl(const QoSMemCtrlParams * p)
47 : AbstractMemory(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)
56 {
57 // Set the priority policy
58 if (policy) {
59 policy->setMemCtrl(this);
60 }
61
62 // Set the queue priority policy
63 if (queuePolicy) {
64 queuePolicy->setMemCtrl(this);
65 }
66
67 // Set the bus turnaround policy
68 if (turnPolicy) {
69 turnPolicy->setMemCtrl(this);
70 }
71
72 readQueueSizes.resize(_numPriorities);
73 writeQueueSizes.resize(_numPriorities);
74 serviceTick.resize(_numPriorities);
75 }
76
77 MemCtrl::~MemCtrl()
78 {}
79
80 void
81 MemCtrl::init()
82 {
83 AbstractMemory::init();
84 }
85
86 void
87 MemCtrl::logRequest(BusState dir, MasterID m_id, uint8_t qos,
88 Addr addr, uint64_t entries)
89 {
90 // If needed, initialize all counters and statistics
91 // for this master
92 addMaster(m_id);
93
94 DPRINTF(QOS,
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],
100 entries);
101
102 if (dir == READ) {
103 readQueueSizes[qos] += entries;
104 totalReadQueueSize += entries;
105 } else if (dir == WRITE) {
106 writeQueueSizes[qos] += entries;
107 totalWriteQueueSize += entries;
108 }
109
110 packetPriorities[m_id][qos] += entries;
111 for (auto j = 0; j < entries; ++j) {
112 requestTimes[m_id][addr].push_back(curTick());
113 }
114
115 // Record statistics
116 avgPriority[m_id].sample(qos);
117
118 // Compute avg priority distance
119
120 for (uint8_t i = 0; i < packetPriorities[m_id].size(); ++i) {
121 uint8_t distance =
122 (abs(int(qos) - int(i))) * packetPriorities[m_id][i];
123
124 if (distance > 0) {
125 avgPriorityDistance[m_id].sample(distance);
126 DPRINTF(QOS,
127 "QoSMemCtrl::logRequest MASTER %s [id %d]"
128 " registering priority distance %d for priority %d"
129 " (packets %d)\n",
130 masters[m_id], m_id, distance, i,
131 packetPriorities[m_id][i]);
132 }
133 }
134
135 DPRINTF(QOS,
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]);
140
141 }
142
143 void
144 MemCtrl::logResponse(BusState dir, MasterID m_id, uint8_t qos,
145 Addr addr, uint64_t entries, double delay)
146 {
147 panic_if(!hasMaster(m_id),
148 "Logging response with invalid master\n");
149
150 DPRINTF(QOS,
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],
156 entries);
157
158 if (dir == READ) {
159 readQueueSizes[qos] -= entries;
160 totalReadQueueSize -= entries;
161 } else if (dir == WRITE) {
162 writeQueueSizes[qos] -= entries;
163 totalWriteQueueSize -= entries;
164 }
165
166 panic_if(packetPriorities[m_id][qos] == 0,
167 "QoSMemCtrl::logResponse master %s negative packets for priority"
168 " %d", masters[m_id], qos);
169
170 packetPriorities[m_id][qos] -= entries;
171
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);
177
178 // Load request time
179 uint64_t requestTime = it->second.front();
180
181 // Remove request entry
182 it->second.pop_front();
183
184 // Remove whole address entry if last one
185 if (it->second.empty()) {
186 requestTimes[m_id].erase(it);
187 }
188 // Compute latency
189 double latency = (double) (curTick() + delay - requestTime)
190 / SimClock::Float::s;
191
192 if (latency > 0) {
193 // Record per-priority latency stats
194 if (priorityMaxLatency[qos].value() < latency) {
195 priorityMaxLatency[qos] = latency;
196 }
197
198 if (priorityMinLatency[qos].value() > latency
199 || priorityMinLatency[qos].value() == 0) {
200 priorityMinLatency[qos] = latency;
201 }
202 }
203 }
204
205 DPRINTF(QOS,
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]);
210 }
211
212 uint8_t
213 MemCtrl::schedule(MasterID m_id, uint64_t data)
214 {
215 if (policy) {
216 return policy->schedule(m_id, data);
217 } else {
218 DPRINTF(QOS,
219 "QoSScheduler::schedule master ID [%d] "
220 "data received [%d], but QoS scheduler not initialized\n",
221 m_id,data);
222 return 0;
223 }
224 }
225
226 uint8_t
227 MemCtrl::schedule(const PacketPtr pkt)
228 {
229 assert(pkt->req);
230
231 if (policy) {
232 return schedule(pkt->req->masterId(), pkt->getSize());
233 } else {
234 DPRINTF(QOS, "QoSScheduler::schedule Packet received [Qv %d], "
235 "but QoS scheduler not initialized\n",
236 pkt->qosValue());
237 return pkt->qosValue();
238 }
239 }
240
241 MemCtrl::BusState
242 MemCtrl::selectNextBusState()
243 {
244 auto bus_state = getBusState();
245
246 if (turnPolicy) {
247 DPRINTF(QOS,
248 "QoSMemoryTurnaround::selectBusState running policy %s\n",
249 turnPolicy->name());
250
251 bus_state = turnPolicy->selectBusState();
252 } else {
253 DPRINTF(QOS,
254 "QoSMemoryTurnaround::selectBusState running "
255 "default bus direction selection policy\n");
256
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 :
261 MemCtrl::READ;
262
263 }
264 }
265
266 return bus_state;
267 }
268
269 void
270 MemCtrl::addMaster(MasterID m_id)
271 {
272 if (!hasMaster(m_id)) {
273 masters.emplace(m_id, _system->getMasterName(m_id));
274 packetPriorities[m_id].resize(numPriorities(), 0);
275
276 DPRINTF(QOS,
277 "QoSMemCtrl::addMaster registering"
278 " Master %s [id %d]\n",
279 masters[m_id], m_id);
280 }
281 }
282
283 void
284 MemCtrl::regStats()
285 {
286 AbstractMemory::regStats();
287
288 using namespace Stats;
289
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);
294
295 avgPriorityDistance.init(_system->maxMasters())
296 .name(name() + ".avgPriorityDistance")
297 .desc("Average QoS priority distance between assigned and "
298 "queued values").flags(nozero | nonan);
299
300 priorityMinLatency.init(numPriorities())
301 .name(name() + ".priorityMinLatency")
302 .desc("per QoS priority minimum request to response latency (s)")
303 .precision(12);
304
305 priorityMaxLatency.init(numPriorities())
306 .name(name() + ".priorityMaxLatency")
307 .desc("per QoS priority maximum request to response latency (s)")
308 .precision(12);
309
310 numReadWriteTurnArounds.name(name() + ".numReadWriteTurnArounds")
311 .desc("Number of turnarounds from READ to WRITE");
312
313 numWriteReadTurnArounds.name(name() + ".numWriteReadTurnArounds")
314 .desc("Number of turnarounds from WRITE to READ");
315
316 numStayReadState.name(name() + ".numStayReadState")
317 .desc("Number of times bus staying in READ state");
318
319 numStayWriteState.name(name() + ".numStayWriteState")
320 .desc("Number of times bus staying in WRITE state");
321
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);
326 }
327
328 for (int j = 0; j < numPriorities(); ++j) {
329 priorityMinLatency.subname(j, std::to_string(j));
330 priorityMaxLatency.subname(j, std::to_string(j));
331 }
332 }
333
334 void
335 MemCtrl::recordTurnaroundStats()
336 {
337 if (busStateNext != busState) {
338 if (busState == READ) {
339 numWriteReadTurnArounds++;
340 } else if (busState == WRITE) {
341 numReadWriteTurnArounds++;
342 }
343 } else {
344 if (busState == READ) {
345 numStayReadState++;
346 } else if (busState == WRITE) {
347 numStayWriteState++;
348 }
349 }
350 }
351
352 } // namespace QoS