mem: Make MemCtrl a ClockedObject
[gem5.git] / src / mem / qos / mem_ctrl.cc
1 /*
2 * Copyright (c) 2017-2020 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
38 #include "mem_ctrl.hh"
39
40 #include "turnaround_policy.hh"
41
42 namespace QoS {
43
44 MemCtrl::MemCtrl(const QoSMemCtrlParams * p)
45 : ClockedObject(p),
46 policy(p->qos_policy),
47 turnPolicy(p->qos_turnaround_policy),
48 queuePolicy(QueuePolicy::create(p)),
49 _numPriorities(p->qos_priorities),
50 qosPriorityEscalation(p->qos_priority_escalation),
51 qosSyncroScheduler(p->qos_syncro_scheduler),
52 totalReadQueueSize(0), totalWriteQueueSize(0),
53 busState(READ), busStateNext(READ),
54 stats(*this),
55 _system(p->system)
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::logRequest(BusState dir, MasterID m_id, uint8_t qos,
82 Addr addr, uint64_t entries)
83 {
84 // If needed, initialize all counters and statistics
85 // for this master
86 addMaster(m_id);
87
88 DPRINTF(QOS,
89 "QoSMemCtrl::logRequest MASTER %s [id %d] address %d"
90 " prio %d this master q packets %d"
91 " - queue size %d - requested entries %d\n",
92 masters[m_id], m_id, addr, qos, packetPriorities[m_id][qos],
93 (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos],
94 entries);
95
96 if (dir == READ) {
97 readQueueSizes[qos] += entries;
98 totalReadQueueSize += entries;
99 } else if (dir == WRITE) {
100 writeQueueSizes[qos] += entries;
101 totalWriteQueueSize += entries;
102 }
103
104 packetPriorities[m_id][qos] += entries;
105 for (auto j = 0; j < entries; ++j) {
106 requestTimes[m_id][addr].push_back(curTick());
107 }
108
109 // Record statistics
110 stats.avgPriority[m_id].sample(qos);
111
112 // Compute avg priority distance
113
114 for (uint8_t i = 0; i < packetPriorities[m_id].size(); ++i) {
115 uint8_t distance =
116 (abs(int(qos) - int(i))) * packetPriorities[m_id][i];
117
118 if (distance > 0) {
119 stats.avgPriorityDistance[m_id].sample(distance);
120 DPRINTF(QOS,
121 "QoSMemCtrl::logRequest MASTER %s [id %d]"
122 " registering priority distance %d for priority %d"
123 " (packets %d)\n",
124 masters[m_id], m_id, distance, i,
125 packetPriorities[m_id][i]);
126 }
127 }
128
129 DPRINTF(QOS,
130 "QoSMemCtrl::logRequest MASTER %s [id %d] prio %d "
131 "this master q packets %d - new queue size %d\n",
132 masters[m_id], m_id, qos, packetPriorities[m_id][qos],
133 (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos]);
134
135 }
136
137 void
138 MemCtrl::logResponse(BusState dir, MasterID m_id, uint8_t qos,
139 Addr addr, uint64_t entries, double delay)
140 {
141 panic_if(!hasMaster(m_id),
142 "Logging response with invalid master\n");
143
144 DPRINTF(QOS,
145 "QoSMemCtrl::logResponse MASTER %s [id %d] address %d prio"
146 " %d this master q packets %d"
147 " - queue size %d - requested entries %d\n",
148 masters[m_id], m_id, addr, qos, packetPriorities[m_id][qos],
149 (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos],
150 entries);
151
152 if (dir == READ) {
153 readQueueSizes[qos] -= entries;
154 totalReadQueueSize -= entries;
155 } else if (dir == WRITE) {
156 writeQueueSizes[qos] -= entries;
157 totalWriteQueueSize -= entries;
158 }
159
160 panic_if(packetPriorities[m_id][qos] == 0,
161 "QoSMemCtrl::logResponse master %s negative packets for priority"
162 " %d", masters[m_id], qos);
163
164 packetPriorities[m_id][qos] -= entries;
165
166 for (auto j = 0; j < entries; ++j) {
167 auto it = requestTimes[m_id].find(addr);
168 panic_if(it == requestTimes[m_id].end(),
169 "QoSMemCtrl::logResponse master %s unmatched response for"
170 " address %d received", masters[m_id], addr);
171
172 // Load request time
173 uint64_t requestTime = it->second.front();
174
175 // Remove request entry
176 it->second.pop_front();
177
178 // Remove whole address entry if last one
179 if (it->second.empty()) {
180 requestTimes[m_id].erase(it);
181 }
182 // Compute latency
183 double latency = (double) (curTick() + delay - requestTime)
184 / SimClock::Float::s;
185
186 if (latency > 0) {
187 // Record per-priority latency stats
188 if (stats.priorityMaxLatency[qos].value() < latency) {
189 stats.priorityMaxLatency[qos] = latency;
190 }
191
192 if (stats.priorityMinLatency[qos].value() > latency
193 || stats.priorityMinLatency[qos].value() == 0) {
194 stats.priorityMinLatency[qos] = latency;
195 }
196 }
197 }
198
199 DPRINTF(QOS,
200 "QoSMemCtrl::logResponse MASTER %s [id %d] prio %d "
201 "this master q packets %d - new queue size %d\n",
202 masters[m_id], m_id, qos, packetPriorities[m_id][qos],
203 (dir == READ) ? readQueueSizes[qos]: writeQueueSizes[qos]);
204 }
205
206 uint8_t
207 MemCtrl::schedule(MasterID m_id, uint64_t data)
208 {
209 if (policy) {
210 return policy->schedule(m_id, data);
211 } else {
212 DPRINTF(QOS,
213 "QoSScheduler::schedule master ID [%d] "
214 "data received [%d], but QoS scheduler not initialized\n",
215 m_id,data);
216 return 0;
217 }
218 }
219
220 uint8_t
221 MemCtrl::schedule(const PacketPtr pkt)
222 {
223 assert(pkt->req);
224
225 if (policy) {
226 return schedule(pkt->req->masterId(), pkt->getSize());
227 } else {
228 DPRINTF(QOS, "QoSScheduler::schedule Packet received [Qv %d], "
229 "but QoS scheduler not initialized\n",
230 pkt->qosValue());
231 return pkt->qosValue();
232 }
233 }
234
235 MemCtrl::BusState
236 MemCtrl::selectNextBusState()
237 {
238 auto bus_state = getBusState();
239
240 if (turnPolicy) {
241 DPRINTF(QOS,
242 "QoSMemoryTurnaround::selectBusState running policy %s\n",
243 turnPolicy->name());
244
245 bus_state = turnPolicy->selectBusState();
246 } else {
247 DPRINTF(QOS,
248 "QoSMemoryTurnaround::selectBusState running "
249 "default bus direction selection policy\n");
250
251 if ((!getTotalReadQueueSize() && bus_state == MemCtrl::READ) ||
252 (!getTotalWriteQueueSize() && bus_state == MemCtrl::WRITE)) {
253 // READ/WRITE turnaround
254 bus_state = (bus_state == MemCtrl::READ) ? MemCtrl::WRITE :
255 MemCtrl::READ;
256
257 }
258 }
259
260 return bus_state;
261 }
262
263 void
264 MemCtrl::addMaster(MasterID m_id)
265 {
266 if (!hasMaster(m_id)) {
267 masters.emplace(m_id, _system->getMasterName(m_id));
268 packetPriorities[m_id].resize(numPriorities(), 0);
269
270 DPRINTF(QOS,
271 "QoSMemCtrl::addMaster registering"
272 " Master %s [id %d]\n",
273 masters[m_id], m_id);
274 }
275 }
276
277 MemCtrl::MemCtrlStats::MemCtrlStats(MemCtrl &mc)
278 : Stats::Group(&mc),
279 memCtrl(mc),
280
281 ADD_STAT(avgPriority,
282 "Average QoS priority value for accepted requests"),
283 ADD_STAT(avgPriorityDistance,
284 "Average QoS priority distance between assigned and "
285 "queued values"),
286
287 ADD_STAT(priorityMinLatency,
288 "per QoS priority minimum request to response latency (s)"),
289 ADD_STAT(priorityMaxLatency,
290 "per QoS priority maximum request to response latency (s)"),
291 ADD_STAT(numReadWriteTurnArounds,
292 "Number of turnarounds from READ to WRITE"),
293 ADD_STAT(numWriteReadTurnArounds,
294 "Number of turnarounds from WRITE to READ"),
295 ADD_STAT(numStayReadState,
296 "Number of times bus staying in READ state"),
297 ADD_STAT(numStayWriteState,
298 "Number of times bus staying in WRITE state")
299 {
300 }
301
302 void
303 MemCtrl::MemCtrlStats::regStats()
304 {
305 Stats::Group::regStats();
306
307 using namespace Stats;
308
309 System *system = memCtrl._system;
310 const auto max_masters = system->maxMasters();
311 const auto num_priorities = memCtrl.numPriorities();
312
313 // Initializes per master statistics
314 avgPriority
315 .init(max_masters)
316 .flags(nozero | nonan)
317 .precision(2)
318 ;
319
320 avgPriorityDistance
321 .init(max_masters)
322 .flags(nozero | nonan)
323 ;
324
325 priorityMinLatency
326 .init(num_priorities)
327 .precision(12)
328 ;
329
330 priorityMaxLatency
331 .init(num_priorities)
332 .precision(12)
333 ;
334
335 for (int i = 0; i < max_masters; i++) {
336 const std::string master = system->getMasterName(i);
337 avgPriority.subname(i, master);
338 avgPriorityDistance.subname(i, master);
339 }
340
341 for (int j = 0; j < num_priorities; ++j) {
342 priorityMinLatency.subname(j, std::to_string(j));
343 priorityMaxLatency.subname(j, std::to_string(j));
344 }
345 }
346
347 void
348 MemCtrl::recordTurnaroundStats()
349 {
350 if (busStateNext != busState) {
351 if (busState == READ) {
352 stats.numWriteReadTurnArounds++;
353 } else if (busState == WRITE) {
354 stats.numReadWriteTurnArounds++;
355 }
356 } else {
357 if (busState == READ) {
358 stats.numStayReadState++;
359 } else if (busState == WRITE) {
360 stats.numStayWriteState++;
361 }
362 }
363 }
364
365 } // namespace QoS