2 * Copyright (c) 2017-2020 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.
38 #include "mem_ctrl.hh"
40 #include "turnaround_policy.hh"
44 MemCtrl::MemCtrl(const QoSMemCtrlParams
* 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
),
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
);
81 MemCtrl::logRequest(BusState dir
, MasterID m_id
, uint8_t qos
,
82 Addr addr
, uint64_t entries
)
84 // If needed, initialize all counters and statistics
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
],
97 readQueueSizes
[qos
] += entries
;
98 totalReadQueueSize
+= entries
;
99 } else if (dir
== WRITE
) {
100 writeQueueSizes
[qos
] += entries
;
101 totalWriteQueueSize
+= entries
;
104 packetPriorities
[m_id
][qos
] += entries
;
105 for (auto j
= 0; j
< entries
; ++j
) {
106 requestTimes
[m_id
][addr
].push_back(curTick());
110 stats
.avgPriority
[m_id
].sample(qos
);
112 // Compute avg priority distance
114 for (uint8_t i
= 0; i
< packetPriorities
[m_id
].size(); ++i
) {
116 (abs(int(qos
) - int(i
))) * packetPriorities
[m_id
][i
];
119 stats
.avgPriorityDistance
[m_id
].sample(distance
);
121 "QoSMemCtrl::logRequest MASTER %s [id %d]"
122 " registering priority distance %d for priority %d"
124 masters
[m_id
], m_id
, distance
, i
,
125 packetPriorities
[m_id
][i
]);
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
]);
138 MemCtrl::logResponse(BusState dir
, MasterID m_id
, uint8_t qos
,
139 Addr addr
, uint64_t entries
, double delay
)
141 panic_if(!hasMaster(m_id
),
142 "Logging response with invalid master\n");
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
],
153 readQueueSizes
[qos
] -= entries
;
154 totalReadQueueSize
-= entries
;
155 } else if (dir
== WRITE
) {
156 writeQueueSizes
[qos
] -= entries
;
157 totalWriteQueueSize
-= entries
;
160 panic_if(packetPriorities
[m_id
][qos
] == 0,
161 "QoSMemCtrl::logResponse master %s negative packets for priority"
162 " %d", masters
[m_id
], qos
);
164 packetPriorities
[m_id
][qos
] -= entries
;
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
);
173 uint64_t requestTime
= it
->second
.front();
175 // Remove request entry
176 it
->second
.pop_front();
178 // Remove whole address entry if last one
179 if (it
->second
.empty()) {
180 requestTimes
[m_id
].erase(it
);
183 double latency
= (double) (curTick() + delay
- requestTime
)
184 / SimClock::Float::s
;
187 // Record per-priority latency stats
188 if (stats
.priorityMaxLatency
[qos
].value() < latency
) {
189 stats
.priorityMaxLatency
[qos
] = latency
;
192 if (stats
.priorityMinLatency
[qos
].value() > latency
193 || stats
.priorityMinLatency
[qos
].value() == 0) {
194 stats
.priorityMinLatency
[qos
] = latency
;
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
]);
207 MemCtrl::schedule(MasterID m_id
, uint64_t data
)
210 return policy
->schedule(m_id
, data
);
213 "QoSScheduler::schedule master ID [%d] "
214 "data received [%d], but QoS scheduler not initialized\n",
221 MemCtrl::schedule(const PacketPtr pkt
)
226 return schedule(pkt
->req
->masterId(), pkt
->getSize());
228 DPRINTF(QOS
, "QoSScheduler::schedule Packet received [Qv %d], "
229 "but QoS scheduler not initialized\n",
231 return pkt
->qosValue();
236 MemCtrl::selectNextBusState()
238 auto bus_state
= getBusState();
242 "QoSMemoryTurnaround::selectBusState running policy %s\n",
245 bus_state
= turnPolicy
->selectBusState();
248 "QoSMemoryTurnaround::selectBusState running "
249 "default bus direction selection policy\n");
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
:
264 MemCtrl::addMaster(MasterID m_id
)
266 if (!hasMaster(m_id
)) {
267 masters
.emplace(m_id
, _system
->getMasterName(m_id
));
268 packetPriorities
[m_id
].resize(numPriorities(), 0);
271 "QoSMemCtrl::addMaster registering"
272 " Master %s [id %d]\n",
273 masters
[m_id
], m_id
);
277 MemCtrl::MemCtrlStats::MemCtrlStats(MemCtrl
&mc
)
281 ADD_STAT(avgPriority
,
282 "Average QoS priority value for accepted requests"),
283 ADD_STAT(avgPriorityDistance
,
284 "Average QoS priority distance between assigned and "
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")
303 MemCtrl::MemCtrlStats::regStats()
305 Stats::Group::regStats();
307 using namespace Stats
;
309 System
*system
= memCtrl
._system
;
310 const auto max_masters
= system
->maxMasters();
311 const auto num_priorities
= memCtrl
.numPriorities();
313 // Initializes per master statistics
316 .flags(nozero
| nonan
)
322 .flags(nozero
| nonan
)
326 .init(num_priorities
)
331 .init(num_priorities
)
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
);
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
));
348 MemCtrl::recordTurnaroundStats()
350 if (busStateNext
!= busState
) {
351 if (busState
== READ
) {
352 stats
.numWriteReadTurnArounds
++;
353 } else if (busState
== WRITE
) {
354 stats
.numReadWriteTurnArounds
++;
357 if (busState
== READ
) {
358 stats
.numStayReadState
++;
359 } else if (busState
== WRITE
) {
360 stats
.numStayWriteState
++;