gem5  v20.1.0.0
mem_ctrl.hh
Go to the documentation of this file.
1 /*
2  * Copyright (c) 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 "debug/QOS.hh"
39 #include "mem/qos/policy.hh"
40 #include "mem/qos/q_policy.hh"
41 #include "params/QoSMemCtrl.hh"
42 #include "sim/clocked_object.hh"
43 #include "sim/system.hh"
44 
45 #include <unordered_map>
46 #include <vector>
47 #include <deque>
48 
49 #ifndef __MEM_QOS_MEM_CTRL_HH__
50 #define __MEM_QOS_MEM_CTRL_HH__
51 
52 namespace QoS {
53 
59 class MemCtrl : public ClockedObject
60 {
61  public:
63  enum BusState { READ, WRITE };
64 
65  protected:
67  const std::unique_ptr<Policy> policy;
68 
70  const std::unique_ptr<TurnaroundPolicy> turnPolicy;
71 
73  const std::unique_ptr<QueuePolicy> queuePolicy;
74 
76  const uint8_t _numPriorities;
77 
80 
85  const bool qosSyncroScheduler;
86 
88  std::unordered_map<RequestorID, const std::string> requestors;
89 
91  std::unordered_map<RequestorID, std::vector<uint64_t> > packetPriorities;
92 
94  std::unordered_map<RequestorID,
95  std::unordered_map<uint64_t, std::deque<uint64_t>> > requestTimes;
96 
102 
105 
108 
111 
114 
120 
123 
124  struct MemCtrlStats : public Stats::Group
125  {
126  MemCtrlStats(MemCtrl &mc);
127 
128  void regStats() override;
129 
130  const MemCtrl &memCtrl;
131 
139 
152  } stats;
153 
156 
163  void addRequestor(const RequestorID id);
164 
175  void logRequest(BusState dir, RequestorID id, uint8_t qos,
176  Addr addr, uint64_t entries);
177 
189  void logResponse(BusState dir, RequestorID id, uint8_t qos,
190  Addr addr, uint64_t entries, double delay);
191 
201  template<typename Queues>
202  uint8_t qosSchedule(std::initializer_list<Queues*> queues_ptr,
203  uint64_t queue_entry_size, const PacketPtr pkt);
204 
205  using SimObject::schedule;
206  uint8_t schedule(RequestorID id, uint64_t data);
207  uint8_t schedule(const PacketPtr pkt);
208 
214 
220 
225  void recordTurnaroundStats();
226 
237  template<typename Queues>
238  void escalate(std::initializer_list<Queues*> queues,
239  uint64_t queue_entry_size,
240  RequestorID id, uint8_t tgt_prio);
241 
257  template<typename Queues>
258  void escalateQueues(Queues& queues, uint64_t queue_entry_size,
259  RequestorID id, uint8_t curr_prio, uint8_t tgt_prio);
260 
261  public:
267  MemCtrl(const QoSMemCtrlParams*);
268 
269  virtual ~MemCtrl();
270 
276  BusState getBusState() const { return busState; }
277 
284 
295  bool hasRequestor(RequestorID id) const
296  {
297  return requestors.find(id) != requestors.end();
298  }
299 
306  uint64_t getReadQueueSize(const uint8_t prio) const
307  { return readQueueSizes[prio]; }
308 
315  uint64_t getWriteQueueSize(const uint8_t prio) const
316  { return writeQueueSizes[prio]; }
317 
323  uint64_t getTotalReadQueueSize() const { return totalReadQueueSize; }
324 
330  uint64_t getTotalWriteQueueSize() const { return totalWriteQueueSize; }
331 
338  Tick getServiceTick(const uint8_t prio) const { return serviceTick[prio]; }
339 
346  uint8_t numPriorities() const { return _numPriorities; }
347 
350  System* system() const { return _system; }
351 };
352 
353 template<typename Queues>
354 void
355 MemCtrl::escalateQueues(Queues& queues, uint64_t queue_entry_size,
356  RequestorID id, uint8_t curr_prio, uint8_t tgt_prio)
357 {
358  auto it = queues[curr_prio].begin();
359  while (it != queues[curr_prio].end()) {
360  // No packets left to move
361  if (packetPriorities[id][curr_prio] == 0)
362  break;
363 
364  auto pkt = *it;
365 
366  DPRINTF(QOS,
367  "QoSMemCtrl::escalate checking priority %d packet "
368  "id %d address %d\n", curr_prio,
369  pkt->requestorId(), pkt->getAddr());
370 
371  // Found a packet to move
372  if (pkt->requestorId() == id) {
373 
374  uint64_t moved_entries = divCeil(pkt->getSize(),
375  queue_entry_size);
376 
377  DPRINTF(QOS,
378  "QoSMemCtrl::escalate Requestor %s [id %d] moving "
379  "packet addr %d size %d (p size %d) from priority %d "
380  "to priority %d - "
381  "this requestor packets %d (entries to move %d)\n",
382  requestors[id], id, pkt->getAddr(),
383  pkt->getSize(),
384  queue_entry_size, curr_prio, tgt_prio,
385  packetPriorities[id][curr_prio], moved_entries);
386 
387 
388  if (pkt->isRead()) {
389  panic_if(readQueueSizes[curr_prio] < moved_entries,
390  "QoSMemCtrl::escalate requestor %s negative READ "
391  "packets for priority %d",
392  requestors[id], tgt_prio);
393  readQueueSizes[curr_prio] -= moved_entries;
394  readQueueSizes[tgt_prio] += moved_entries;
395  } else if (pkt->isWrite()) {
396  panic_if(writeQueueSizes[curr_prio] < moved_entries,
397  "QoSMemCtrl::escalate requestor %s negative WRITE "
398  "packets for priority %d",
399  requestors[id], tgt_prio);
400  writeQueueSizes[curr_prio] -= moved_entries;
401  writeQueueSizes[tgt_prio] += moved_entries;
402  }
403 
404  // Change QoS priority and move packet
405  pkt->qosValue(tgt_prio);
406  queues[tgt_prio].push_back(pkt);
407 
408  // Erase element from source packet queue, this will
409  // increment the iterator
410  it = queues[curr_prio].erase(it);
411  panic_if(packetPriorities[id][curr_prio] < moved_entries,
412  "QoSMemCtrl::escalate requestor %s negative packets "
413  "for priority %d",
414  requestors[id], tgt_prio);
415 
416  packetPriorities[id][curr_prio] -= moved_entries;
417  packetPriorities[id][tgt_prio] += moved_entries;
418  } else {
419  // Increment iterator to next location in the queue
420  it++;
421  }
422  }
423 }
424 
425 template<typename Queues>
426 void
427 MemCtrl::escalate(std::initializer_list<Queues*> queues,
428  uint64_t queue_entry_size,
429  RequestorID id, uint8_t tgt_prio)
430 {
431  // If needed, initialize all counters and statistics
432  // for this requestor
433  addRequestor(id);
434 
435  DPRINTF(QOS,
436  "QoSMemCtrl::escalate Requestor %s [id %d] to priority "
437  "%d (currently %d packets)\n",requestors[id], id, tgt_prio,
438  packetPriorities[id][tgt_prio]);
439 
440  for (uint8_t curr_prio = 0; curr_prio < numPriorities(); ++curr_prio) {
441  // Skip target priority
442  if (curr_prio == tgt_prio)
443  continue;
444 
445  // Process other priority packet
446  while (packetPriorities[id][curr_prio] > 0) {
447  DPRINTF(QOS,
448  "QoSMemCtrl::escalate MID %d checking priority %d "
449  "(packets %d)- current packets in prio %d: %d\n"
450  "\t(source read %d source write %d target read %d, "
451  "target write %d)\n",
452  id, curr_prio, packetPriorities[id][curr_prio],
453  tgt_prio, packetPriorities[id][tgt_prio],
454  readQueueSizes[curr_prio],
455  writeQueueSizes[curr_prio], readQueueSizes[tgt_prio],
456  writeQueueSizes[tgt_prio]);
457 
458  // Check both read and write queue
459  for (auto q : queues) {
460  escalateQueues(*q, queue_entry_size, id,
461  curr_prio, tgt_prio);
462  }
463  }
464  }
465 
466  DPRINTF(QOS,
467  "QoSMemCtrl::escalate Completed requestor %s [id %d] to priority "
468  "%d (now %d packets)\n\t(total read %d, total write %d)\n",
469  requestors[id], id, tgt_prio, packetPriorities[id][tgt_prio],
470  readQueueSizes[tgt_prio], writeQueueSizes[tgt_prio]);
471 }
472 
473 template<typename Queues>
474 uint8_t
475 MemCtrl::qosSchedule(std::initializer_list<Queues*> queues,
476  const uint64_t queue_entry_size,
477  const PacketPtr pkt)
478 {
479  // Schedule packet.
480  uint8_t pkt_priority = schedule(pkt);
481 
482  assert(pkt_priority < numPriorities());
483 
484  pkt->qosValue(pkt_priority);
485 
486  if (qosSyncroScheduler) {
487  // Call the scheduling function on all other requestors.
488  for (const auto& requestor : requestors) {
489 
490  if (requestor.first == pkt->requestorId())
491  continue;
492 
493  uint8_t prio = schedule(requestor.first, 0);
494 
495  if (qosPriorityEscalation) {
496  DPRINTF(QOS,
497  "QoSMemCtrl::qosSchedule: (syncro) escalating "
498  "REQUESTOR %s to assigned priority %d\n",
499  _system->getRequestorName(requestor.first),
500  prio);
501  escalate(queues, queue_entry_size, requestor.first, prio);
502  }
503  }
504  }
505 
506  if (qosPriorityEscalation) {
507  DPRINTF(QOS,
508  "QoSMemCtrl::qosSchedule: escalating "
509  "REQUESTOR %s to assigned priority %d\n",
511  pkt_priority);
512  escalate(queues, queue_entry_size, pkt->requestorId(), pkt_priority);
513  }
514 
515  // Update last service tick for selected priority
516  serviceTick[pkt_priority] = curTick();
517 
518  return pkt_priority;
519 }
520 
521 } // namespace QoS
522 
523 #endif /* __MEM_QOS_MEM_CTRL_HH__ */
QoS::MemCtrl::getBusState
BusState getBusState() const
Gets the current bus state.
Definition: mem_ctrl.hh:276
QoS
Definition: mem_ctrl.cc:42
QoS::MemCtrl::MemCtrlStats::avgPriority
Stats::VectorStandardDeviation avgPriority
per-requestor average QoS priority
Definition: mem_ctrl.hh:133
QoS::MemCtrl::escalate
void escalate(std::initializer_list< Queues * > queues, uint64_t queue_entry_size, RequestorID id, uint8_t tgt_prio)
Escalates/demotes priority of all packets belonging to the passed requestor to given priority value.
Definition: mem_ctrl.hh:427
QoS::MemCtrl::requestTimes
std::unordered_map< RequestorID, std::unordered_map< uint64_t, std::deque< uint64_t > > > requestTimes
Hash of requestors - address of request - queue of times of request.
Definition: mem_ctrl.hh:95
QoS::MemCtrl
The QoS::MemCtrl is a base class for Memory objects which support QoS - it provides access to a set o...
Definition: mem_ctrl.hh:59
QoS::MemCtrl::setCurrentBusState
void setCurrentBusState()
Set current bus direction (READ or WRITE) from next selected one.
Definition: mem_ctrl.hh:219
system.hh
QoS::MemCtrl::stats
QoS::MemCtrl::MemCtrlStats stats
data
const char data[]
Definition: circlebuf.test.cc:42
QoS::MemCtrl::WRITE
@ WRITE
Definition: mem_ctrl.hh:63
QoS::MemCtrl::schedule
uint8_t schedule(RequestorID id, uint64_t data)
Definition: mem_ctrl.cc:207
QoS::MemCtrl::recordTurnaroundStats
void recordTurnaroundStats()
Record statistics on turnarounds based on busStateNext and busState values.
Definition: mem_ctrl.cc:348
QoS::MemCtrl::MemCtrlStats::priorityMaxLatency
Stats::Vector priorityMaxLatency
per-priority maximum latency
Definition: mem_ctrl.hh:143
QoS::MemCtrl::policy
const std::unique_ptr< Policy > policy
QoS Policy, assigns QoS priority to the incoming packets.
Definition: mem_ctrl.hh:67
QoS::MemCtrl::numPriorities
uint8_t numPriorities() const
Gets the total number of priority levels in the QoS memory controller.
Definition: mem_ctrl.hh:346
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:63
ArmISA::q
Bitfield< 27 > q
Definition: miscregs_types.hh:52
QoS::MemCtrl::READ
@ READ
Definition: mem_ctrl.hh:63
Packet::requestorId
RequestorID requestorId() const
Definition: packet.hh:740
std::vector< Tick >
QoS::MemCtrl::~MemCtrl
virtual ~MemCtrl()
Definition: mem_ctrl.cc:77
q_policy.hh
Stats::Vector
A vector of scalar stats.
Definition: statistics.hh:2575
ClockedObject
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Definition: clocked_object.hh:231
QoS::MemCtrl::MemCtrl
MemCtrl(const QoSMemCtrlParams *)
QoS Memory base class.
Definition: mem_ctrl.cc:44
QoS::MemCtrl::qosSchedule
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:475
Stats::Scalar
This is a simple scalar statistic, like a counter.
Definition: statistics.hh:2533
QoS::MemCtrl::logResponse
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:138
RequestorID
uint16_t RequestorID
Definition: request.hh:85
QoS::MemCtrl::totalWriteQueueSize
uint64_t totalWriteQueueSize
Total write request packets queue length in #packets.
Definition: mem_ctrl.hh:113
QoS::MemCtrl::qosSyncroScheduler
const bool qosSyncroScheduler
Enables QoS synchronized scheduling invokes the QoS scheduler on all requestors, at every packet arri...
Definition: mem_ctrl.hh:85
Packet::qosValue
uint8_t qosValue() const
QoS Value getter Returns 0 if QoS value was never set (constructor default).
Definition: packet.hh:729
divCeil
T divCeil(const T &a, const U &b)
Definition: intmath.hh:114
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1005
QoS::MemCtrl::MemCtrlStats::regStats
void regStats() override
Callback to set stat parameters.
Definition: mem_ctrl.cc:303
QoS::MemCtrl::packetPriorities
std::unordered_map< RequestorID, std::vector< uint64_t > > packetPriorities
Hash of requestors - number of packets queued per priority.
Definition: mem_ctrl.hh:91
QoS::MemCtrl::logRequest
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:81
QoS::MemCtrl::qosPriorityEscalation
const bool qosPriorityEscalation
Enables QoS priority escalation.
Definition: mem_ctrl.hh:79
QoS::MemCtrl::busStateNext
BusState busStateNext
bus state for next request event triggered
Definition: mem_ctrl.hh:122
System
Definition: system.hh:73
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:234
QoS::MemCtrl::addRequestor
void addRequestor(const RequestorID id)
Initializes dynamically counters and statistics for a given Requestor.
Definition: mem_ctrl.cc:264
QoS::MemCtrl::_system
System * _system
Pointer to the System object.
Definition: mem_ctrl.hh:155
QoS::MemCtrl::totalReadQueueSize
uint64_t totalReadQueueSize
Total read request packets queue length in #packets.
Definition: mem_ctrl.hh:110
QoS::MemCtrl::hasRequestor
bool hasRequestor(RequestorID id) const
hasRequestor returns true if the selected requestor(ID) has been registered in the memory controller,...
Definition: mem_ctrl.hh:295
QoS::MemCtrl::MemCtrlStats::numStayReadState
Stats::Scalar numStayReadState
Count the number of times bus staying in READ state.
Definition: mem_ctrl.hh:149
QoS::MemCtrl::getTotalReadQueueSize
uint64_t getTotalReadQueueSize() const
Gets the total combined READ queues size.
Definition: mem_ctrl.hh:323
QoS::MemCtrl::MemCtrlStats::memCtrl
const MemCtrl & memCtrl
Definition: mem_ctrl.hh:130
policy.hh
QoS::MemCtrl::getReadQueueSize
uint64_t getReadQueueSize(const uint8_t prio) const
Gets a READ queue size.
Definition: mem_ctrl.hh:306
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:142
QoS::MemCtrl::getServiceTick
Tick getServiceTick(const uint8_t prio) const
Gets the last service tick related to a QoS Priority.
Definition: mem_ctrl.hh:338
QoS::MemCtrl::MemCtrlStats::numWriteReadTurnArounds
Stats::Scalar numWriteReadTurnArounds
Count the number of turnarounds WRITE to READ.
Definition: mem_ctrl.hh:147
QoS::MemCtrl::readQueueSizes
std::vector< uint64_t > readQueueSizes
Read request packets queue length in #packets, per QoS priority.
Definition: mem_ctrl.hh:104
QoS::MemCtrl::MemCtrlStats::avgPriorityDistance
Stats::VectorStandardDeviation avgPriorityDistance
per-requestor average QoS distance between assigned and queued values
Definition: mem_ctrl.hh:138
QoS::MemCtrl::MemCtrlStats::numReadWriteTurnArounds
Stats::Scalar numReadWriteTurnArounds
Count the number of turnarounds READ to WRITE.
Definition: mem_ctrl.hh:145
QoS::MemCtrl::MemCtrlStats::priorityMinLatency
Stats::Vector priorityMinLatency
per-priority minimum latency
Definition: mem_ctrl.hh:141
QoS::MemCtrl::turnPolicy
const std::unique_ptr< TurnaroundPolicy > turnPolicy
QoS Bus Turnaround Policy: selects the bus direction (READ/WRITE)
Definition: mem_ctrl.hh:70
QoS::MemCtrl::BusState
BusState
Bus Direction.
Definition: mem_ctrl.hh:63
panic_if
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition: logging.hh:197
QoS::MemCtrl::serviceTick
std::vector< Tick > serviceTick
Vector of QoS priorities/last service time.
Definition: mem_ctrl.hh:101
QoS::MemCtrl::MemCtrlStats::MemCtrlStats
MemCtrlStats(MemCtrl &mc)
Definition: mem_ctrl.cc:277
clocked_object.hh
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:257
QoS::MemCtrl::getTotalWriteQueueSize
uint64_t getTotalWriteQueueSize() const
Gets the total combined WRITE queues size.
Definition: mem_ctrl.hh:330
Stats::Group
Statistics container.
Definition: group.hh:83
addr
ip6_addr_t addr
Definition: inet.hh:423
QoS::MemCtrl::MemCtrlStats
Definition: mem_ctrl.hh:124
QoS::MemCtrl::getWriteQueueSize
uint64_t getWriteQueueSize(const uint8_t prio) const
Gets a WRITE queue size.
Definition: mem_ctrl.hh:315
System::getRequestorName
std::string getRequestorName(RequestorID requestor_id)
Get the name of an object for a given request id.
Definition: system.cc:651
QoS::MemCtrl::system
System * system() const
read the system pointer
Definition: mem_ctrl.hh:350
QoS::MemCtrl::requestors
std::unordered_map< RequestorID, const std::string > requestors
Hash of requestor ID - requestor name.
Definition: mem_ctrl.hh:88
QoS::MemCtrl::MemCtrlStats::numStayWriteState
Stats::Scalar numStayWriteState
Count the number of times bus staying in WRITE state.
Definition: mem_ctrl.hh:151
QoS::MemCtrl::queuePolicy
const std::unique_ptr< QueuePolicy > queuePolicy
QoS Queue Policy: selects packet among same-priority queue.
Definition: mem_ctrl.hh:73
Stats::VectorStandardDeviation
This is a vector of StandardDeviation stats.
Definition: statistics.hh:2758
QoS::MemCtrl::busState
BusState busState
Bus state used to control the read/write switching and drive the scheduling of the next request.
Definition: mem_ctrl.hh:119
QoS::MemCtrl::selectNextBusState
BusState selectNextBusState()
Returns next bus direction (READ or WRITE) based on configured policy.
Definition: mem_ctrl.cc:236
QoS::MemCtrl::getBusStateNext
BusState getBusStateNext() const
Gets the next bus state.
Definition: mem_ctrl.hh:283
QoS::MemCtrl::escalateQueues
void escalateQueues(Queues &queues, uint64_t queue_entry_size, RequestorID id, uint8_t curr_prio, uint8_t tgt_prio)
Escalates/demotes priority of all packets belonging to the passed requestor to given priority value i...
Definition: mem_ctrl.hh:355
ArmISA::id
Bitfield< 33 > id
Definition: miscregs_types.hh:247
QoS::MemCtrl::_numPriorities
const uint8_t _numPriorities
Number of configured QoS priorities.
Definition: mem_ctrl.hh:76
curTick
Tick curTick()
The current simulated tick.
Definition: core.hh:45
QoS::MemCtrl::writeQueueSizes
std::vector< uint64_t > writeQueueSizes
Write request packets queue length in #packets, per QoS priority.
Definition: mem_ctrl.hh:107

Generated on Wed Sep 30 2020 14:02:13 for gem5 by doxygen 1.8.17