gem5  v21.1.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  }
480 }
481 
482 #ifndef PARTIAL_FUNC_READS
483 bool
485 {
486  Addr address(pkt->getAddr());
487  Addr line_address = makeLineAddress(address);
488 
489  AccessPermission access_perm = AccessPermission_NotPresent;
490 
491  DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
492 
493  unsigned int num_ro = 0;
494  unsigned int num_rw = 0;
495  unsigned int num_busy = 0;
496  unsigned int num_maybe_stale = 0;
497  unsigned int num_backing_store = 0;
498  unsigned int num_invalid = 0;
499 
500  // Only send functional requests within the same network.
501  assert(requestorToNetwork.count(pkt->requestorId()));
502  int request_net_id = requestorToNetwork[pkt->requestorId()];
503  assert(netCntrls.count(request_net_id));
504 
505  AbstractController *ctrl_ro = nullptr;
506  AbstractController *ctrl_rw = nullptr;
507  AbstractController *ctrl_backing_store = nullptr;
508 
509  // In this loop we count the number of controllers that have the given
510  // address in read only, read write and busy states.
511  for (auto& cntrl : netCntrls[request_net_id]) {
512  access_perm = cntrl-> getAccessPermission(line_address);
513  if (access_perm == AccessPermission_Read_Only){
514  num_ro++;
515  if (ctrl_ro == nullptr) ctrl_ro = cntrl;
516  }
517  else if (access_perm == AccessPermission_Read_Write){
518  num_rw++;
519  if (ctrl_rw == nullptr) ctrl_rw = cntrl;
520  }
521  else if (access_perm == AccessPermission_Busy)
522  num_busy++;
523  else if (access_perm == AccessPermission_Maybe_Stale)
524  num_maybe_stale++;
525  else if (access_perm == AccessPermission_Backing_Store) {
526  // See RubySlicc_Exports.sm for details, but Backing_Store is meant
527  // to represent blocks in memory *for Broadcast/Snooping protocols*,
528  // where memory has no idea whether it has an exclusive copy of data
529  // or not.
530  num_backing_store++;
531  if (ctrl_backing_store == nullptr)
532  ctrl_backing_store = cntrl;
533  }
534  else if (access_perm == AccessPermission_Invalid ||
535  access_perm == AccessPermission_NotPresent)
536  num_invalid++;
537  }
538 
539  // This if case is meant to capture what happens in a Broadcast/Snoop
540  // protocol where the block does not exist in the cache hierarchy. You
541  // only want to read from the Backing_Store memory if there is no copy in
542  // the cache hierarchy, otherwise you want to try to read the RO or RW
543  // copies existing in the cache hierarchy (covered by the else statement).
544  // The reason is because the Backing_Store memory could easily be stale, if
545  // there are copies floating around the cache hierarchy, so you want to read
546  // it only if it's not in the cache hierarchy at all.
547  int num_controllers = netCntrls[request_net_id].size();
548  if (num_invalid == (num_controllers - 1) && num_backing_store == 1) {
549  DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n");
550  ctrl_backing_store->functionalRead(line_address, pkt);
551  return true;
552  } else if (num_ro > 0 || num_rw >= 1) {
553  if (num_rw > 1) {
554  // We iterate over the vector of abstract controllers, and return
555  // the first copy found. If we have more than one cache with block
556  // in writable permission, the first one found would be returned.
557  warn("More than one Abstract Controller with RW permission for "
558  "addr: %#x on cacheline: %#x.", address, line_address);
559  }
560  // In Broadcast/Snoop protocols, this covers if you know the block
561  // exists somewhere in the caching hierarchy, then you want to read any
562  // valid RO or RW block. In directory protocols, same thing, you want
563  // to read any valid readable copy of the block.
564  DPRINTF(RubySystem, "num_maybe_stale=%d, num_busy = %d, num_ro = %d, "
565  "num_rw = %d\n",
566  num_maybe_stale, num_busy, num_ro, num_rw);
567  // Use the copy from the controller with read/write permission (if
568  // any), otherwise use get the first read only found
569  if (ctrl_rw) {
570  ctrl_rw->functionalRead(line_address, pkt);
571  } else {
572  assert(ctrl_ro);
573  ctrl_ro->functionalRead(line_address, pkt);
574  }
575  return true;
576  } else if ((num_busy + num_maybe_stale) > 0) {
577  // No controller has a valid copy of the block, but a transient or
578  // stale state indicates a valid copy should be in transit in the
579  // network or in a message buffer waiting to be handled
580  DPRINTF(RubySystem, "Controllers functionalRead lookup "
581  "(num_maybe_stale=%d, num_busy = %d)\n",
582  num_maybe_stale, num_busy);
583  for (auto& cntrl : netCntrls[request_net_id]) {
584  if (cntrl->functionalReadBuffers(pkt))
585  return true;
586  }
587  DPRINTF(RubySystem, "Network functionalRead lookup "
588  "(num_maybe_stale=%d, num_busy = %d)\n",
589  num_maybe_stale, num_busy);
590  for (auto& network : m_networks) {
591  if (network->functionalRead(pkt))
592  return true;
593  }
594  }
595 
596  return false;
597 }
598 #else
599 bool
601 {
602  Addr address(pkt->getAddr());
603  Addr line_address = makeLineAddress(address);
604 
605  DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
606 
610  AbstractController *ctrl_rw = nullptr;
611  AbstractController *ctrl_bs = nullptr;
612 
613  // Build lists of controllers that have line
614  for (auto ctrl : m_abs_cntrl_vec) {
615  switch(ctrl->getAccessPermission(line_address)) {
616  case AccessPermission_Read_Only:
617  ctrl_ro.push_back(ctrl);
618  break;
619  case AccessPermission_Busy:
620  ctrl_busy.push_back(ctrl);
621  break;
622  case AccessPermission_Read_Write:
623  assert(ctrl_rw == nullptr);
624  ctrl_rw = ctrl;
625  break;
626  case AccessPermission_Backing_Store:
627  assert(ctrl_bs == nullptr);
628  ctrl_bs = ctrl;
629  break;
630  case AccessPermission_Backing_Store_Busy:
631  assert(ctrl_bs == nullptr);
632  ctrl_bs = ctrl;
633  ctrl_busy.push_back(ctrl);
634  break;
635  default:
636  ctrl_others.push_back(ctrl);
637  break;
638  }
639  }
640 
641  DPRINTF(RubySystem, "num_ro=%d, num_busy=%d , has_rw=%d, "
642  "backing_store=%d\n",
643  ctrl_ro.size(), ctrl_busy.size(),
644  ctrl_rw != nullptr, ctrl_bs != nullptr);
645 
646  // Issue functional reads to all controllers found in a stable state
647  // until we get a full copy of the line
648  WriteMask bytes;
649  if (ctrl_rw != nullptr) {
650  ctrl_rw->functionalRead(line_address, pkt, bytes);
651  // if a RW controllter has the full line that's all uptodate
652  if (bytes.isFull())
653  return true;
654  }
655 
656  // Get data from RO and BS
657  for (auto ctrl : ctrl_ro)
658  ctrl->functionalRead(line_address, pkt, bytes);
659 
660  if (ctrl_bs)
661  ctrl_bs->functionalRead(line_address, pkt, bytes);
662 
663  // if there is any busy controller or bytes still not set, then a partial
664  // and/or dirty copy of the line might be in a message buffer or the
665  // network
666  if (!ctrl_busy.empty() || !bytes.isFull()) {
667  DPRINTF(RubySystem, "Reading from remaining controllers, "
668  "buffers and networks\n");
669  if (ctrl_rw != nullptr)
670  ctrl_rw->functionalReadBuffers(pkt, bytes);
671  for (auto ctrl : ctrl_ro)
672  ctrl->functionalReadBuffers(pkt, bytes);
673  if (ctrl_bs != nullptr)
674  ctrl_bs->functionalReadBuffers(pkt, bytes);
675  for (auto ctrl : ctrl_busy) {
676  ctrl->functionalRead(line_address, pkt, bytes);
677  ctrl->functionalReadBuffers(pkt, bytes);
678  }
679  for (auto& network : m_networks) {
680  network->functionalRead(pkt, bytes);
681  }
682  for (auto ctrl : ctrl_others) {
683  ctrl->functionalRead(line_address, pkt, bytes);
684  ctrl->functionalReadBuffers(pkt, bytes);
685  }
686  }
687  // we either got the full line or couldn't find anything at this point
688  panic_if(!(bytes.isFull() || bytes.isEmpty()),
689  "Inconsistent state on functional read for %#x %s\n",
690  address, bytes);
691 
692  return bytes.isFull();
693 }
694 #endif
695 
696 // The function searches through all the buffers that exist in different
697 // cache, directory and memory controllers, and in the network components
698 // and writes the data portion of those that hold the address specified
699 // in the packet.
700 bool
702 {
703  Addr addr(pkt->getAddr());
704  Addr line_addr = makeLineAddress(addr);
705  AccessPermission access_perm = AccessPermission_NotPresent;
706 
707  DPRINTF(RubySystem, "Functional Write request for %#x\n", addr);
708 
709  GEM5_VAR_USED uint32_t num_functional_writes = 0;
710 
711  // Only send functional requests within the same network.
712  assert(requestorToNetwork.count(pkt->requestorId()));
713  int request_net_id = requestorToNetwork[pkt->requestorId()];
714  assert(netCntrls.count(request_net_id));
715 
716  for (auto& cntrl : netCntrls[request_net_id]) {
717  num_functional_writes += cntrl->functionalWriteBuffers(pkt);
718 
719  access_perm = cntrl->getAccessPermission(line_addr);
720  if (access_perm != AccessPermission_Invalid &&
721  access_perm != AccessPermission_NotPresent) {
722  num_functional_writes +=
723  cntrl->functionalWrite(line_addr, pkt);
724  }
725 
726  // Also updates requests pending in any sequencer associated
727  // with the controller
728  if (cntrl->getCPUSequencer()) {
729  num_functional_writes +=
730  cntrl->getCPUSequencer()->functionalWrite(pkt);
731  }
732  if (cntrl->getDMASequencer()) {
733  num_functional_writes +=
734  cntrl->getDMASequencer()->functionalWrite(pkt);
735  }
736  }
737 
738  for (auto& network : m_networks) {
739  num_functional_writes += network->functionalWrite(pkt);
740  }
741  DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes);
742 
743  return true;
744 }
745 
746 } // namespace ruby
747 } // 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:189
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:245
gem5::ruby::RubySystem::functionalRead
bool functionalRead(Packet *ptr)
Definition: RubySystem.cc:484
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:249
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::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::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:324
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:767
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:283
gem5::EventQueue::deschedule
void deschedule(Event *event)
Deschedule the specified event.
Definition: eventq.hh:797
gem5::MipsISA::p
Bitfield< 0 > p
Definition: pra_constants.hh:326
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:83
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:203
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::floorLog2
static constexpr std::enable_if_t< std::is_integral< T >::value, int > floorLog2(T x)
Definition: intmath.hh:59
gem5::ruby::RubySystem::functionalWrite
bool functionalWrite(Packet *ptr)
Definition: RubySystem.cc:701
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:250
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:781
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:225
gem5
Reference material can be found at the JEDEC website: UFS standard http://www.jedec....
Definition: decoder.cc:40
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 Tue Sep 21 2021 12:25:42 for gem5 by doxygen 1.8.17