gem5  v22.0.0.2
RubySystem.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-2011 Mark D. Hill and David A. Wood
15  * All rights reserved.
16  *
17  * Redistribution and use in source and binary forms, with or without
18  * modification, are permitted provided that the following conditions are
19  * met: redistributions of source code must retain the above copyright
20  * notice, this list of conditions and the following disclaimer;
21  * redistributions in binary form must reproduce the above copyright
22  * notice, this list of conditions and the following disclaimer in the
23  * documentation and/or other materials provided with the distribution;
24  * neither the name of the copyright holders nor the names of its
25  * contributors may be used to endorse or promote products derived from
26  * this software without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
30  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
31  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
32  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
33  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
34  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
38  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39  */
40 
42 
43 #include <fcntl.h>
44 #include <zlib.h>
45 
46 #include <cstdio>
47 #include <list>
48 
49 #include "base/compiler.hh"
50 #include "base/intmath.hh"
51 #include "base/statistics.hh"
52 #include "debug/RubyCacheTrace.hh"
53 #include "debug/RubySystem.hh"
58 #include "mem/simple_mem.hh"
59 #include "sim/eventq.hh"
60 #include "sim/simulate.hh"
61 #include "sim/system.hh"
62 
63 namespace gem5
64 {
65 
66 namespace ruby
67 {
68 
73 bool RubySystem::m_warmup_enabled = false;
74 // To look forward to allowing multiple RubySystem instances, track the number
75 // of RubySystems that need to be warmed up on checkpoint restore.
78 
80  : ClockedObject(p), m_access_backing_store(p.access_backing_store),
81  m_cache_recorder(NULL)
82 {
83  m_randomization = p.randomization;
84 
85  m_block_size_bytes = p.block_size_bytes;
88  m_memory_size_bits = p.memory_size_bits;
89 
90  // Resize to the size of different machine types
91  m_abstract_controls.resize(MachineType_NUM);
92 
93  // Collate the statistics before they are printed.
95  // Create the profiler
96  m_profiler = new Profiler(p, this);
97  m_phys_mem = p.phys_mem;
98 }
99 
100 void
102 {
103  m_networks.emplace_back(network_ptr);
104 }
105 
106 void
108 {
109  m_abs_cntrl_vec.push_back(cntrl);
110 
111  MachineID id = cntrl->getMachineID();
112  m_abstract_controls[id.getType()][id.getNum()] = cntrl;
113 }
114 
115 void
117 {
118  int network_id = -1;
119  for (int idx = 0; idx < m_networks.size(); ++idx) {
120  if (m_networks[idx].get() == network) {
121  network_id = idx;
122  }
123  }
124 
125  fatal_if(network_id < 0, "Could not add MachineID %s. Network not found",
126  MachineIDToString(mach_id).c_str());
127 
128  machineToNetwork.insert(std::make_pair(mach_id, network_id));
129 }
130 
131 // This registers all requestor IDs in the system for functional reads. This
132 // should be called in init() since requestor IDs are obtained in a SimObject's
133 // constructor and there are functional reads/writes between init() and
134 // startup().
135 void
137 {
138  // Create the map for RequestorID to network node. This is done in init()
139  // because all RequestorIDs must be obtained in the constructor and
140  // AbstractControllers are registered in their constructor. This is done
141  // in two steps: (1) Add all of the AbstractControllers. Since we don't
142  // have a mapping of RequestorID to MachineID this is the easiest way to
143  // filter out AbstractControllers from non-Ruby requestors. (2) Go through
144  // the system's list of RequestorIDs and add missing RequestorIDs to
145  // network 0 (the default).
146  for (auto& cntrl : m_abs_cntrl_vec) {
147  RequestorID id = cntrl->getRequestorId();
148  MachineID mach_id = cntrl->getMachineID();
149 
150  // These are setup in Network constructor and should exist
151  fatal_if(!machineToNetwork.count(mach_id),
152  "No machineID %s. Does not belong to a Ruby network?",
153  MachineIDToString(mach_id).c_str());
154 
155  auto network_id = machineToNetwork[mach_id];
156  requestorToNetwork.insert(std::make_pair(id, network_id));
157 
158  // Create helper vectors for each network to iterate over.
159  netCntrls[network_id].push_back(cntrl);
160  }
161 
162  // Default all other requestor IDs to network 0
163  for (auto id = 0; id < params().system->maxRequestors(); ++id) {
164  if (!requestorToNetwork.count(id)) {
165  requestorToNetwork.insert(std::make_pair(id, 0));
166  }
167  }
168 }
169 
171 {
172  delete m_profiler;
173 }
174 
175 void
176 RubySystem::makeCacheRecorder(uint8_t *uncompressed_trace,
177  uint64_t cache_trace_size,
178  uint64_t block_size_bytes)
179 {
180  std::vector<Sequencer*> sequencer_map;
181  Sequencer* sequencer_ptr = NULL;
182 
183  for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
184  sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getCPUSequencer());
185  if (sequencer_ptr == NULL) {
186  sequencer_ptr = sequencer_map[cntrl];
187  }
188  }
189 
190  assert(sequencer_ptr != NULL);
191 
192  for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
193  if (sequencer_map[cntrl] == NULL) {
194  sequencer_map[cntrl] = sequencer_ptr;
195  }
196  }
197 
198  // Remove the old CacheRecorder if it's still hanging about.
199  if (m_cache_recorder != NULL) {
200  delete m_cache_recorder;
201  }
202 
203  // Create the CacheRecorder and record the cache trace
204  m_cache_recorder = new CacheRecorder(uncompressed_trace, cache_trace_size,
205  sequencer_map, block_size_bytes);
206 }
207 
208 void
210 {
211  m_cooldown_enabled = true;
212 
213  // Make the trace so we know what to write back.
214  DPRINTF(RubyCacheTrace, "Recording Cache Trace\n");
216  for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
217  m_abs_cntrl_vec[cntrl]->recordCacheTrace(cntrl, m_cache_recorder);
218  }
219  DPRINTF(RubyCacheTrace, "Cache Trace Complete\n");
220 
221  // save the current tick value
222  Tick curtick_original = curTick();
223  DPRINTF(RubyCacheTrace, "Recording current tick %ld\n", curtick_original);
224 
225  // Deschedule all prior events on the event queue, but record the tick they
226  // were scheduled at so they can be restored correctly later.
227  std::list<std::pair<Event*, Tick> > original_events;
228  while (!eventq->empty()) {
229  Event *curr_head = eventq->getHead();
230  if (curr_head->isAutoDelete()) {
231  DPRINTF(RubyCacheTrace, "Event %s auto-deletes when descheduled,"
232  " not recording\n", curr_head->name());
233  } else {
234  original_events.push_back(
235  std::make_pair(curr_head, curr_head->when()));
236  }
237  eventq->deschedule(curr_head);
238  }
239 
240  // Schedule an event to start cache cooldown
241  DPRINTF(RubyCacheTrace, "Starting cache flush\n");
243  simulate();
244  DPRINTF(RubyCacheTrace, "Cache flush complete\n");
245 
246  // Deschedule any events left on the event queue.
247  while (!eventq->empty()) {
249  }
250 
251  // Restore curTick
252  setCurTick(curtick_original);
253 
254  // Restore all events that were originally on the event queue. This is
255  // done after setting curTick back to its original value so that events do
256  // not seem to be scheduled in the past.
257  while (!original_events.empty()) {
258  std::pair<Event*, Tick> event = original_events.back();
259  eventq->schedule(event.first, event.second);
260  original_events.pop_back();
261  }
262 
263  // No longer flushing back to memory.
264  m_cooldown_enabled = false;
265 
266  // There are several issues with continuing simulation after calling
267  // memWriteback() at the moment, that stem from taking events off the
268  // queue, simulating again, and then putting them back on, whilst
269  // pretending that no time has passed. One is that some events will have
270  // been deleted, so can't be put back. Another is that any object
271  // recording the tick something happens may end up storing a tick in the
272  // future. A simple warning here alerts the user that things may not work
273  // as expected.
274  warn_once("Ruby memory writeback is experimental. Continuing simulation "
275  "afterwards may not always work as intended.");
276 
277  // Keep the cache recorder around so that we can dump the trace if a
278  // checkpoint is immediately taken.
279 }
280 
281 void
282 RubySystem::writeCompressedTrace(uint8_t *raw_data, std::string filename,
283  uint64_t uncompressed_trace_size)
284 {
285  // Create the checkpoint file for the memory
286  std::string thefile = CheckpointIn::dir() + "/" + filename.c_str();
287 
288  int fd = creat(thefile.c_str(), 0664);
289  if (fd < 0) {
290  perror("creat");
291  fatal("Can't open memory trace file '%s'\n", filename);
292  }
293 
294  gzFile compressedMemory = gzdopen(fd, "wb");
295  if (compressedMemory == NULL)
296  fatal("Insufficient memory to allocate compression state for %s\n",
297  filename);
298 
299  if (gzwrite(compressedMemory, raw_data, uncompressed_trace_size) !=
300  uncompressed_trace_size) {
301  fatal("Write failed on memory trace file '%s'\n", filename);
302  }
303 
304  if (gzclose(compressedMemory)) {
305  fatal("Close failed on memory trace file '%s'\n", filename);
306  }
307  delete[] raw_data;
308 }
309 
310 void
312 {
313  // Store the cache-block size, so we are able to restore on systems with a
314  // different cache-block size. CacheRecorder depends on the correct
315  // cache-block size upon unserializing.
316  uint64_t block_size_bytes = getBlockSizeBytes();
317  SERIALIZE_SCALAR(block_size_bytes);
318 
319  // Check that there's a valid trace to use. If not, then memory won't be
320  // up-to-date and the simulation will probably fail when restoring from the
321  // checkpoint.
322  if (m_cache_recorder == NULL) {
323  fatal("Call memWriteback() before serialize() to create ruby trace");
324  }
325 
326  // Aggregate the trace entries together into a single array
327  uint8_t *raw_data = new uint8_t[4096];
328  uint64_t cache_trace_size = m_cache_recorder->aggregateRecords(&raw_data,
329  4096);
330  std::string cache_trace_file = name() + ".cache.gz";
331  writeCompressedTrace(raw_data, cache_trace_file, cache_trace_size);
332 
333  SERIALIZE_SCALAR(cache_trace_file);
334  SERIALIZE_SCALAR(cache_trace_size);
335 }
336 
337 void
339 {
340  // Delete the cache recorder if it was created in memWriteback()
341  // to checkpoint the current cache state.
342  if (m_cache_recorder) {
343  delete m_cache_recorder;
344  m_cache_recorder = NULL;
345  }
346 }
347 
348 void
349 RubySystem::readCompressedTrace(std::string filename, uint8_t *&raw_data,
350  uint64_t &uncompressed_trace_size)
351 {
352  // Read the trace file
353  gzFile compressedTrace;
354 
355  // trace file
356  int fd = open(filename.c_str(), O_RDONLY);
357  if (fd < 0) {
358  perror("open");
359  fatal("Unable to open trace file %s", filename);
360  }
361 
362  compressedTrace = gzdopen(fd, "rb");
363  if (compressedTrace == NULL) {
364  fatal("Insufficient memory to allocate compression state for %s\n",
365  filename);
366  }
367 
368  raw_data = new uint8_t[uncompressed_trace_size];
369  if (gzread(compressedTrace, raw_data, uncompressed_trace_size) <
370  uncompressed_trace_size) {
371  fatal("Unable to read complete trace from file %s\n", filename);
372  }
373 
374  if (gzclose(compressedTrace)) {
375  fatal("Failed to close cache trace file '%s'\n", filename);
376  }
377 }
378 
379 void
381 {
382  uint8_t *uncompressed_trace = NULL;
383 
384  // This value should be set to the checkpoint-system's block-size.
385  // Optional, as checkpoints without it can be run if the
386  // checkpoint-system's block-size == current block-size.
387  uint64_t block_size_bytes = getBlockSizeBytes();
388  UNSERIALIZE_OPT_SCALAR(block_size_bytes);
389 
390  std::string cache_trace_file;
391  uint64_t cache_trace_size = 0;
392 
393  UNSERIALIZE_SCALAR(cache_trace_file);
394  UNSERIALIZE_SCALAR(cache_trace_size);
395  cache_trace_file = cp.getCptDir() + "/" + cache_trace_file;
396 
397  readCompressedTrace(cache_trace_file, uncompressed_trace,
398  cache_trace_size);
399  m_warmup_enabled = true;
401 
402  // Create the cache recorder that will hang around until startup.
403  makeCacheRecorder(uncompressed_trace, cache_trace_size, block_size_bytes);
404 }
405 
406 void
408 {
410 }
411 
412 void
414 {
415 
416  // Ruby restores state from a checkpoint by resetting the clock to 0 and
417  // playing the requests that can possibly re-generate the cache state.
418  // The clock value is set to the actual checkpointed value once all the
419  // requests have been executed.
420  //
421  // This way of restoring state is pretty finicky. For example, if a
422  // Ruby component reads time before the state has been restored, it would
423  // cache this value and hence its clock would not be reset to 0, when
424  // Ruby resets the global clock. This can potentially result in a
425  // deadlock.
426  //
427  // The solution is that no Ruby component should read time before the
428  // simulation starts. And then one also needs to hope that the time
429  // Ruby finishes restoring the state is less than the time when the
430  // state was checkpointed.
431 
432  if (m_warmup_enabled) {
433  DPRINTF(RubyCacheTrace, "Starting ruby cache warmup\n");
434  // save the current tick value
435  Tick curtick_original = curTick();
436  // save the event queue head
437  Event* eventq_head = eventq->replaceHead(NULL);
438  // set curTick to 0 and reset Ruby System's clock
439  setCurTick(0);
440  resetClock();
441 
442  // Schedule an event to start cache warmup
444  simulate();
445 
446  delete m_cache_recorder;
447  m_cache_recorder = NULL;
449  if (m_systems_to_warmup == 0) {
450  m_warmup_enabled = false;
451  }
452 
453  // Restore eventq head
454  eventq->replaceHead(eventq_head);
455  // Restore curTick and Ruby System's clock
456  setCurTick(curtick_original);
457  resetClock();
458  }
459 
460  resetStats();
461 }
462 
463 void
465 {
466  if (getWarmupEnabled()) {
468  } else if (getCooldownEnabled()) {
470  }
471 }
472 
473 void
475 {
477  for (auto& network : m_networks) {
478  network->resetStats();
479  }
481 }
482 
483 #ifndef PARTIAL_FUNC_READS
484 bool
486 {
487  Addr address(pkt->getAddr());
488  Addr line_address = makeLineAddress(address);
489 
490  AccessPermission access_perm = AccessPermission_NotPresent;
491 
492  DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
493 
494  unsigned int num_ro = 0;
495  unsigned int num_rw = 0;
496  unsigned int num_busy = 0;
497  unsigned int num_maybe_stale = 0;
498  unsigned int num_backing_store = 0;
499  unsigned int num_invalid = 0;
500 
501  // Only send functional requests within the same network.
502  assert(requestorToNetwork.count(pkt->requestorId()));
503  int request_net_id = requestorToNetwork[pkt->requestorId()];
504  assert(netCntrls.count(request_net_id));
505 
506  AbstractController *ctrl_ro = nullptr;
507  AbstractController *ctrl_rw = nullptr;
508  AbstractController *ctrl_backing_store = nullptr;
509 
510  // In this loop we count the number of controllers that have the given
511  // address in read only, read write and busy states.
512  for (auto& cntrl : netCntrls[request_net_id]) {
513  access_perm = cntrl-> getAccessPermission(line_address);
514  if (access_perm == AccessPermission_Read_Only){
515  num_ro++;
516  if (ctrl_ro == nullptr) ctrl_ro = cntrl;
517  }
518  else if (access_perm == AccessPermission_Read_Write){
519  num_rw++;
520  if (ctrl_rw == nullptr) ctrl_rw = cntrl;
521  }
522  else if (access_perm == AccessPermission_Busy)
523  num_busy++;
524  else if (access_perm == AccessPermission_Maybe_Stale)
525  num_maybe_stale++;
526  else if (access_perm == AccessPermission_Backing_Store) {
527  // See RubySlicc_Exports.sm for details, but Backing_Store is meant
528  // to represent blocks in memory *for Broadcast/Snooping protocols*,
529  // where memory has no idea whether it has an exclusive copy of data
530  // or not.
531  num_backing_store++;
532  if (ctrl_backing_store == nullptr)
533  ctrl_backing_store = cntrl;
534  }
535  else if (access_perm == AccessPermission_Invalid ||
536  access_perm == AccessPermission_NotPresent)
537  num_invalid++;
538  }
539 
540  // This if case is meant to capture what happens in a Broadcast/Snoop
541  // protocol where the block does not exist in the cache hierarchy. You
542  // only want to read from the Backing_Store memory if there is no copy in
543  // the cache hierarchy, otherwise you want to try to read the RO or RW
544  // copies existing in the cache hierarchy (covered by the else statement).
545  // The reason is because the Backing_Store memory could easily be stale, if
546  // there are copies floating around the cache hierarchy, so you want to read
547  // it only if it's not in the cache hierarchy at all.
548  int num_controllers = netCntrls[request_net_id].size();
549  if (num_invalid == (num_controllers - 1) && num_backing_store == 1) {
550  DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n");
551  ctrl_backing_store->functionalRead(line_address, pkt);
552  return true;
553  } else if (num_ro > 0 || num_rw >= 1) {
554  if (num_rw > 1) {
555  // We iterate over the vector of abstract controllers, and return
556  // the first copy found. If we have more than one cache with block
557  // in writable permission, the first one found would be returned.
558  warn("More than one Abstract Controller with RW permission for "
559  "addr: %#x on cacheline: %#x.", address, line_address);
560  }
561  // In Broadcast/Snoop protocols, this covers if you know the block
562  // exists somewhere in the caching hierarchy, then you want to read any
563  // valid RO or RW block. In directory protocols, same thing, you want
564  // to read any valid readable copy of the block.
565  DPRINTF(RubySystem, "num_maybe_stale=%d, num_busy = %d, num_ro = %d, "
566  "num_rw = %d\n",
567  num_maybe_stale, num_busy, num_ro, num_rw);
568  // Use the copy from the controller with read/write permission (if
569  // any), otherwise use get the first read only found
570  if (ctrl_rw) {
571  ctrl_rw->functionalRead(line_address, pkt);
572  } else {
573  assert(ctrl_ro);
574  ctrl_ro->functionalRead(line_address, pkt);
575  }
576  return true;
577  } else if ((num_busy + num_maybe_stale) > 0) {
578  // No controller has a valid copy of the block, but a transient or
579  // stale state indicates a valid copy should be in transit in the
580  // network or in a message buffer waiting to be handled
581  DPRINTF(RubySystem, "Controllers functionalRead lookup "
582  "(num_maybe_stale=%d, num_busy = %d)\n",
583  num_maybe_stale, num_busy);
584  for (auto& cntrl : netCntrls[request_net_id]) {
585  if (cntrl->functionalReadBuffers(pkt))
586  return true;
587  }
588  DPRINTF(RubySystem, "Network functionalRead lookup "
589  "(num_maybe_stale=%d, num_busy = %d)\n",
590  num_maybe_stale, num_busy);
591  for (auto& network : m_networks) {
592  if (network->functionalRead(pkt))
593  return true;
594  }
595  }
596 
597  return false;
598 }
599 #else
600 bool
602 {
603  Addr address(pkt->getAddr());
604  Addr line_address = makeLineAddress(address);
605 
606  DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
607 
611  AbstractController *ctrl_rw = nullptr;
612  AbstractController *ctrl_bs = nullptr;
613 
614  // Build lists of controllers that have line
615  for (auto ctrl : m_abs_cntrl_vec) {
616  switch(ctrl->getAccessPermission(line_address)) {
617  case AccessPermission_Read_Only:
618  ctrl_ro.push_back(ctrl);
619  break;
620  case AccessPermission_Busy:
621  ctrl_busy.push_back(ctrl);
622  break;
623  case AccessPermission_Read_Write:
624  assert(ctrl_rw == nullptr);
625  ctrl_rw = ctrl;
626  break;
627  case AccessPermission_Backing_Store:
628  assert(ctrl_bs == nullptr);
629  ctrl_bs = ctrl;
630  break;
631  case AccessPermission_Backing_Store_Busy:
632  assert(ctrl_bs == nullptr);
633  ctrl_bs = ctrl;
634  ctrl_busy.push_back(ctrl);
635  break;
636  default:
637  ctrl_others.push_back(ctrl);
638  break;
639  }
640  }
641 
642  DPRINTF(RubySystem, "num_ro=%d, num_busy=%d , has_rw=%d, "
643  "backing_store=%d\n",
644  ctrl_ro.size(), ctrl_busy.size(),
645  ctrl_rw != nullptr, ctrl_bs != nullptr);
646 
647  // Issue functional reads to all controllers found in a stable state
648  // until we get a full copy of the line
649  WriteMask bytes;
650  if (ctrl_rw != nullptr) {
651  ctrl_rw->functionalRead(line_address, pkt, bytes);
652  // if a RW controllter has the full line that's all uptodate
653  if (bytes.isFull())
654  return true;
655  }
656 
657  // Get data from RO and BS
658  for (auto ctrl : ctrl_ro)
659  ctrl->functionalRead(line_address, pkt, bytes);
660 
661  if (ctrl_bs)
662  ctrl_bs->functionalRead(line_address, pkt, bytes);
663 
664  // if there is any busy controller or bytes still not set, then a partial
665  // and/or dirty copy of the line might be in a message buffer or the
666  // network
667  if (!ctrl_busy.empty() || !bytes.isFull()) {
668  DPRINTF(RubySystem, "Reading from remaining controllers, "
669  "buffers and networks\n");
670  if (ctrl_rw != nullptr)
671  ctrl_rw->functionalReadBuffers(pkt, bytes);
672  for (auto ctrl : ctrl_ro)
673  ctrl->functionalReadBuffers(pkt, bytes);
674  if (ctrl_bs != nullptr)
675  ctrl_bs->functionalReadBuffers(pkt, bytes);
676  for (auto ctrl : ctrl_busy) {
677  ctrl->functionalRead(line_address, pkt, bytes);
678  ctrl->functionalReadBuffers(pkt, bytes);
679  }
680  for (auto& network : m_networks) {
681  network->functionalRead(pkt, bytes);
682  }
683  for (auto ctrl : ctrl_others) {
684  ctrl->functionalRead(line_address, pkt, bytes);
685  ctrl->functionalReadBuffers(pkt, bytes);
686  }
687  }
688  // we either got the full line or couldn't find anything at this point
689  panic_if(!(bytes.isFull() || bytes.isEmpty()),
690  "Inconsistent state on functional read for %#x %s\n",
691  address, bytes);
692 
693  return bytes.isFull();
694 }
695 #endif
696 
697 // The function searches through all the buffers that exist in different
698 // cache, directory and memory controllers, and in the network components
699 // and writes the data portion of those that hold the address specified
700 // in the packet.
701 bool
703 {
704  Addr addr(pkt->getAddr());
705  Addr line_addr = makeLineAddress(addr);
706  AccessPermission access_perm = AccessPermission_NotPresent;
707 
708  DPRINTF(RubySystem, "Functional Write request for %#x\n", addr);
709 
710  [[maybe_unused]] uint32_t num_functional_writes = 0;
711 
712  // Only send functional requests within the same network.
713  assert(requestorToNetwork.count(pkt->requestorId()));
714  int request_net_id = requestorToNetwork[pkt->requestorId()];
715  assert(netCntrls.count(request_net_id));
716 
717  for (auto& cntrl : netCntrls[request_net_id]) {
718  num_functional_writes += cntrl->functionalWriteBuffers(pkt);
719 
720  access_perm = cntrl->getAccessPermission(line_addr);
721  if (access_perm != AccessPermission_Invalid &&
722  access_perm != AccessPermission_NotPresent) {
723  num_functional_writes +=
724  cntrl->functionalWrite(line_addr, pkt);
725  }
726 
727  // Also updates requests pending in any sequencer associated
728  // with the controller
729  if (cntrl->getCPUSequencer()) {
730  num_functional_writes +=
731  cntrl->getCPUSequencer()->functionalWrite(pkt);
732  }
733  if (cntrl->getDMASequencer()) {
734  num_functional_writes +=
735  cntrl->getDMASequencer()->functionalWrite(pkt);
736  }
737  }
738 
739  for (auto& network : m_networks) {
740  num_functional_writes += network->functionalWrite(pkt);
741  }
742  DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes);
743 
744  return true;
745 }
746 
747 } // namespace ruby
748 } // namespace gem5
gem5::curTick
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
fatal
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
gem5::ruby::RubySystem::m_warmup_enabled
static bool m_warmup_enabled
Definition: RubySystem.hh:142
gem5::Event::when
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
gem5::ruby::Sequencer
Definition: Sequencer.hh:86
gem5::ruby::RubySystem::RubySystem
RubySystem(const Params &p)
Definition: RubySystem.cc:79
gem5::Event::name
virtual const std::string name() const
Definition: eventq.cc:84
warn
#define warn(...)
Definition: logging.hh:246
gem5::ruby::RubySystem::functionalRead
bool functionalRead(Packet *ptr)
Definition: RubySystem.cc:485
system.hh
gem5::EventQueue::replaceHead
Event * replaceHead(Event *s)
function for replacing the head of the event queue, so that a different set of events can run without...
Definition: eventq.cc:356
gem5::Clocked::curCycle
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
Definition: clocked_object.hh:195
gem5::CheckpointIn::dir
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:154
UNSERIALIZE_SCALAR
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
gem5::ArmISA::fd
Bitfield< 14, 12 > fd
Definition: types.hh:150
warn_once
#define warn_once(...)
Definition: logging.hh:250
DMASequencer.hh
gem5::ruby::AbstractController::getMachineID
MachineID getMachineID() const
Definition: AbstractController.hh:174
gem5::ruby::RubySystem::startup
void startup() override
startup() is the final initialization call before simulation.
Definition: RubySystem.cc:413
gem5::ruby::RubySystem::machineToNetwork
std::unordered_map< MachineID, unsigned > machineToNetwork
Definition: RubySystem.hh:153
gem5::CheckpointIn
Definition: serialize.hh:68
simulate.hh
gem5::MipsISA::event
Bitfield< 10, 5 > event
Definition: pra_constants.hh:300
gem5::ruby::Network
Definition: Network.hh:82
gem5::ruby::RubySystem::init
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: RubySystem.cc:407
gem5::ruby::RubySystem::processRubyEvent
void processRubyEvent()
Definition: RubySystem.cc:464
gem5::ruby::RubySystem::serialize
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: RubySystem.cc:311
gem5::ruby::RubySystem::netCntrls
std::unordered_map< unsigned, std::vector< AbstractController * > > netCntrls
Definition: RubySystem.hh:155
gem5::ruby::RubySystem::m_abstract_controls
std::vector< std::map< uint32_t, AbstractController * > > m_abstract_controls
Definition: RubySystem.hh:160
gem5::floorLog2
static constexpr std::enable_if_t< std::is_integral_v< T >, int > floorLog2(T x)
Definition: intmath.hh:59
gem5::ruby::CacheRecorder::enqueueNextFlushRequest
void enqueueNextFlushRequest()
Function for flushing the memory contents of the caches to the main memory.
Definition: CacheRecorder.cc:87
gem5::ruby::RubySystem::getBlockSizeBytes
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:72
std::vector
STL vector class.
Definition: stl.hh:37
gem5::ruby::RubySystem::m_start_cycle
Cycles m_start_cycle
Definition: RubySystem.hh:151
gem5::ruby::CacheRecorder::aggregateRecords
uint64_t aggregateRecords(uint8_t **data, uint64_t size)
Definition: CacheRecorder.cc:175
gem5::ruby::RubySystem::resetStats
void resetStats() override
Callback to reset stats.
Definition: RubySystem.cc:474
gem5::ruby::CacheRecorder::enqueueNextFetchRequest
void enqueueNextFetchRequest()
Function for fetching warming up the memory and the caches.
Definition: CacheRecorder.cc:109
gem5::statistics::Group::resetStats
virtual void resetStats()
Callback to reset stats.
Definition: group.cc:86
gem5::ruby::makeLineAddress
Addr makeLineAddress(Addr addr)
Definition: Address.cc:60
gem5::ruby::AbstractController
Definition: AbstractController.hh:82
gem5::isPowerOf2
static constexpr bool isPowerOf2(const T &n)
Definition: intmath.hh:98
gem5::EventQueue::getHead
Event * getHead() const
Definition: eventq.hh:858
gem5::ruby::RubySystem::m_phys_mem
memory::SimpleMemory * m_phys_mem
Definition: RubySystem.hh:145
gem5::ruby::RubySystem::writeCompressedTrace
static void writeCompressedTrace(uint8_t *raw_data, std::string file, uint64_t uncompressed_trace_size)
Definition: RubySystem.cc:282
gem5::statistics::registerDumpCallback
void registerDumpCallback(const std::function< void()> &callback)
Register a callback that should be called whenever statistics are about to be dumped.
Definition: statistics.cc:330
gem5::ruby::RubySystem::registerAbstractController
void registerAbstractController(AbstractController *)
Definition: RubySystem.cc:107
gem5::ruby::RubySystem::m_networks
std::vector< std::unique_ptr< Network > > m_networks
Definition: RubySystem.hh:149
gem5::ruby::RubySystem::readCompressedTrace
static void readCompressedTrace(std::string filename, uint8_t *&raw_data, uint64_t &uncompressed_trace_size)
Definition: RubySystem.cc:349
gem5::Named::name
virtual std::string name() const
Definition: named.hh:47
gem5::EventManager::setCurTick
void setCurTick(Tick newVal)
Definition: eventq.hh:1080
gem5::Packet::requestorId
RequestorID requestorId() const
Definition: packet.hh:776
gem5::VegaISA::p
Bitfield< 54 > p
Definition: pagetable.hh:70
gem5::SimObject::params
const Params & params() const
Definition: sim_object.hh:176
DPRINTF
#define DPRINTF(x,...)
Definition: trace.hh:186
gem5::Event
Definition: eventq.hh:251
gem5::ruby::RubySystem::m_randomization
static bool m_randomization
Definition: RubySystem.hh:137
gem5::Packet
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:291
gem5::EventQueue::deschedule
void deschedule(Event *event)
Deschedule the specified event.
Definition: eventq.hh:797
statistics.hh
gem5::ruby::RubySystem::m_cache_recorder
CacheRecorder * m_cache_recorder
Definition: RubySystem.hh:159
gem5::Tick
uint64_t Tick
Tick count type.
Definition: types.hh:58
gem5::ruby::RubySystem::m_abs_cntrl_vec
std::vector< AbstractController * > m_abs_cntrl_vec
Definition: RubySystem.hh:150
gem5::EventManager::eventq
EventQueue * eventq
A pointer to this object's event queue.
Definition: eventq.hh:991
UNSERIALIZE_OPT_SCALAR
#define UNSERIALIZE_OPT_SCALAR(scalar)
Definition: serialize.hh:582
gem5::ruby::RubySystem::m_profiler
Profiler * m_profiler
Definition: RubySystem.hh:158
gem5::EventQueue::empty
bool empty() const
Returns true if no events are queued.
Definition: eventq.hh:898
gem5::ruby::RubySystem::m_block_size_bytes
static uint32_t m_block_size_bytes
Definition: RubySystem.hh:138
gem5::ruby::RubySystem::memWriteback
void memWriteback() override
Write back dirty buffers to memory using functional writes.
Definition: RubySystem.cc:209
compiler.hh
std::pair
STL pair class.
Definition: stl.hh:58
gem5::Event::isAutoDelete
bool isAutoDelete() const
The function returns true if the object is automatically deleted after the event is processed.
Definition: eventq.hh:501
RubySystem.hh
gem5::Addr
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
gem5::ruby::RubySystem::~RubySystem
~RubySystem()
Definition: RubySystem.cc:170
gem5::ruby::RubySystem::getCooldownEnabled
static bool getCooldownEnabled()
Definition: RubySystem.hh:76
gem5::ruby::RubySystem::registerRequestorIDs
void registerRequestorIDs()
Definition: RubySystem.cc:136
SERIALIZE_SCALAR
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
gem5::ruby::RubySystem::makeCacheRecorder
void makeCacheRecorder(uint8_t *uncompressed_trace, uint64_t cache_trace_size, uint64_t block_size_bytes)
Definition: RubySystem.cc:176
gem5::ruby::RubySystem::registerMachineID
void registerMachineID(const MachineID &mach_id, Network *network)
Definition: RubySystem.cc:116
gem5::ClockedObject
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
Definition: clocked_object.hh:234
gem5::ruby::RubySystem::requestorToNetwork
std::unordered_map< RequestorID, unsigned > requestorToNetwork
Definition: RubySystem.hh:154
gem5::ruby::RubySystem::unserialize
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: RubySystem.cc:380
gem5::ruby::RubySystem::drainResume
void drainResume() override
Resume execution after a successful drain.
Definition: RubySystem.cc:338
gem5::CheckpointIn::getCptDir
const std::string getCptDir()
Definition: serialize.hh:85
Network.hh
gem5::ruby::RubySystem
Definition: RubySystem.hh:63
gem5::ruby::AbstractController::functionalReadBuffers
virtual bool functionalReadBuffers(PacketPtr &)=0
These functions are used by ruby system to read/write the data blocks that exist with in the controll...
gem5::simulate
GlobalSimLoopExitEvent * simulate(Tick num_cycles)
Simulate for num_cycles additional cycles.
Definition: simulate.cc:188
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:204
gem5::ruby::RubySystem::m_memory_size_bits
static uint32_t m_memory_size_bits
Definition: RubySystem.hh:140
gem5::ruby::RubySystem::m_systems_to_warmup
static unsigned m_systems_to_warmup
Definition: RubySystem.hh:143
gem5::ruby::RubySystem::getWarmupEnabled
static bool getWarmupEnabled()
Definition: RubySystem.hh:75
Address.hh
gem5::ruby::RubySystem::collateStats
void collateStats()
Definition: RubySystem.hh:93
gem5::ruby::RubySystem::enqueueRubyEvent
void enqueueRubyEvent(Tick tick)
Definition: RubySystem.hh:112
gem5::ruby::RubySystem::functionalWrite
bool functionalWrite(Packet *ptr)
Definition: RubySystem.cc:702
gem5::Clocked::resetClock
void resetClock() const
Reset the object's clock using the current global tick value.
Definition: clocked_object.hh:137
gem5::ArmISA::id
Bitfield< 33 > id
Definition: misc_types.hh:251
gem5::EventQueue::schedule
void schedule(Event *event, Tick when, bool global=false)
Schedule the given event on this queue.
Definition: eventq.hh:764
gem5::CheckpointOut
std::ostream CheckpointOut
Definition: serialize.hh:66
gem5::RequestorID
uint16_t RequestorID
Definition: request.hh:95
gem5::ClockedObject::Params
ClockedObjectParams Params
Parameters of ClockedObject.
Definition: clocked_object.hh:240
std::list
STL list class.
Definition: stl.hh:51
gem5::Packet::getAddr
Addr getAddr() const
Definition: packet.hh:790
intmath.hh
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:226
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: gpu_translation_state.hh:37
gem5::ruby::RubySystem::m_cooldown_enabled
static bool m_cooldown_enabled
Definition: RubySystem.hh:144
gem5::ruby::MachineIDToString
std::string MachineIDToString(MachineID machine)
Definition: MachineID.hh:73
gem5::ruby::MachineID
Definition: MachineID.hh:56
gem5::ruby::Profiler
Definition: Profiler.hh:71
gem5::ruby::CacheRecorder
Definition: CacheRecorder.hh:73
gem5::ruby::AbstractController::functionalRead
virtual void functionalRead(const Addr &addr, PacketPtr)
Definition: AbstractController.hh:125
gem5::ruby::RubySystem::registerNetwork
void registerNetwork(Network *)
Definition: RubySystem.cc:101
gem5::ruby::RubySystem::m_block_size_bits
static uint32_t m_block_size_bits
Definition: RubySystem.hh:139
gem5::X86ISA::addr
Bitfield< 3 > addr
Definition: types.hh:84
simple_mem.hh
eventq.hh
Sequencer.hh

Generated on Thu Jul 28 2022 13:32:36 for gem5 by doxygen 1.8.17