gem5  v21.0.0.0
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Sequencer.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2021 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  * Copyright (c) 1999-2008 Mark D. Hill and David A. Wood
15  * Copyright (c) 2013 Advanced Micro Devices, Inc.
16  * All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions are
20  * met: redistributions of source code must retain the above copyright
21  * notice, this list of conditions and the following disclaimer;
22  * redistributions in binary form must reproduce the above copyright
23  * notice, this list of conditions and the following disclaimer in the
24  * documentation and/or other materials provided with the distribution;
25  * neither the name of the copyright holders nor the names of its
26  * contributors may be used to endorse or promote products derived from
27  * this software without specific prior written permission.
28  *
29  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40  */
41 
43 
44 #include "arch/x86/ldstflags.hh"
45 #include "base/logging.hh"
46 #include "base/str.hh"
48 #include "debug/LLSC.hh"
49 #include "debug/MemoryAccess.hh"
50 #include "debug/ProtocolTrace.hh"
51 #include "debug/RubySequencer.hh"
52 #include "debug/RubyStats.hh"
53 #include "mem/packet.hh"
55 #include "mem/ruby/protocol/PrefetchBit.hh"
56 #include "mem/ruby/protocol/RubyAccessMode.hh"
60 #include "sim/system.hh"
61 
63  : RubyPort(p), m_IncompleteTimes(MachineType_NUM),
64  deadlockCheckEvent([this]{ wakeup(); }, "Sequencer deadlock check")
65 {
66  m_outstanding_count = 0;
67 
68  m_dataCache_ptr = p.dcache;
69  m_max_outstanding_requests = p.max_outstanding_requests;
70  m_deadlock_threshold = p.deadlock_threshold;
71 
72  m_coreId = p.coreid; // for tracking the two CorePair sequencers
73  assert(m_max_outstanding_requests > 0);
74  assert(m_deadlock_threshold > 0);
75 
76  m_runningGarnetStandalone = p.garnet_standalone;
77 
78 
79  // These statistical variables are not for display.
80  // The profiler will collate these across different
81  // sequencers and display those collated statistics.
82  m_outstandReqHist.init(10);
83  m_latencyHist.init(10);
84  m_hitLatencyHist.init(10);
85  m_missLatencyHist.init(10);
86 
87  for (int i = 0; i < RubyRequestType_NUM; i++) {
88  m_typeLatencyHist.push_back(new Stats::Histogram());
89  m_typeLatencyHist[i]->init(10);
90 
91  m_hitTypeLatencyHist.push_back(new Stats::Histogram());
92  m_hitTypeLatencyHist[i]->init(10);
93 
94  m_missTypeLatencyHist.push_back(new Stats::Histogram());
95  m_missTypeLatencyHist[i]->init(10);
96  }
97 
98  for (int i = 0; i < MachineType_NUM; i++) {
99  m_hitMachLatencyHist.push_back(new Stats::Histogram());
100  m_hitMachLatencyHist[i]->init(10);
101 
102  m_missMachLatencyHist.push_back(new Stats::Histogram());
103  m_missMachLatencyHist[i]->init(10);
104 
105  m_IssueToInitialDelayHist.push_back(new Stats::Histogram());
106  m_IssueToInitialDelayHist[i]->init(10);
107 
108  m_InitialToForwardDelayHist.push_back(new Stats::Histogram());
109  m_InitialToForwardDelayHist[i]->init(10);
110 
111  m_ForwardToFirstResponseDelayHist.push_back(new Stats::Histogram());
112  m_ForwardToFirstResponseDelayHist[i]->init(10);
113 
114  m_FirstResponseToCompletionDelayHist.push_back(new Stats::Histogram());
115  m_FirstResponseToCompletionDelayHist[i]->init(10);
116  }
117 
118  for (int i = 0; i < RubyRequestType_NUM; i++) {
119  m_hitTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
120  m_missTypeMachLatencyHist.push_back(std::vector<Stats::Histogram *>());
121 
122  for (int j = 0; j < MachineType_NUM; j++) {
123  m_hitTypeMachLatencyHist[i].push_back(new Stats::Histogram());
124  m_hitTypeMachLatencyHist[i][j]->init(10);
125 
126  m_missTypeMachLatencyHist[i].push_back(new Stats::Histogram());
127  m_missTypeMachLatencyHist[i][j]->init(10);
128  }
129  }
130 
131 }
132 
134 {
135 }
136 
137 void
139 {
140  fatal_if(m_dataCache_ptr == NULL,
141  "%s must have a dcache object to support LLSC requests.", name());
142  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
143  if (line) {
144  line->setLocked(m_version);
145  DPRINTF(LLSC, "LLSC Monitor - inserting load linked - "
146  "addr=0x%lx - cpu=%u\n", claddr, m_version);
147  }
148 }
149 
150 void
152 {
153  // clear monitor is called for all stores and evictions
154  if (m_dataCache_ptr == NULL)
155  return;
156  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
157  if (line && line->isLocked(m_version)) {
158  line->clearLocked();
159  DPRINTF(LLSC, "LLSC Monitor - clearing due to store - "
160  "addr=0x%lx - cpu=%u\n", claddr, m_version);
161  }
162 }
163 
164 bool
166 {
167  fatal_if(m_dataCache_ptr == NULL,
168  "%s must have a dcache object to support LLSC requests.", name());
169  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
170  if (!line)
171  return false;
172 
173  DPRINTF(LLSC, "LLSC Monitor - clearing due to "
174  "store conditional - "
175  "addr=0x%lx - cpu=%u\n",
176  claddr, m_version);
177 
178  if (line->isLocked(m_version)) {
179  line->clearLocked();
180  return true;
181  } else {
182  line->clearLocked();
183  return false;
184  }
185 }
186 
187 bool
189 {
190  assert(m_dataCache_ptr != NULL);
191  const Addr claddr = makeLineAddress(address);
192  AbstractCacheEntry *line = m_dataCache_ptr->lookup(claddr);
193  if (!line)
194  return false;
195 
196  if (line->isLocked(m_version)) {
197  return true;
198  } else {
199  return false;
200  }
201 }
202 
203 void
205 {
207 }
208 
209 void
211 {
212  assert(drainState() != DrainState::Draining);
213 
214  // Check for deadlock of any of the requests
215  Cycles current_time = curCycle();
216 
217  // Check across all outstanding requests
218  int total_outstanding = 0;
219 
220  for (const auto &table_entry : m_RequestTable) {
221  for (const auto &seq_req : table_entry.second) {
222  if (current_time - seq_req.issue_time < m_deadlock_threshold)
223  continue;
224 
225  panic("Possible Deadlock detected. Aborting!\n version: %d "
226  "request.paddr: 0x%x m_readRequestTable: %d current time: "
227  "%u issue_time: %d difference: %d\n", m_version,
228  seq_req.pkt->getAddr(), table_entry.second.size(),
229  current_time * clockPeriod(), seq_req.issue_time
230  * clockPeriod(), (current_time * clockPeriod())
231  - (seq_req.issue_time * clockPeriod()));
232  }
233  total_outstanding += table_entry.second.size();
234  }
235 
236  assert(m_outstanding_count == total_outstanding);
237 
238  if (m_outstanding_count > 0) {
239  // If there are still outstanding requests, keep checking
241  }
242 }
243 
244 int
246 {
247  int num_written = RubyPort::functionalWrite(func_pkt);
248 
249  for (const auto &table_entry : m_RequestTable) {
250  for (const auto& seq_req : table_entry.second) {
251  if (seq_req.functionalWrite(func_pkt))
252  ++num_written;
253  }
254  }
255 
256  return num_written;
257 }
258 
260 {
265  for (int i = 0; i < RubyRequestType_NUM; i++) {
266  m_typeLatencyHist[i]->reset();
267  m_hitTypeLatencyHist[i]->reset();
268  m_missTypeLatencyHist[i]->reset();
269  for (int j = 0; j < MachineType_NUM; j++) {
270  m_hitTypeMachLatencyHist[i][j]->reset();
271  m_missTypeMachLatencyHist[i][j]->reset();
272  }
273  }
274 
275  for (int i = 0; i < MachineType_NUM; i++) {
276  m_missMachLatencyHist[i]->reset();
277  m_hitMachLatencyHist[i]->reset();
278 
279  m_IssueToInitialDelayHist[i]->reset();
280  m_InitialToForwardDelayHist[i]->reset();
283 
284  m_IncompleteTimes[i] = 0;
285  }
286 }
287 
288 // Insert the request in the request table. Return RequestStatus_Aliased
289 // if the entry was already present.
290 RequestStatus
291 Sequencer::insertRequest(PacketPtr pkt, RubyRequestType primary_type,
292  RubyRequestType secondary_type)
293 {
294  // See if we should schedule a deadlock check
295  if (!deadlockCheckEvent.scheduled() &&
298  }
299 
300  Addr line_addr = makeLineAddress(pkt->getAddr());
301  // Check if there is any outstanding request for the same cache line.
302  auto &seq_req_list = m_RequestTable[line_addr];
303  // Create a default entry
304  seq_req_list.emplace_back(pkt, primary_type,
305  secondary_type, curCycle());
307 
308  if (seq_req_list.size() > 1) {
309  return RequestStatus_Aliased;
310  }
311 
313 
314  return RequestStatus_Ready;
315 }
316 
317 void
319 {
321 }
322 
323 void
324 Sequencer::recordMissLatency(SequencerRequest* srequest, bool llscSuccess,
325  const MachineType respondingMach,
326  bool isExternalHit, Cycles initialRequestTime,
327  Cycles forwardRequestTime,
328  Cycles firstResponseTime)
329 {
330  RubyRequestType type = srequest->m_type;
331  Cycles issued_time = srequest->issue_time;
332  Cycles completion_time = curCycle();
333 
334  assert(curCycle() >= issued_time);
335  Cycles total_lat = completion_time - issued_time;
336 
337  if ((initialRequestTime != 0) && (initialRequestTime < issued_time)) {
338  // if the request was combined in the protocol with an earlier request
339  // for the same address, it is possible that it will return an
340  // initialRequestTime corresponding the earlier request. Since Cycles
341  // is unsigned, we can't let this request get profiled below.
342 
343  total_lat = Cycles(0);
344  }
345 
346  DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %s %d cycles\n",
347  curTick(), m_version, "Seq", llscSuccess ? "Done" : "SC_Failed",
348  "", "", printAddress(srequest->pkt->getAddr()), total_lat);
349 
350  m_latencyHist.sample(total_lat);
351  m_typeLatencyHist[type]->sample(total_lat);
352 
353  if (isExternalHit) {
354  m_missLatencyHist.sample(total_lat);
355  m_missTypeLatencyHist[type]->sample(total_lat);
356 
357  if (respondingMach != MachineType_NUM) {
358  m_missMachLatencyHist[respondingMach]->sample(total_lat);
359  m_missTypeMachLatencyHist[type][respondingMach]->sample(total_lat);
360 
361  if ((issued_time <= initialRequestTime) &&
362  (initialRequestTime <= forwardRequestTime) &&
363  (forwardRequestTime <= firstResponseTime) &&
364  (firstResponseTime <= completion_time)) {
365 
366  m_IssueToInitialDelayHist[respondingMach]->sample(
367  initialRequestTime - issued_time);
368  m_InitialToForwardDelayHist[respondingMach]->sample(
369  forwardRequestTime - initialRequestTime);
370  m_ForwardToFirstResponseDelayHist[respondingMach]->sample(
371  firstResponseTime - forwardRequestTime);
372  m_FirstResponseToCompletionDelayHist[respondingMach]->sample(
373  completion_time - firstResponseTime);
374  } else {
375  m_IncompleteTimes[respondingMach]++;
376  }
377  }
378  } else {
379  m_hitLatencyHist.sample(total_lat);
380  m_hitTypeLatencyHist[type]->sample(total_lat);
381 
382  if (respondingMach != MachineType_NUM) {
383  m_hitMachLatencyHist[respondingMach]->sample(total_lat);
384  m_hitTypeMachLatencyHist[type][respondingMach]->sample(total_lat);
385  }
386  }
387 }
388 
389 void
391 {
392  llscClearMonitor(address);
393  writeCallback(address, data);
394 }
395 
396 void
398  const bool externalHit, const MachineType mach,
399  const Cycles initialRequestTime,
400  const Cycles forwardRequestTime,
401  const Cycles firstResponseTime,
402  const bool noCoales)
403 {
404  //
405  // Free the whole list as we assume we have had the exclusive access
406  // to this cache line when response for the write comes back
407  //
408  assert(address == makeLineAddress(address));
409  assert(m_RequestTable.find(address) != m_RequestTable.end());
410  auto &seq_req_list = m_RequestTable[address];
411 
412  // Perform hitCallback on every cpu request made to this cache block while
413  // ruby request was outstanding. Since only 1 ruby request was made,
414  // profile the ruby latency once.
415  bool ruby_request = true;
416  int aliased_stores = 0;
417  int aliased_loads = 0;
418  while (!seq_req_list.empty()) {
419  SequencerRequest &seq_req = seq_req_list.front();
420 
421  if (noCoales && !ruby_request) {
422  // Do not process follow-up requests
423  // (e.g. if full line no present)
424  // Reissue to the cache hierarchy
425  issueRequest(seq_req.pkt, seq_req.m_second_type);
426  break;
427  }
428 
429  if (ruby_request) {
430  assert(seq_req.m_type != RubyRequestType_LD);
431  assert(seq_req.m_type != RubyRequestType_Load_Linked);
432  assert(seq_req.m_type != RubyRequestType_IFETCH);
433  }
434 
435  // handle write request
436  if ((seq_req.m_type != RubyRequestType_LD) &&
437  (seq_req.m_type != RubyRequestType_Load_Linked) &&
438  (seq_req.m_type != RubyRequestType_IFETCH)) {
439  // LL/SC support (tested with ARMv8)
440  bool success = true;
441 
442  if (seq_req.m_type != RubyRequestType_Store_Conditional) {
443  // Regular stores to addresses being monitored
444  // will fail (remove) the monitor entry.
445  llscClearMonitor(address);
446  } else {
447  // Store conditionals must first check the monitor
448  // if they will succeed or not
449  success = llscStoreConditional(address);
450  seq_req.pkt->req->setExtraData(success ? 1 : 0);
451  }
452 
453  // Handle SLICC block_on behavior for Locked_RMW accesses. NOTE: the
454  // address variable here is assumed to be a line address, so when
455  // blocking buffers, must check line addresses.
456  if (seq_req.m_type == RubyRequestType_Locked_RMW_Read) {
457  // blockOnQueue blocks all first-level cache controller queues
458  // waiting on memory accesses for the specified address that go
459  // to the specified queue. In this case, a Locked_RMW_Write must
460  // go to the mandatory_q before unblocking the first-level
461  // controller. This will block standard loads, stores, ifetches,
462  // etc.
464  } else if (seq_req.m_type == RubyRequestType_Locked_RMW_Write) {
465  m_controller->unblock(address);
466  }
467 
468  if (ruby_request) {
469  recordMissLatency(&seq_req, success, mach, externalHit,
470  initialRequestTime, forwardRequestTime,
471  firstResponseTime);
472  } else {
473  aliased_stores++;
474  }
475  markRemoved();
476  hitCallback(&seq_req, data, success, mach, externalHit,
477  initialRequestTime, forwardRequestTime,
478  firstResponseTime, !ruby_request);
479  ruby_request = false;
480  } else {
481  // handle read request
482  assert(!ruby_request);
483  markRemoved();
484  aliased_loads++;
485  hitCallback(&seq_req, data, true, mach, externalHit,
486  initialRequestTime, forwardRequestTime,
487  firstResponseTime, !ruby_request);
488  }
489  seq_req_list.pop_front();
490  }
491 
492  // free all outstanding requests corresponding to this address
493  if (seq_req_list.empty()) {
494  m_RequestTable.erase(address);
495  }
496 }
497 
498 void
500  bool externalHit, const MachineType mach,
501  Cycles initialRequestTime,
502  Cycles forwardRequestTime,
503  Cycles firstResponseTime)
504 {
505  //
506  // Free up read requests until we hit the first Write request
507  // or end of the corresponding list.
508  //
509  assert(address == makeLineAddress(address));
510  assert(m_RequestTable.find(address) != m_RequestTable.end());
511  auto &seq_req_list = m_RequestTable[address];
512 
513  // Perform hitCallback on every cpu request made to this cache block while
514  // ruby request was outstanding. Since only 1 ruby request was made,
515  // profile the ruby latency once.
516  bool ruby_request = true;
517  int aliased_loads = 0;
518  while (!seq_req_list.empty()) {
519  SequencerRequest &seq_req = seq_req_list.front();
520  if (ruby_request) {
521  assert((seq_req.m_type == RubyRequestType_LD) ||
522  (seq_req.m_type == RubyRequestType_Load_Linked) ||
523  (seq_req.m_type == RubyRequestType_IFETCH));
524  } else {
525  aliased_loads++;
526  }
527  if ((seq_req.m_type != RubyRequestType_LD) &&
528  (seq_req.m_type != RubyRequestType_Load_Linked) &&
529  (seq_req.m_type != RubyRequestType_IFETCH)) {
530  // Write request: reissue request to the cache hierarchy
531  issueRequest(seq_req.pkt, seq_req.m_second_type);
532  break;
533  }
534  if (ruby_request) {
535  recordMissLatency(&seq_req, true, mach, externalHit,
536  initialRequestTime, forwardRequestTime,
537  firstResponseTime);
538  }
539  markRemoved();
540  hitCallback(&seq_req, data, true, mach, externalHit,
541  initialRequestTime, forwardRequestTime,
542  firstResponseTime, !ruby_request);
543  ruby_request = false;
544  seq_req_list.pop_front();
545  }
546 
547  // free all outstanding requests corresponding to this address
548  if (seq_req_list.empty()) {
549  m_RequestTable.erase(address);
550  }
551 }
552 
553 void
555  bool llscSuccess,
556  const MachineType mach, const bool externalHit,
557  const Cycles initialRequestTime,
558  const Cycles forwardRequestTime,
559  const Cycles firstResponseTime,
560  const bool was_coalesced)
561 {
562  warn_once("Replacement policy updates recently became the responsibility "
563  "of SLICC state machines. Make sure to setMRU() near callbacks "
564  "in .sm files!");
565 
566  PacketPtr pkt = srequest->pkt;
567  Addr request_address(pkt->getAddr());
568  RubyRequestType type = srequest->m_type;
569 
570  if (was_coalesced) {
571  // Notify the controller about a coalesced request so it can properly
572  // account for it in its hit/miss stats and/or train prefetchers
573  // (this is protocol-dependent)
574  m_controller->notifyCoalesced(request_address, type, pkt->req,
575  data, externalHit);
576  }
577 
578  // Load-linked handling
579  if (type == RubyRequestType_Load_Linked) {
580  Addr line_addr = makeLineAddress(request_address);
581  llscLoadLinked(line_addr);
582  }
583 
584  // update the data unless it is a non-data-carrying flush
586  data.setData(pkt);
587  } else if (!pkt->isFlush()) {
588  if ((type == RubyRequestType_LD) ||
589  (type == RubyRequestType_IFETCH) ||
590  (type == RubyRequestType_RMW_Read) ||
591  (type == RubyRequestType_Locked_RMW_Read) ||
592  (type == RubyRequestType_Load_Linked)) {
593  pkt->setData(
594  data.getData(getOffset(request_address), pkt->getSize()));
595  DPRINTF(RubySequencer, "read data %s\n", data);
596  } else if (pkt->req->isSwap()) {
597  assert(!pkt->isMaskedWrite());
598  std::vector<uint8_t> overwrite_val(pkt->getSize());
599  pkt->writeData(&overwrite_val[0]);
600  pkt->setData(
601  data.getData(getOffset(request_address), pkt->getSize()));
602  data.setData(&overwrite_val[0],
603  getOffset(request_address), pkt->getSize());
604  DPRINTF(RubySequencer, "swap data %s\n", data);
605  } else if (type != RubyRequestType_Store_Conditional || llscSuccess) {
606  // Types of stores set the actual data here, apart from
607  // failed Store Conditional requests
608  data.setData(pkt);
609  DPRINTF(RubySequencer, "set data %s\n", data);
610  }
611  }
612 
613  // If using the RubyTester, update the RubyTester sender state's
614  // subBlock with the recieved data. The tester will later access
615  // this state.
616  if (m_usingRubyTester) {
617  DPRINTF(RubySequencer, "hitCallback %s 0x%x using RubyTester\n",
618  pkt->cmdString(), pkt->getAddr());
619  RubyTester::SenderState* testerSenderState =
621  assert(testerSenderState);
622  testerSenderState->subBlock.mergeFrom(data);
623  }
624 
627  assert(pkt->req);
628  delete pkt;
629  rs->m_cache_recorder->enqueueNextFetchRequest();
630  } else if (RubySystem::getCooldownEnabled()) {
631  delete pkt;
632  rs->m_cache_recorder->enqueueNextFlushRequest();
633  } else {
634  ruby_hit_callback(pkt);
636  }
637 }
638 
639 bool
641 {
642  return m_RequestTable.empty();
643 }
644 
645 RequestStatus
647 {
648  // HTM abort signals must be allowed to reach the Sequencer
649  // the same cycle they are issued. They cannot be retried.
651  !pkt->req->isHTMAbort()) {
652  return RequestStatus_BufferFull;
653  }
654 
655  RubyRequestType primary_type = RubyRequestType_NULL;
656  RubyRequestType secondary_type = RubyRequestType_NULL;
657 
658  if (pkt->isLLSC()) {
659  // LL/SC instructions need to be handled carefully by the cache
660  // coherence protocol to ensure they follow the proper semantics. In
661  // particular, by identifying the operations as atomic, the protocol
662  // should understand that migratory sharing optimizations should not
663  // be performed (i.e. a load between the LL and SC should not steal
664  // away exclusive permission).
665  //
666  // The following logic works correctly with the semantics
667  // of armV8 LDEX/STEX instructions.
668 
669  if (pkt->isWrite()) {
670  DPRINTF(RubySequencer, "Issuing SC\n");
671  primary_type = RubyRequestType_Store_Conditional;
672 #if defined (PROTOCOL_MESI_Three_Level) || defined (PROTOCOL_MESI_Three_Level_HTM)
673  secondary_type = RubyRequestType_Store_Conditional;
674 #else
675  secondary_type = RubyRequestType_ST;
676 #endif
677  } else {
678  DPRINTF(RubySequencer, "Issuing LL\n");
679  assert(pkt->isRead());
680  primary_type = RubyRequestType_Load_Linked;
681  secondary_type = RubyRequestType_LD;
682  }
683  } else if (pkt->req->isLockedRMW()) {
684  //
685  // x86 locked instructions are translated to store cache coherence
686  // requests because these requests should always be treated as read
687  // exclusive operations and should leverage any migratory sharing
688  // optimization built into the protocol.
689  //
690  if (pkt->isWrite()) {
691  DPRINTF(RubySequencer, "Issuing Locked RMW Write\n");
692  primary_type = RubyRequestType_Locked_RMW_Write;
693  } else {
694  DPRINTF(RubySequencer, "Issuing Locked RMW Read\n");
695  assert(pkt->isRead());
696  primary_type = RubyRequestType_Locked_RMW_Read;
697  }
698  secondary_type = RubyRequestType_ST;
699  } else {
700  //
701  // To support SwapReq, we need to check isWrite() first: a SwapReq
702  // should always be treated like a write, but since a SwapReq implies
703  // both isWrite() and isRead() are true, check isWrite() first here.
704  //
705  if (pkt->isWrite()) {
706  //
707  // Note: M5 packets do not differentiate ST from RMW_Write
708  //
709  primary_type = secondary_type = RubyRequestType_ST;
710  } else if (pkt->isRead()) {
711  // hardware transactional memory commands
712  if (pkt->req->isHTMCmd()) {
713  primary_type = secondary_type = htmCmdToRubyRequestType(pkt);
714  } else if (pkt->req->isInstFetch()) {
715  primary_type = secondary_type = RubyRequestType_IFETCH;
716  } else {
717  bool storeCheck = false;
718  // only X86 need the store check
719  if (system->getArch() == Arch::X86ISA) {
720  uint32_t flags = pkt->req->getFlags();
721  storeCheck = flags &
723  }
724  if (storeCheck) {
725  primary_type = RubyRequestType_RMW_Read;
726  secondary_type = RubyRequestType_ST;
727  } else {
728  primary_type = secondary_type = RubyRequestType_LD;
729  }
730  }
731  } else if (pkt->isFlush()) {
732  primary_type = secondary_type = RubyRequestType_FLUSH;
733  } else {
734  panic("Unsupported ruby packet type\n");
735  }
736  }
737 
738  // Check if the line is blocked for a Locked_RMW
740  (primary_type != RubyRequestType_Locked_RMW_Write)) {
741  // Return that this request's cache line address aliases with
742  // a prior request that locked the cache line. The request cannot
743  // proceed until the cache line is unlocked by a Locked_RMW_Write
744  return RequestStatus_Aliased;
745  }
746 
747  RequestStatus status = insertRequest(pkt, primary_type, secondary_type);
748 
749  // It is OK to receive RequestStatus_Aliased, it can be considered Issued
750  if (status != RequestStatus_Ready && status != RequestStatus_Aliased)
751  return status;
752  // non-aliased with any existing request in the request table, just issue
753  // to the cache
754  if (status != RequestStatus_Aliased)
755  issueRequest(pkt, secondary_type);
756 
757  // TODO: issue hardware prefetches here
758  return RequestStatus_Issued;
759 }
760 
761 void
762 Sequencer::issueRequest(PacketPtr pkt, RubyRequestType secondary_type)
763 {
764  assert(pkt != NULL);
765  ContextID proc_id = pkt->req->hasContextId() ?
766  pkt->req->contextId() : InvalidContextID;
767 
768  ContextID core_id = coreId();
769 
770  // If valid, copy the pc to the ruby request
771  Addr pc = 0;
772  if (pkt->req->hasPC()) {
773  pc = pkt->req->getPC();
774  }
775 
776  // check if the packet has data as for example prefetch and flush
777  // requests do not
778  std::shared_ptr<RubyRequest> msg =
779  std::make_shared<RubyRequest>(clockEdge(), pkt->getAddr(),
780  pkt->getSize(), pc, secondary_type,
781  RubyAccessMode_Supervisor, pkt,
782  PrefetchBit_No, proc_id, core_id);
783 
784  DPRINTFR(ProtocolTrace, "%15s %3s %10s%20s %6s>%-6s %#x %s\n",
785  curTick(), m_version, "Seq", "Begin", "", "",
786  printAddress(msg->getPhysicalAddress()),
787  RubyRequestType_to_string(secondary_type));
788 
789  // hardware transactional memory
790  // If the request originates in a transaction,
791  // then mark the Ruby message as such.
792  if (pkt->isHtmTransactional()) {
793  msg->m_htmFromTransaction = true;
794  msg->m_htmTransactionUid = pkt->getHtmTransactionUid();
795  }
796 
797  Tick latency = cyclesToTicks(
798  m_controller->mandatoryQueueLatency(secondary_type));
799  assert(latency > 0);
800 
801  assert(m_mandatory_q_ptr != NULL);
802  m_mandatory_q_ptr->enqueue(msg, clockEdge(), latency);
803 }
804 
805 template <class KEY, class VALUE>
806 std::ostream &
807 operator<<(std::ostream &out, const std::unordered_map<KEY, VALUE> &map)
808 {
809  for (const auto &table_entry : map) {
810  out << "[ " << table_entry.first << " =";
811  for (const auto &seq_req : table_entry.second) {
812  out << " " << RubyRequestType_to_string(seq_req.m_second_type);
813  }
814  }
815  out << " ]";
816 
817  return out;
818 }
819 
820 void
821 Sequencer::print(std::ostream& out) const
822 {
823  out << "[Sequencer: " << m_version
824  << ", outstanding requests: " << m_outstanding_count
825  << ", request table: " << m_RequestTable
826  << "]";
827 }
828 
829 void
830 Sequencer::recordRequestType(SequencerRequestType requestType) {
831  DPRINTF(RubyStats, "Recorded statistic: %s\n",
832  SequencerRequestType_to_string(requestType));
833 }
834 
835 void
837 {
838  llscClearMonitor(address);
839  ruby_eviction_callback(address);
840 }
AbstractCacheEntry
Definition: AbstractCacheEntry.hh:57
ArmISA::status
Bitfield< 5, 0 > status
Definition: miscregs_types.hh:417
AbstractController::blockOnQueue
void blockOnQueue(Addr, MessageBuffer *)
Definition: AbstractController.cc:306
X86ISA::FlagShift
const int FlagShift
Definition: ldstflags.hh:50
Event::scheduled
bool scheduled() const
Determine if the current event is scheduled.
Definition: eventq.hh:462
Sequencer::m_ForwardToFirstResponseDelayHist
std::vector< Stats::Histogram * > m_ForwardToFirstResponseDelayHist
Definition: Sequencer.hh:269
RubyPort::m_usingRubyTester
bool m_usingRubyTester
Definition: RubyPort.hh:192
RubyPort::ruby_hit_callback
void ruby_hit_callback(PacketPtr pkt)
Definition: RubyPort.cc:434
Sequencer::m_outstanding_count
int m_outstanding_count
Definition: Sequencer.hh:232
Sequencer::functionalWrite
virtual int functionalWrite(Packet *func_pkt) override
Definition: Sequencer.cc:245
Sequencer::m_outstandReqHist
Stats::Histogram m_outstandReqHist
Histogram for number of outstanding requests per cycle.
Definition: Sequencer.hh:240
system.hh
SequencerRequest::pkt
PacketPtr pkt
Definition: Sequencer.hh:58
Sequencer::empty
virtual bool empty() const
Definition: Sequencer.cc:640
Profiler.hh
Sequencer::m_missMachLatencyHist
std::vector< Stats::Histogram * > m_missMachLatencyHist
Histograms for profiling the latencies for requests that required external messages.
Definition: Sequencer.hh:263
CacheMemory::lookup
AbstractCacheEntry * lookup(Addr address)
Definition: CacheMemory.cc:335
data
const char data[]
Definition: circlebuf.test.cc:47
Sequencer::resetStats
void resetStats() override
Callback to reset stats.
Definition: Sequencer.cc:259
htmCmdToRubyRequestType
RubyRequestType htmCmdToRubyRequestType(const Packet *pkt)
Definition: RubySlicc_Util.hh:159
Packet::getAddr
Addr getAddr() const
Definition: packet.hh:755
Sequencer::m_max_outstanding_requests
int m_max_outstanding_requests
Definition: Sequencer.hh:220
makeLineAddress
Addr makeLineAddress(Addr addr)
Definition: Address.cc:54
AbstractCacheEntry::setLocked
void setLocked(int context)
Definition: AbstractCacheEntry.cc:78
Packet::writeData
void writeData(uint8_t *p) const
Copy data from the packet to the memory at the provided pointer.
Definition: packet.hh:1255
Packet::isHtmTransactional
bool isHtmTransactional() const
Returns whether or not this packet/request originates in the CPU executing in transactional mode,...
Definition: packet.cc:544
Sequencer::writeCallbackScFail
void writeCallbackScFail(Addr address, DataBlock &data)
Proxy function to writeCallback that first invalidates the line address in the local monitor.
Definition: Sequencer.cc:390
RubyPort::Params
RubyPortParams Params
Definition: RubyPort.hh:146
Sequencer::Sequencer
Sequencer(const Params &)
Definition: Sequencer.cc:62
warn_once
#define warn_once(...)
Definition: logging.hh:243
ArmISA::i
Bitfield< 7 > i
Definition: miscregs_types.hh:63
Sequencer::m_hitTypeLatencyHist
std::vector< Stats::Histogram * > m_hitTypeLatencyHist
Definition: Sequencer.hh:249
Sequencer::m_IssueToInitialDelayHist
std::vector< Stats::Histogram * > m_IssueToInitialDelayHist
Histograms for recording the breakdown of miss latency.
Definition: Sequencer.hh:267
ContextID
int ContextID
Globally unique thread context ID.
Definition: types.hh:237
RubyPort::testDrainComplete
void testDrainComplete()
Definition: RubyPort.cc:483
SequencerRequest::m_type
RubyRequestType m_type
Definition: Sequencer.hh:59
Packet::isRead
bool isRead() const
Definition: packet.hh:557
Sequencer::m_dataCache_ptr
CacheMemory * m_dataCache_ptr
Definition: Sequencer.hh:222
Tick
uint64_t Tick
Tick count type.
Definition: types.hh:59
Sequencer::wakeup
virtual void wakeup()
Definition: Sequencer.cc:210
Sequencer::~Sequencer
~Sequencer()
Definition: Sequencer.cc:133
Packet::req
RequestPtr req
A pointer to the original request.
Definition: packet.hh:341
Sequencer::makeRequest
RequestStatus makeRequest(PacketPtr pkt) override
Definition: Sequencer.cc:646
RubyRequest.hh
ldstflags.hh
Packet::isLLSC
bool isLLSC() const
Definition: packet.hh:583
std::vector< Stats::Histogram * >
InvalidContextID
const ContextID InvalidContextID
Definition: types.hh:238
Packet::getSize
unsigned getSize() const
Definition: packet.hh:765
MessageBuffer::enqueue
void enqueue(MsgPtr message, Tick curTime, Tick delta)
Definition: MessageBuffer.cc:191
Sequencer::coreId
int coreId() const
Definition: Sequencer.hh:137
Sequencer::m_RequestTable
std::unordered_map< Addr, std::list< SequencerRequest > > m_RequestTable
Definition: Sequencer.hh:211
Sequencer::m_hitLatencyHist
Stats::Histogram m_hitLatencyHist
Histogram for holding latency profile of all requests that hit in the controller connected to this se...
Definition: Sequencer.hh:248
AbstractController::isBlocked
bool isBlocked(Addr) const
Definition: AbstractController.cc:313
Sequencer::m_latencyHist
Stats::Histogram m_latencyHist
Histogram for holding latency profile of all requests.
Definition: Sequencer.hh:243
Sequencer::m_missTypeMachLatencyHist
std::vector< std::vector< Stats::Histogram * > > m_missTypeMachLatencyHist
Definition: Sequencer.hh:264
Packet::setData
void setData(const uint8_t *p)
Copy data into the packet from the provided pointer.
Definition: packet.hh:1226
DataBlock
Definition: DataBlock.hh:54
packet.hh
RubyPort::m_mandatory_q_ptr
MessageBuffer * m_mandatory_q_ptr
Definition: RubyPort.hh:191
Stats::Histogram
A simple histogram stat.
Definition: statistics.hh:2126
SequencerRequest::issue_time
Cycles issue_time
Definition: Sequencer.hh:61
SequencerRequest::m_second_type
RubyRequestType m_second_type
Definition: Sequencer.hh:60
str.hh
System::getArch
Arch getArch() const
Get the architecture.
Definition: system.hh:377
RubyPort::m_controller
AbstractController * m_controller
Definition: RubyPort.hh:190
Sequencer::print
virtual void print(std::ostream &out) const
Definition: Sequencer.cc:821
ArmISA::j
Bitfield< 24 > j
Definition: miscregs_types.hh:54
AbstractController::unblock
void unblock(Addr)
Definition: AbstractController.cc:319
EventManager::schedule
void schedule(Event &event, Tick when)
Definition: eventq.hh:1016
operator<<
std::ostream & operator<<(std::ostream &out, const std::unordered_map< KEY, VALUE > &map)
Definition: Sequencer.cc:807
Clocked::cyclesToTicks
Tick cyclesToTicks(Cycles c) const
Definition: clocked_object.hh:224
Sequencer::insertRequest
virtual RequestStatus insertRequest(PacketPtr pkt, RubyRequestType primary_type, RubyRequestType secondary_type)
Definition: Sequencer.cc:291
Sequencer::recordMissLatency
void recordMissLatency(SequencerRequest *srequest, bool llscSuccess, const MachineType respondingMach, bool isExternalHit, Cycles initialRequestTime, Cycles forwardRequestTime, Cycles firstResponseTime)
Definition: Sequencer.cc:324
Sequencer::llscStoreConditional
bool llscStoreConditional(const Addr)
Searches for cache line address in the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:165
Sequencer::readCallback
void readCallback(Addr address, DataBlock &data, const bool externalHit=false, const MachineType mach=MachineType_NUM, const Cycles initialRequestTime=Cycles(0), const Cycles forwardRequestTime=Cycles(0), const Cycles firstResponseTime=Cycles(0))
Definition: Sequencer.cc:499
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:237
RubySystem
Definition: RubySystem.hh:52
Packet::cmdString
const std::string & cmdString() const
Return the string name of the cmd field (for debugging and tracing).
Definition: packet.hh:552
MipsISA::pc
Bitfield< 4 > pc
Definition: pra_constants.hh:240
RubyPort
Definition: RubyPort.hh:58
Sequencer::markRemoved
void markRemoved()
Definition: Sequencer.cc:318
Packet::findNextSenderState
T * findNextSenderState() const
Go through the sender state stack and return the first instance that is of type T (as determined by a...
Definition: packet.hh:539
RubyTester.hh
Sequencer::m_missLatencyHist
Stats::Histogram m_missLatencyHist
Histogram for holding latency profile of all requests that miss in the controller connected to this s...
Definition: Sequencer.hh:258
Clocked::curCycle
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Definition: clocked_object.hh:192
Sequencer::llscLoadLinked
void llscLoadLinked(const Addr)
Places the cache line address into the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:138
Clocked::clockEdge
Tick clockEdge(Cycles cycles=Cycles(0)) const
Determine the tick when a cycle begins, by default the current one, but the argument also enables the...
Definition: clocked_object.hh:174
Sequencer::deadlockCheckEvent
EventFunctionWrapper deadlockCheckEvent
Definition: Sequencer.hh:273
RubyTester::SenderState
Definition: RubyTester.hh:86
DPRINTFR
#define DPRINTFR(...)
Definition: trace.hh:239
RubySlicc_Util.hh
Sequencer::evictionCallback
void evictionCallback(Addr address)
Definition: Sequencer.cc:836
Sequencer::m_IncompleteTimes
std::vector< Stats::Counter > m_IncompleteTimes
Definition: Sequencer.hh:271
AbstractCacheEntry::clearLocked
void clearLocked()
Definition: AbstractCacheEntry.cc:85
Sequencer::llscClearMonitor
void llscClearMonitor(const Addr)
Removes the cache line address from the global monitor.
Definition: Sequencer.cc:151
RubyPort::system
System * system
Definition: RubyPort.hh:193
Sequencer::recordRequestType
void recordRequestType(SequencerRequestType requestType)
Definition: Sequencer.cc:830
Sequencer::hitCallback
void hitCallback(SequencerRequest *srequest, DataBlock &data, bool llscSuccess, const MachineType mach, const bool externalHit, const Cycles initialRequestTime, const Cycles forwardRequestTime, const Cycles firstResponseTime, const bool was_coalesced)
Definition: Sequencer.cc:554
RubySystem.hh
Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:148
Sequencer::m_hitTypeMachLatencyHist
std::vector< std::vector< Stats::Histogram * > > m_hitTypeMachLatencyHist
Definition: Sequencer.hh:254
RubySystem::getCooldownEnabled
static bool getCooldownEnabled()
Definition: RubySystem.hh:65
AbstractCacheEntry::isLocked
bool isLocked(int context) const
Definition: AbstractCacheEntry.cc:92
Clocked::clockPeriod
Tick clockPeriod() const
Definition: clocked_object.hh:214
Sequencer::llscCheckMonitor
bool llscCheckMonitor(const Addr)
Searches for cache line address in the global monitor tagged with this Sequencer object's version id.
Definition: Sequencer.cc:188
CacheMemory::clearLockedAll
void clearLockedAll(int context)
Definition: CacheMemory.cc:490
RubyPort::functionalWrite
virtual int functionalWrite(Packet *func_pkt)
Definition: RubyPort.cc:651
Drainable::drainState
DrainState drainState() const
Return the current drain state of an object.
Definition: drain.hh:320
Packet::getHtmTransactionUid
uint64_t getHtmTransactionUid() const
If a packet/request originates in a CPU executing in transactional mode, i.e.
Definition: packet.cc:550
SimObject::name
virtual const std::string name() const
Definition: sim_object.hh:182
AbstractController::notifyCoalesced
virtual void notifyCoalesced(const Addr &addr, const RubyRequestType &type, const RequestPtr &req, const DataBlock &data_blk, const bool &was_miss)
Notifies controller of a request coalesced at the sequencer.
Definition: AbstractController.hh:142
RubyTester::SenderState::subBlock
SubBlock subBlock
Definition: RubyTester.hh:88
Sequencer::m_hitMachLatencyHist
std::vector< Stats::Histogram * > m_hitMachLatencyHist
Histograms for profiling the latencies for requests that did not required external messages.
Definition: Sequencer.hh:253
X86ISA::StoreCheck
@ StoreCheck
Definition: ldstflags.hh:54
Sequencer::m_InitialToForwardDelayHist
std::vector< Stats::Histogram * > m_InitialToForwardDelayHist
Definition: Sequencer.hh:268
Sequencer::m_deadlock_threshold
Cycles m_deadlock_threshold
Definition: Sequencer.hh:213
RubySystem::getWarmupEnabled
static bool getWarmupEnabled()
Definition: RubySystem.hh:64
Sequencer::writeCallback
void writeCallback(Addr address, DataBlock &data, const bool externalHit=false, const MachineType mach=MachineType_NUM, const Cycles initialRequestTime=Cycles(0), const Cycles forwardRequestTime=Cycles(0), const Cycles firstResponseTime=Cycles(0), const bool noCoales=false)
Definition: Sequencer.cc:397
Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:258
getOffset
Addr getOffset(Addr addr)
Definition: Address.cc:48
Sequencer::m_typeLatencyHist
std::vector< Stats::Histogram * > m_typeLatencyHist
Definition: Sequencer.hh:244
Stats::DistBase::reset
void reset()
Reset stat value to default.
Definition: statistics.hh:1347
Packet::isMaskedWrite
bool isMaskedWrite() const
Definition: packet.hh:1374
ArmISA::rs
Bitfield< 9, 8 > rs
Definition: miscregs_types.hh:372
Stats::DistBase::sample
void sample(const U &v, int n=1)
Add a value to the distribtion n times.
Definition: statistics.hh:1323
logging.hh
Cycles
Cycles is a wrapper class for representing cycle counts, i.e.
Definition: types.hh:79
Packet::isWrite
bool isWrite() const
Definition: packet.hh:558
SequencerRequest
Definition: Sequencer.hh:56
X86ISA::type
type
Definition: misc.hh:727
curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:43
Sequencer::issueRequest
void issueRequest(PacketPtr pkt, RubyRequestType type)
Definition: Sequencer.cc:762
Packet::isFlush
bool isFlush() const
Definition: packet.hh:586
MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:323
fatal_if
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition: logging.hh:219
SubBlock::mergeFrom
void mergeFrom(const DataBlock &data)
Definition: SubBlock.hh:60
AbstractController::mandatoryQueueLatency
virtual Cycles mandatoryQueueLatency(const RubyRequestType &param_type)
Definition: AbstractController.hh:113
RubyPort::m_ruby_system
RubySystem * m_ruby_system
Definition: RubyPort.hh:188
RubyPort::m_version
uint32_t m_version
Definition: RubyPort.hh:189
printAddress
std::string printAddress(Addr addr)
Definition: Address.cc:74
Sequencer::llscClearLocalMonitor
void llscClearLocalMonitor()
Removes all addresses from the local monitor.
Definition: Sequencer.cc:204
RubyPort::ruby_eviction_callback
void ruby_eviction_callback(Addr address)
Definition: RubyPort.cc:617
DrainState::Draining
@ Draining
Draining buffers pending serialization/handover.
Sequencer::m_FirstResponseToCompletionDelayHist
std::vector< Stats::Histogram * > m_FirstResponseToCompletionDelayHist
Definition: Sequencer.hh:270
Sequencer::m_missTypeLatencyHist
std::vector< Stats::Histogram * > m_missTypeLatencyHist
Definition: Sequencer.hh:259
panic
#define panic(...)
This implements a cprintf based panic() function.
Definition: logging.hh:171
Sequencer.hh

Generated on Tue Mar 23 2021 19:41:28 for gem5 by doxygen 1.8.17