gem5 [DEVELOP-FOR-25.0]
Loading...
Searching...
No Matches
mem_sink.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2018-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/qos/mem_sink.hh"
39
40#include "base/logging.hh"
41#include "base/trace.hh"
42#include "debug/Drain.hh"
43#include "debug/QOS.hh"
44#include "mem/qos/q_policy.hh"
45#include "params/QoSMemSinkInterface.hh"
46
47namespace gem5
48{
49
50namespace memory
51{
52
53namespace qos
54{
55
56MemSinkCtrl::MemSinkCtrl(const QoSMemSinkCtrlParams &p)
57 : MemCtrl(p), requestLatency(p.request_latency),
58 responseLatency(p.response_latency),
59 memoryPacketSize(p.memory_packet_size),
60 readBufferSize(p.read_buffer_size),
61 writeBufferSize(p.write_buffer_size), port(name() + ".port", *this),
63 retryRdReq(false), retryWrReq(false), nextRequest(0), nextReqEvent(*this),
64 stats(this)
65{
66 // Resize read and write queue to allocate space
67 // for configured QoS priorities
68 readQueue.resize(numPriorities());
69 writeQueue.resize(numPriorities());
70
71 interface->setMemCtrl(this);
72}
73
76
77void
79{
81
82 // Allow unconnected memories as this is used in several ruby
83 // systems at the moment
84 if (port.isConnected()) {
85 port.sendRangeChange();
86 }
87}
88
89bool
90MemSinkCtrl::readQueueFull(const uint64_t packets) const
91{
92 return (totalReadQueueSize + packets > readBufferSize);
93}
94
95bool
96MemSinkCtrl::writeQueueFull(const uint64_t packets) const
97{
98 return (totalWriteQueueSize + packets > writeBufferSize);
99}
100
101Tick
103{
105 "%s Should not see packets where cache is responding\n",
106 __func__);
107
108 interface->access(pkt);
109 return responseLatency;
110}
111
112void
114{
115 pkt->pushLabel(name());
116
117 interface->functionalAccess(pkt);
118
119 pkt->popLabel();
120}
121
122Port &
123MemSinkCtrl::getPort(const std::string &interface, PortID idx)
124{
125 if (interface != "port") {
126 return MemCtrl::getPort(interface, idx);
127 } else {
128 return port;
129 }
130}
131
132bool
134{
135 // Request accepted
136 bool req_accepted = true;
137
138 panic_if(!(pkt->isRead() || pkt->isWrite()),
139 "%s. Should only see "
140 "read and writes at memory controller\n",
141 __func__);
142
144 "%s. Should not see packets where cache is responding\n",
145 __func__);
146
147 DPRINTF(QOS,
148 "%s: REQUESTOR %s request %s addr %lld size %d\n",
149 __func__,
150 _system->getRequestorName(pkt->req->requestorId()),
151 pkt->cmdString(), pkt->getAddr(), pkt->getSize());
152
153 uint64_t required_entries = divCeil(pkt->getSize(), memoryPacketSize);
154
155 assert(required_entries);
156
157 // Schedule packet
158 uint8_t pkt_priority = qosSchedule({&readQueue, &writeQueue},
159 memoryPacketSize, pkt);
160
161 if (pkt->isRead()) {
162 if (readQueueFull(required_entries)) {
163 DPRINTF(QOS,
164 "%s Read queue full, not accepting\n", __func__);
165 // Remember that we have to retry this port
166 retryRdReq = true;
167 stats.numReadRetries++;
168 req_accepted = false;
169 } else {
170 // Enqueue the incoming packet into corresponding
171 // QoS priority queue
172 readQueue.at(pkt_priority).push_back(pkt);
173 queuePolicy->enqueuePacket(pkt);
174 }
175 } else {
176 if (writeQueueFull(required_entries)) {
177 DPRINTF(QOS,
178 "%s Write queue full, not accepting\n", __func__);
179 // Remember that we have to retry this port
180 retryWrReq = true;
181 stats.numWriteRetries++;
182 req_accepted = false;
183 } else {
184 // Enqueue the incoming packet into corresponding QoS
185 // priority queue
186 writeQueue.at(pkt_priority).push_back(pkt);
187 queuePolicy->enqueuePacket(pkt);
188 }
189 }
190
191 if (req_accepted) {
192 // The packet is accepted - log it
193 logRequest(pkt->isRead()? READ : WRITE,
194 pkt->req->requestorId(),
195 pkt->qosValue(),
196 pkt->getAddr(),
197 required_entries);
198 }
199
200 // Check if we have to process next request event
201 if (!nextReqEvent.scheduled()) {
202 DPRINTF(QOS,
203 "%s scheduling next request at "
204 "time %d (next is %d)\n", __func__,
205 std::max(curTick(), nextRequest), nextRequest);
207 }
208 return req_accepted;
209}
210
211void
213{
214 PacketPtr pkt = nullptr;
215
216 // Evaluate bus direction
218
219 // Record turnaround stats and update current state direction
221
222 // Set current bus state
224
225 // Access current direction buffer
226 std::vector<PacketQueue>* queue_ptr = (busState == READ ? &readQueue :
227 &writeQueue);
228
229 DPRINTF(QOS,
230 "%s DUMPING %s queues status\n", __func__,
231 (busState == WRITE ? "WRITE" : "READ"));
232
233 if (debug::QOS) {
234 for (uint8_t i = 0; i < numPriorities(); ++i) {
235 std::string plist = "";
236 for (auto& e : (busState == WRITE ? writeQueue[i]: readQueue[i])) {
237 plist += (std::to_string(e->req->requestorId())) + " ";
238 }
239 DPRINTF(QOS,
240 "%s priority Queue [%i] contains %i elements, "
241 "packets are: [%s]\n", __func__, i,
244 plist);
245 }
246 }
247
248 uint8_t curr_prio = numPriorities();
249
250 for (auto queue = (*queue_ptr).rbegin();
251 queue != (*queue_ptr).rend(); ++queue) {
252
253 curr_prio--;
254
255 DPRINTF(QOS,
256 "%s checking %s queue [%d] priority [%d packets]\n",
257 __func__, (busState == READ? "READ" : "WRITE"),
258 curr_prio, queue->size());
259
260 if (!queue->empty()) {
261 // Call the queue policy to select packet from priority queue
262 auto p_it = queuePolicy->selectPacket(&(*queue));
263 pkt = *p_it;
264 queue->erase(p_it);
265
266 DPRINTF(QOS,
267 "%s scheduling packet address %d for requestor %s from "
268 "priority queue %d\n", __func__, pkt->getAddr(),
269 _system->getRequestorName(pkt->req->requestorId()),
270 curr_prio);
271 break;
272 }
273 }
274
275 assert(pkt);
276
277 // Setup next request service time - do it here as retry request
278 // hands over control to the port
280
281 uint64_t removed_entries = divCeil(pkt->getSize(), memoryPacketSize);
282
283 DPRINTF(QOS,
284 "%s scheduled packet address %d for requestor %s size is %d, "
285 "corresponds to %d memory packets\n", __func__, pkt->getAddr(),
286 _system->getRequestorName(pkt->req->requestorId()),
287 pkt->getSize(), removed_entries);
288
289 // Schedule response
290 panic_if(!pkt->needsResponse(),
291 "%s response not required\n", __func__);
292
293 // Do the actual memory access which also turns the packet
294 // into a response
295 interface->access(pkt);
296
297 // Log the response
298 logResponse(pkt->isRead()? READ : WRITE,
299 pkt->req->requestorId(),
300 pkt->qosValue(),
301 pkt->getAddr(),
302 removed_entries, responseLatency);
303
304 // Schedule the response
305 port.schedTimingResp(pkt, curTick() + responseLatency);
306 DPRINTF(QOS,
307 "%s response scheduled at time %d\n",
308 __func__, curTick() + responseLatency);
309
310 // Finally - handle retry requests - this handles control
311 // to the port, so do it last
312 if (busState == READ && retryRdReq) {
313 retryRdReq = false;
314 port.sendRetryReq();
315 } else if (busState == WRITE && retryWrReq) {
316 retryWrReq = false;
317 port.sendRetryReq();
318 }
319
320 // Check if we have to schedule another request event
322 !nextReqEvent.scheduled()) {
323
325 DPRINTF(QOS,
326 "%s scheduling next request event at tick %d\n",
327 __func__, curTick() + requestLatency);
328 }
329}
330
333{
335 DPRINTF(Drain,
336 "%s queues have requests, waiting to drain\n",
337 __func__);
339 } else {
340 return DrainState::Drained;
341 }
342}
343
345 : statistics::Group(parent),
346 ADD_STAT(numReadRetries, statistics::units::Count::get(),
347 "Number of read retries"),
349 "Number of write retries")
350{
351}
352
354 MemSinkCtrl& m)
355 : QueuedResponsePort(n, queue, true),
356 mem(m), queue(mem, *this, true)
357{}
358
361{
362 AddrRangeList ranges;
363 ranges.push_back(mem.interface->getAddrRange());
364 return ranges;
365}
366
367Tick
369{
370 return mem.recvAtomic(pkt);
371}
372
373void
375{
376 pkt->pushLabel(mem.name());
377
378 if (!queue.trySatisfyFunctional(pkt)) {
379 // Default implementation of SimpleTimingPort::recvFunctional()
380 // calls recvAtomic() and throws away the latency; we can save a
381 // little here by just not calculating the latency.
382 mem.recvFunctional(pkt);
383 }
384
385 pkt->popLabel();
386}
387
388bool
390{
391 return mem.recvTimingReq(pkt);
392}
393
394MemSinkInterface::MemSinkInterface(const QoSMemSinkInterfaceParams &_p)
395 : AbstractMemory(_p)
396{
397}
398
399} // namespace qos
400} // namespace memory
401} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:209
virtual std::string name() const
Definition named.hh:60
bool isRead() const
Definition packet.hh:593
Addr getAddr() const
Definition packet.hh:807
void pushLabel(const std::string &lbl)
Push label for PrintReq (safe to call unconditionally).
Definition packet.hh:1470
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition packet.hh:588
bool needsResponse() const
Definition packet.hh:608
uint8_t qosValue() const
QoS Value getter Returns 0 if QoS value was never set (constructor default).
Definition packet.hh:769
bool isWrite() const
Definition packet.hh:594
RequestPtr req
A pointer to the original request.
Definition packet.hh:377
unsigned getSize() const
Definition packet.hh:817
void popLabel()
Pop label for PrintReq (safe to call unconditionally).
Definition packet.hh:1480
bool cacheResponding() const
Definition packet.hh:659
Ports are used to interface objects to each other.
Definition port.hh:62
QueuedResponsePort(const std::string &name, RespPacketQueue &resp_queue, PortID id=InvalidPortID)
Create a QueuedPort with a given name, owner, and a supplied implementation of a packet queue.
Definition qport.hh:80
AbstractMemory(const AbstractMemory &)
void logResponse(BusState dir, RequestorID id, uint8_t _qos, Addr addr, uint64_t entries, double delay)
Called upon receiving a response, updates statistics and updates queues status.
Definition mem_ctrl.cc:148
std::vector< uint64_t > writeQueueSizes
Write request packets queue length in #packets, per QoS priority.
Definition mem_ctrl.hh:127
uint8_t qosSchedule(std::initializer_list< Queues * > queues_ptr, uint64_t queue_entry_size, const PacketPtr pkt)
Assign priority to a packet by executing the configured QoS policy.
Definition mem_ctrl.hh:495
uint64_t totalWriteQueueSize
Total write request packets queue length in #packets.
Definition mem_ctrl.hh:133
void recordTurnaroundStats(BusState busState, BusState busStateNext)
Record statistics on turnarounds based on busStateNext and busState values.
Definition mem_ctrl.cc:358
void setCurrentBusState()
Set current bus direction (READ or WRITE) from next selected one.
Definition mem_ctrl.hh:239
std::vector< uint64_t > readQueueSizes
Read request packets queue length in #packets, per QoS priority.
Definition mem_ctrl.hh:124
const std::unique_ptr< QueuePolicy > queuePolicy
QoS Queue Policy: selects packet among same-priority queue.
Definition mem_ctrl.hh:93
MemCtrl(const QoSMemCtrlParams &)
QoS Memory base class.
Definition mem_ctrl.cc:54
BusState selectNextBusState()
Returns next bus direction (READ or WRITE) based on configured policy.
Definition mem_ctrl.cc:246
uint8_t numPriorities() const
Gets the total number of priority levels in the QoS memory controller.
Definition mem_ctrl.hh:366
BusState busState
Bus state used to control the read/write switching and drive the scheduling of the next request.
Definition mem_ctrl.hh:139
System * _system
Pointer to the System object.
Definition mem_ctrl.hh:175
uint64_t totalReadQueueSize
Total read request packets queue length in #packets.
Definition mem_ctrl.hh:130
BusState busStateNext
bus state for next request event triggered
Definition mem_ctrl.hh:142
uint8_t schedule(RequestorID id, uint64_t data)
Definition mem_ctrl.cc:217
void logRequest(BusState dir, RequestorID id, uint8_t _qos, Addr addr, uint64_t entries)
Called upon receiving a request or updates statistics and updates queues status.
Definition mem_ctrl.cc:91
void recvFunctional(PacketPtr pkt)
Receive a Packet in Functional mode.
Definition mem_sink.cc:374
MemoryPort(const std::string &, MemSinkCtrl &)
Constructor.
Definition mem_sink.cc:353
AddrRangeList getAddrRanges() const
Gets the configured address ranges for this port.
Definition mem_sink.cc:360
Tick recvAtomic(PacketPtr pkt)
Receive a Packet in Atomic mode.
Definition mem_sink.cc:368
bool recvTimingReq(PacketPtr pkt)
Receive a Packet in Timing mode.
Definition mem_sink.cc:389
RespPacketQueue queue
Outgoing packet responses queue.
Definition mem_sink.hh:91
MemSinkCtrl & mem
reference to parent memory object
Definition mem_sink.hh:88
MemoryPort port
Memory response port.
Definition mem_sink.hh:181
Tick recvAtomic(PacketPtr pkt)
Receive a Packet in Atomic mode.
Definition mem_sink.cc:102
const Tick responseLatency
Memory response latency (ticks)
Definition mem_sink.hh:169
Port & getPort(const std::string &if_name, PortID=InvalidPortID) override
Getter method to access this memory's response port.
Definition mem_sink.cc:123
MemberEventWrapper<&MemSinkCtrl::processNextReqEvent > nextReqEvent
Event wrapper to schedule next request handler function.
Definition mem_sink.hh:225
const uint64_t writeBufferSize
Write request packets queue buffer size in #packets.
Definition mem_sink.hh:178
DrainState drain() override
Checks and return the Drain state of this SimObject.
Definition mem_sink.cc:332
bool readQueueFull(const uint64_t packets) const
Check if the read queue has room for more entries.
Definition mem_sink.cc:90
bool recvTimingReq(PacketPtr pkt)
Receive a Packet in Timing mode.
Definition mem_sink.cc:133
const uint64_t readBufferSize
Read request packets queue buffer size in #packets.
Definition mem_sink.hh:175
bool retryWrReq
Write request pending.
Definition mem_sink.hh:192
std::vector< PacketQueue > readQueue
QoS-aware (per priority) incoming read requests packets queue.
Definition mem_sink.hh:211
bool retryRdReq
Read request pending.
Definition mem_sink.hh:189
void processNextReqEvent()
Processes the next Request event according to configured request latency.
Definition mem_sink.cc:212
bool writeQueueFull(const uint64_t packets) const
Check if the write queue has room for more entries.
Definition mem_sink.cc:96
const Tick requestLatency
Memory between requests latency (ticks)
Definition mem_sink.hh:166
const uint64_t memoryPacketSize
Memory packet size in bytes.
Definition mem_sink.hh:172
void init() override
Initializes this object.
Definition mem_sink.cc:78
MemSinkCtrl(const QoSMemSinkCtrlParams &)
QoS Memory Sink Constructor.
Definition mem_sink.cc:56
void recvFunctional(PacketPtr pkt)
Receive a Packet in Functional mode.
Definition mem_sink.cc:113
Tick nextRequest
Next request service time.
Definition mem_sink.hh:195
std::vector< PacketQueue > writeQueue
QoS-aware (per priority) incoming read requests packets queue.
Definition mem_sink.hh:216
MemSinkInterface *const interface
Create pointer to interface of actual media.
Definition mem_sink.hh:186
MemSinkInterface(const QoSMemSinkInterfaceParams &_p)
Definition mem_sink.cc:394
Statistics container.
Definition group.hh:93
STL vector class.
Definition stl.hh:37
#define ADD_STAT(n,...)
Convenience macro to add a stat to a statistics group.
Definition group.hh:75
std::list< AddrRange > AddrRangeList
Convenience typedef for a collection of address ranges.
Definition addr_range.hh:64
static constexpr T divCeil(const T &a, const U &b)
Definition intmath.hh:110
DrainState
Object drain/handover states.
Definition drain.hh:75
@ Draining
Draining buffers pending serialization/handover.
Definition drain.hh:77
@ Drained
Buffers drained, ready for serialization/handover.
Definition drain.hh:78
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:246
virtual Port & getPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a port with a given name and index.
virtual void init()
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition sim_object.cc:73
Bitfield< 31 > n
Bitfield< 7 > i
Definition misc_types.hh:67
Bitfield< 9 > e
Definition misc_types.hh:65
Bitfield< 0 > m
Bitfield< 0 > p
Units for Stats.
Definition units.hh:113
Copyright (c) 2024 Arm Limited All rights reserved.
Definition binary32.hh:36
Tick curTick()
The universal simulation clock.
Definition cur_tick.hh:46
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
Definition types.hh:245
uint64_t Tick
Tick count type.
Definition types.hh:58
Packet * PacketPtr
statistics::Scalar numReadRetries
Count the number of read retries.
Definition mem_sink.hh:202
MemSinkCtrlStats(statistics::Group *parent)
Definition mem_sink.cc:344
statistics::Scalar numWriteRetries
Count the number of write retries.
Definition mem_sink.hh:205

Generated on Mon May 26 2025 09:19:12 for gem5 by doxygen 1.13.2