gem5  v22.1.0.0
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
#define DPRINTF(x,...)
Definition: trace.hh:186
The ClockedObject class extends the SimObject with a clock and accessor functions to relate ticks to ...
ClockedObjectParams Params
Parameters of ClockedObject.
Cycles curCycle() const
Determine the current cycle, corresponding to a tick aligned to a clock edge.
void resetClock() const
Reset the object's clock using the current global tick value.
void setCurTick(Tick newVal)
Definition: eventq.hh:1080
EventQueue * eventq
A pointer to this object's event queue.
Definition: eventq.hh:991
Event * getHead() const
Definition: eventq.hh:858
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
virtual std::string name() const
Definition: named.hh:47
A Packet is used to encapsulate a transfer between two objects in the memory system (e....
Definition: packet.hh:294
Addr getAddr() const
Definition: packet.hh:805
RequestorID requestorId() const
Definition: packet.hh:778
virtual bool functionalReadBuffers(PacketPtr &)=0
These functions are used by ruby system to read/write the data blocks that exist with in the controll...
virtual void functionalRead(const Addr &addr, PacketPtr)
uint64_t aggregateRecords(uint8_t **data, uint64_t size)
void enqueueNextFetchRequest()
Function for fetching warming up the memory and the caches.
void enqueueNextFlushRequest()
Function for flushing the memory contents of the caches to the main memory.
void enqueueRubyEvent(Tick tick)
Definition: RubySystem.hh:112
static bool m_warmup_enabled
Definition: RubySystem.hh:142
static bool getWarmupEnabled()
Definition: RubySystem.hh:75
bool functionalWrite(Packet *ptr)
Definition: RubySystem.cc:702
static uint32_t getBlockSizeBytes()
Definition: RubySystem.hh:72
void unserialize(CheckpointIn &cp) override
Unserialize an object.
Definition: RubySystem.cc:380
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
Definition: RubySystem.cc:407
static bool m_cooldown_enabled
Definition: RubySystem.hh:144
std::vector< std::map< uint32_t, AbstractController * > > m_abstract_controls
Definition: RubySystem.hh:160
void registerMachineID(const MachineID &mach_id, Network *network)
Definition: RubySystem.cc:116
static bool m_randomization
Definition: RubySystem.hh:137
static unsigned m_systems_to_warmup
Definition: RubySystem.hh:143
std::unordered_map< RequestorID, unsigned > requestorToNetwork
Definition: RubySystem.hh:154
static void writeCompressedTrace(uint8_t *raw_data, std::string file, uint64_t uncompressed_trace_size)
Definition: RubySystem.cc:282
RubySystem(const Params &p)
Definition: RubySystem.cc:79
void registerNetwork(Network *)
Definition: RubySystem.cc:101
void startup() override
startup() is the final initialization call before simulation.
Definition: RubySystem.cc:413
std::unordered_map< MachineID, unsigned > machineToNetwork
Definition: RubySystem.hh:153
static void readCompressedTrace(std::string filename, uint8_t *&raw_data, uint64_t &uncompressed_trace_size)
Definition: RubySystem.cc:349
void registerAbstractController(AbstractController *)
Definition: RubySystem.cc:107
CacheRecorder * m_cache_recorder
Definition: RubySystem.hh:159
static uint32_t m_block_size_bits
Definition: RubySystem.hh:139
std::vector< std::unique_ptr< Network > > m_networks
Definition: RubySystem.hh:149
void drainResume() override
Resume execution after a successful drain.
Definition: RubySystem.cc:338
static uint32_t m_block_size_bytes
Definition: RubySystem.hh:138
std::vector< AbstractController * > m_abs_cntrl_vec
Definition: RubySystem.hh:150
void resetStats() override
Callback to reset stats.
Definition: RubySystem.cc:474
memory::SimpleMemory * m_phys_mem
Definition: RubySystem.hh:145
std::unordered_map< unsigned, std::vector< AbstractController * > > netCntrls
Definition: RubySystem.hh:155
static uint32_t m_memory_size_bits
Definition: RubySystem.hh:140
bool functionalRead(Packet *ptr)
Definition: RubySystem.cc:485
void makeCacheRecorder(uint8_t *uncompressed_trace, uint64_t cache_trace_size, uint64_t block_size_bytes)
Definition: RubySystem.cc:176
void serialize(CheckpointOut &cp) const override
Serialize an object.
Definition: RubySystem.cc:311
void memWriteback() override
Write back dirty buffers to memory using functional writes.
Definition: RubySystem.cc:209
static bool getCooldownEnabled()
Definition: RubySystem.hh:76
STL list class.
Definition: stl.hh:51
STL pair class.
Definition: stl.hh:58
STL vector class.
Definition: stl.hh:37
static constexpr std::enable_if_t< std::is_integral_v< T >, int > floorLog2(T x)
Definition: intmath.hh:59
static constexpr bool isPowerOf2(const T &n)
Definition: intmath.hh:98
void schedule(Event *event, Tick when, bool global=false)
Schedule the given event on this queue.
Definition: eventq.hh:764
void deschedule(Event *event)
Deschedule the specified event.
Definition: eventq.hh:797
bool isAutoDelete() const
The function returns true if the object is automatically deleted after the event is processed.
Definition: eventq.hh:501
virtual const std::string name() const
Definition: eventq.cc:84
bool empty() const
Returns true if no events are queued.
Definition: eventq.hh:898
Tick when() const
Get the time that the event is scheduled.
Definition: eventq.hh:508
#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
#define fatal(...)
This implements a cprintf based fatal() function.
Definition: logging.hh:190
#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
#define UNSERIALIZE_OPT_SCALAR(scalar)
Definition: serialize.hh:582
const std::string getCptDir()
Definition: serialize.hh:85
static std::string dir()
Get the current checkout directory name.
Definition: serialize.cc:154
const Params & params() const
Definition: sim_object.hh:176
virtual void resetStats()
Callback to reset stats.
Definition: group.cc:86
#define warn(...)
Definition: logging.hh:246
#define warn_once(...)
Definition: logging.hh:250
Bitfield< 14, 12 > fd
Definition: types.hh:150
Bitfield< 33 > id
Definition: misc_types.hh:257
Bitfield< 10, 5 > event
Bitfield< 54 > p
Definition: pagetable.hh:70
Bitfield< 3 > addr
Definition: types.hh:84
std::string MachineIDToString(MachineID machine)
Definition: MachineID.hh:73
Addr makeLineAddress(Addr addr)
Definition: Address.cc:60
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
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Tick curTick()
The universal simulation clock.
Definition: cur_tick.hh:46
std::ostream CheckpointOut
Definition: serialize.hh:66
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
Definition: types.hh:147
uint64_t Tick
Tick count type.
Definition: types.hh:58
uint16_t RequestorID
Definition: request.hh:95
GlobalSimLoopExitEvent * simulate(Tick num_cycles)
Simulate for num_cycles additional cycles.
Definition: simulate.cc:188
#define UNSERIALIZE_SCALAR(scalar)
Definition: serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition: serialize.hh:568
SimpleMemory declaration.
Declaration of Statistics objects.

Generated on Wed Dec 21 2022 10:22:39 for gem5 by doxygen 1.9.1