gem5 v24.0.0.0
Loading...
Searching...
No Matches
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
63namespace gem5
64{
65
66namespace ruby
67{
68
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
100void
102{
103 m_networks.emplace_back(network_ptr);
104}
105
106void
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
115void
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().
135void
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
175void
176RubySystem::makeCacheRecorder(uint8_t *uncompressed_trace,
177 uint64_t cache_trace_size,
178 uint64_t block_size_bytes)
179{
180 std::vector<RubyPort*> ruby_port_map;
181 RubyPort* ruby_port_ptr = NULL;
182
183 for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
184 if (m_abs_cntrl_vec[cntrl]->getGPUCoalescer() != NULL) {
185 ruby_port_map.push_back(
186 (RubyPort*)m_abs_cntrl_vec[cntrl]->getGPUCoalescer());
187 } else {
188 ruby_port_map.push_back(
189 (RubyPort*)m_abs_cntrl_vec[cntrl]->getCPUSequencer());
190 }
191
192 if (ruby_port_ptr == NULL) {
193 ruby_port_ptr = ruby_port_map[cntrl];
194 }
195 }
196
197 assert(ruby_port_ptr != NULL);
198
199 for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
200 if (ruby_port_map[cntrl] == NULL) {
201 ruby_port_map[cntrl] = ruby_port_ptr;
202 } else {
203 ruby_port_ptr = ruby_port_map[cntrl];
204 }
205
206 }
207
208 // Remove the old CacheRecorder if it's still hanging about.
209 if (m_cache_recorder != NULL) {
210 delete m_cache_recorder;
211 }
212
213 // Create the CacheRecorder and record the cache trace
214 m_cache_recorder = new CacheRecorder(uncompressed_trace, cache_trace_size,
215 ruby_port_map,
216 block_size_bytes);
217}
218
219void
221{
222 m_cooldown_enabled = true;
223
224 // Make the trace so we know what to write back.
225 DPRINTF(RubyCacheTrace, "Recording Cache Trace\n");
227 for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) {
228 m_abs_cntrl_vec[cntrl]->recordCacheTrace(cntrl, m_cache_recorder);
229 }
230 DPRINTF(RubyCacheTrace, "Cache Trace Complete\n");
231
232 // If there is no dirty block, we don't need to flush the cache
234 {
235 m_cooldown_enabled = false;
236 return;
237 }
238
239 // save the current tick value
240 Tick curtick_original = curTick();
241 DPRINTF(RubyCacheTrace, "Recording current tick %ld\n", curtick_original);
242
243 // Deschedule all prior events on the event queue, but record the tick they
244 // were scheduled at so they can be restored correctly later.
245 std::list<std::pair<Event*, Tick> > original_events;
246 while (!eventq->empty()) {
247 Event *curr_head = eventq->getHead();
248 if (curr_head->isAutoDelete()) {
249 DPRINTF(RubyCacheTrace, "Event %s auto-deletes when descheduled,"
250 " not recording\n", curr_head->name());
251 } else {
252 original_events.push_back(
253 std::make_pair(curr_head, curr_head->when()));
254 }
255 eventq->deschedule(curr_head);
256 }
257
258 // Schedule an event to start cache cooldown
259 DPRINTF(RubyCacheTrace, "Starting cache flush\n");
261 simulate();
262 DPRINTF(RubyCacheTrace, "Cache flush complete\n");
263
264 // Deschedule any events left on the event queue.
265 while (!eventq->empty()) {
267 }
268
269 // Restore curTick
270 setCurTick(curtick_original);
271
272 // Restore all events that were originally on the event queue. This is
273 // done after setting curTick back to its original value so that events do
274 // not seem to be scheduled in the past.
275 while (!original_events.empty()) {
276 std::pair<Event*, Tick> event = original_events.back();
277 eventq->schedule(event.first, event.second);
278 original_events.pop_back();
279 }
280
281 // No longer flushing back to memory.
282 m_cooldown_enabled = false;
283
284 // There are several issues with continuing simulation after calling
285 // memWriteback() at the moment, that stem from taking events off the
286 // queue, simulating again, and then putting them back on, whilst
287 // pretending that no time has passed. One is that some events will have
288 // been deleted, so can't be put back. Another is that any object
289 // recording the tick something happens may end up storing a tick in the
290 // future. A simple warning here alerts the user that things may not work
291 // as expected.
292 warn_once("Ruby memory writeback is experimental. Continuing simulation "
293 "afterwards may not always work as intended.");
294
295 // Keep the cache recorder around so that we can dump the trace if a
296 // checkpoint is immediately taken.
297}
298
299void
300RubySystem::writeCompressedTrace(uint8_t *raw_data, std::string filename,
301 uint64_t uncompressed_trace_size)
302{
303 // Create the checkpoint file for the memory
304 std::string thefile = CheckpointIn::dir() + "/" + filename.c_str();
305
306 int fd = creat(thefile.c_str(), 0664);
307 if (fd < 0) {
308 perror("creat");
309 fatal("Can't open memory trace file '%s'\n", filename);
310 }
311
312 gzFile compressedMemory = gzdopen(fd, "wb");
313 if (compressedMemory == NULL)
314 fatal("Insufficient memory to allocate compression state for %s\n",
315 filename);
316
317 if (gzwrite(compressedMemory, raw_data, uncompressed_trace_size) !=
318 uncompressed_trace_size) {
319 fatal("Write failed on memory trace file '%s'\n", filename);
320 }
321
322 if (gzclose(compressedMemory)) {
323 fatal("Close failed on memory trace file '%s'\n", filename);
324 }
325 delete[] raw_data;
326}
327
328void
330{
331 // Store the cache-block size, so we are able to restore on systems
332 // with a different cache-block size. CacheRecorder depends on the
333 // correct cache-block size upon unserializing.
334 uint64_t block_size_bytes = getBlockSizeBytes();
335 SERIALIZE_SCALAR(block_size_bytes);
336
337 // Check that there's a valid trace to use. If not, then memory won't
338 // be up-to-date and the simulation will probably fail when restoring
339 // from the checkpoint.
340 if (m_cache_recorder == NULL) {
341 fatal("Call memWriteback() before serialize() to create"
342 "ruby trace");
343 }
344
345 // Aggregate the trace entries together into a single array
346 uint8_t *raw_data = new uint8_t[4096];
347 uint64_t cache_trace_size = m_cache_recorder->aggregateRecords(
348 &raw_data, 4096);
349 std::string cache_trace_file = name() + ".cache.gz";
350 writeCompressedTrace(raw_data, cache_trace_file, cache_trace_size);
351
352 SERIALIZE_SCALAR(cache_trace_file);
353 SERIALIZE_SCALAR(cache_trace_size);
354}
355
356void
358{
359 // Delete the cache recorder if it was created in memWriteback()
360 // to checkpoint the current cache state.
361 if (m_cache_recorder) {
362 delete m_cache_recorder;
363 m_cache_recorder = NULL;
364 }
365}
366
367void
368RubySystem::readCompressedTrace(std::string filename, uint8_t *&raw_data,
369 uint64_t &uncompressed_trace_size)
370{
371 // Read the trace file
372 gzFile compressedTrace;
373
374 // trace file
375 int fd = open(filename.c_str(), O_RDONLY);
376 if (fd < 0) {
377 perror("open");
378 fatal("Unable to open trace file %s", filename);
379 }
380
381 compressedTrace = gzdopen(fd, "rb");
382 if (compressedTrace == NULL) {
383 fatal("Insufficient memory to allocate compression state for %s\n",
384 filename);
385 }
386
387 raw_data = new uint8_t[uncompressed_trace_size];
388 if (gzread(compressedTrace, raw_data, uncompressed_trace_size) <
389 uncompressed_trace_size) {
390 fatal("Unable to read complete trace from file %s\n", filename);
391 }
392
393 if (gzclose(compressedTrace)) {
394 fatal("Failed to close cache trace file '%s'\n", filename);
395 }
396}
397
398void
400{
401 uint8_t *uncompressed_trace = NULL;
402
403 // This value should be set to the checkpoint-system's block-size.
404 // Optional, as checkpoints without it can be run if the
405 // checkpoint-system's block-size == current block-size.
406 uint64_t block_size_bytes = getBlockSizeBytes();
407 UNSERIALIZE_OPT_SCALAR(block_size_bytes);
408
409 std::string cache_trace_file;
410 uint64_t cache_trace_size = 0;
411
412 UNSERIALIZE_SCALAR(cache_trace_file);
413 UNSERIALIZE_SCALAR(cache_trace_size);
414 cache_trace_file = cp.getCptDir() + "/" + cache_trace_file;
415
416 readCompressedTrace(cache_trace_file, uncompressed_trace,
417 cache_trace_size);
418 m_warmup_enabled = true;
420
421 // Create the cache recorder that will hang around until startup.
422 makeCacheRecorder(uncompressed_trace, cache_trace_size, block_size_bytes);
423}
424
425void
430
431void
433{
434
435 // Ruby restores state from a checkpoint by resetting the clock to 0 and
436 // playing the requests that can possibly re-generate the cache state.
437 // The clock value is set to the actual checkpointed value once all the
438 // requests have been executed.
439 //
440 // This way of restoring state is pretty finicky. For example, if a
441 // Ruby component reads time before the state has been restored, it would
442 // cache this value and hence its clock would not be reset to 0, when
443 // Ruby resets the global clock. This can potentially result in a
444 // deadlock.
445 //
446 // The solution is that no Ruby component should read time before the
447 // simulation starts. And then one also needs to hope that the time
448 // Ruby finishes restoring the state is less than the time when the
449 // state was checkpointed.
450
451 if (m_warmup_enabled) {
452 DPRINTF(RubyCacheTrace, "Starting ruby cache warmup\n");
453 // save the current tick value
454 Tick curtick_original = curTick();
455 // save the event queue head
456 Event* eventq_head = eventq->replaceHead(NULL);
457 // save the exit event pointer
458 GlobalSimLoopExitEvent *original_simulate_limit_event = nullptr;
459 original_simulate_limit_event = simulate_limit_event;
460 // set curTick to 0 and reset Ruby System's clock
461 setCurTick(0);
462 resetClock();
463
464 // Schedule an event to start cache warmup
466 simulate();
467
468 delete m_cache_recorder;
469 m_cache_recorder = NULL;
471 if (m_systems_to_warmup == 0) {
472 m_warmup_enabled = false;
473 }
474
475 // Restore eventq head
476 eventq->replaceHead(eventq_head);
477 // Restore exit event pointer
478 simulate_limit_event = original_simulate_limit_event;
479 // Restore curTick and Ruby System's clock
480 setCurTick(curtick_original);
481 resetClock();
482 }
483
484 resetStats();
485}
486
487void
496
497void
499{
501 for (auto& network : m_networks) {
502 network->resetStats();
503 }
505}
506
507#ifndef PARTIAL_FUNC_READS
508bool
510{
511 Addr address(pkt->getAddr());
512 Addr line_address = makeLineAddress(address);
513
514 AccessPermission access_perm = AccessPermission_NotPresent;
515
516 DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
517
518 unsigned int num_ro = 0;
519 unsigned int num_rw = 0;
520 unsigned int num_busy = 0;
521 unsigned int num_maybe_stale = 0;
522 unsigned int num_backing_store = 0;
523 unsigned int num_invalid = 0;
524
525 // Only send functional requests within the same network.
526 assert(requestorToNetwork.count(pkt->requestorId()));
527 int request_net_id = requestorToNetwork[pkt->requestorId()];
528 assert(netCntrls.count(request_net_id));
529
530 AbstractController *ctrl_ro = nullptr;
531 AbstractController *ctrl_rw = nullptr;
532 AbstractController *ctrl_backing_store = nullptr;
533
534 // In this loop we count the number of controllers that have the given
535 // address in read only, read write and busy states.
536 for (auto& cntrl : netCntrls[request_net_id]) {
537 access_perm = cntrl-> getAccessPermission(line_address);
538 if (access_perm == AccessPermission_Read_Only){
539 num_ro++;
540 if (ctrl_ro == nullptr) ctrl_ro = cntrl;
541 }
542 else if (access_perm == AccessPermission_Read_Write){
543 num_rw++;
544 if (ctrl_rw == nullptr) ctrl_rw = cntrl;
545 }
546 else if (access_perm == AccessPermission_Busy)
547 num_busy++;
548 else if (access_perm == AccessPermission_Maybe_Stale)
549 num_maybe_stale++;
550 else if (access_perm == AccessPermission_Backing_Store) {
551 // See RubySlicc_Exports.sm for details, but Backing_Store is meant
552 // to represent blocks in memory *for Broadcast/Snooping protocols*,
553 // where memory has no idea whether it has an exclusive copy of data
554 // or not.
555 num_backing_store++;
556 if (ctrl_backing_store == nullptr)
557 ctrl_backing_store = cntrl;
558 }
559 else if (access_perm == AccessPermission_Invalid ||
560 access_perm == AccessPermission_NotPresent)
561 num_invalid++;
562 }
563
564 // This if case is meant to capture what happens in a Broadcast/Snoop
565 // protocol where the block does not exist in the cache hierarchy. You
566 // only want to read from the Backing_Store memory if there is no copy in
567 // the cache hierarchy, otherwise you want to try to read the RO or RW
568 // copies existing in the cache hierarchy (covered by the else statement).
569 // The reason is because the Backing_Store memory could easily be stale, if
570 // there are copies floating around the cache hierarchy, so you want to read
571 // it only if it's not in the cache hierarchy at all.
572 int num_controllers = netCntrls[request_net_id].size();
573 if (num_invalid == (num_controllers - 1) && num_backing_store == 1) {
574 DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n");
575 ctrl_backing_store->functionalRead(line_address, pkt);
576 return true;
577 } else if (num_ro > 0 || num_rw >= 1) {
578 if (num_rw > 1) {
579 // We iterate over the vector of abstract controllers, and return
580 // the first copy found. If we have more than one cache with block
581 // in writable permission, the first one found would be returned.
582 warn("More than one Abstract Controller with RW permission for "
583 "addr: %#x on cacheline: %#x.", address, line_address);
584 }
585 // In Broadcast/Snoop protocols, this covers if you know the block
586 // exists somewhere in the caching hierarchy, then you want to read any
587 // valid RO or RW block. In directory protocols, same thing, you want
588 // to read any valid readable copy of the block.
589 DPRINTF(RubySystem, "num_maybe_stale=%d, num_busy = %d, num_ro = %d, "
590 "num_rw = %d\n",
591 num_maybe_stale, num_busy, num_ro, num_rw);
592 // Use the copy from the controller with read/write permission (if
593 // any), otherwise use get the first read only found
594 if (ctrl_rw) {
595 ctrl_rw->functionalRead(line_address, pkt);
596 } else {
597 assert(ctrl_ro);
598 ctrl_ro->functionalRead(line_address, pkt);
599 }
600 return true;
601 } else if ((num_busy + num_maybe_stale) > 0) {
602 // No controller has a valid copy of the block, but a transient or
603 // stale state indicates a valid copy should be in transit in the
604 // network or in a message buffer waiting to be handled
605 DPRINTF(RubySystem, "Controllers functionalRead lookup "
606 "(num_maybe_stale=%d, num_busy = %d)\n",
607 num_maybe_stale, num_busy);
608 for (auto& cntrl : netCntrls[request_net_id]) {
609 if (cntrl->functionalReadBuffers(pkt))
610 return true;
611 }
612 DPRINTF(RubySystem, "Network functionalRead lookup "
613 "(num_maybe_stale=%d, num_busy = %d)\n",
614 num_maybe_stale, num_busy);
615 for (auto& network : m_networks) {
616 if (network->functionalRead(pkt))
617 return true;
618 }
619 }
620
621 return false;
622}
623#else
624bool
626{
627 Addr address(pkt->getAddr());
628 Addr line_address = makeLineAddress(address);
629
630 DPRINTF(RubySystem, "Functional Read request for %#x\n", address);
631
635 AbstractController *ctrl_rw = nullptr;
636 AbstractController *ctrl_bs = nullptr;
637
638 // Build lists of controllers that have line
639 for (auto ctrl : m_abs_cntrl_vec) {
640 switch(ctrl->getAccessPermission(line_address)) {
641 case AccessPermission_Read_Only:
642 ctrl_ro.push_back(ctrl);
643 break;
644 case AccessPermission_Busy:
645 ctrl_busy.push_back(ctrl);
646 break;
647 case AccessPermission_Read_Write:
648 assert(ctrl_rw == nullptr);
649 ctrl_rw = ctrl;
650 break;
651 case AccessPermission_Backing_Store:
652 assert(ctrl_bs == nullptr);
653 ctrl_bs = ctrl;
654 break;
655 case AccessPermission_Backing_Store_Busy:
656 assert(ctrl_bs == nullptr);
657 ctrl_bs = ctrl;
658 ctrl_busy.push_back(ctrl);
659 break;
660 default:
661 ctrl_others.push_back(ctrl);
662 break;
663 }
664 }
665
666 DPRINTF(RubySystem, "num_ro=%d, num_busy=%d , has_rw=%d, "
667 "backing_store=%d\n",
668 ctrl_ro.size(), ctrl_busy.size(),
669 ctrl_rw != nullptr, ctrl_bs != nullptr);
670
671 // Issue functional reads to all controllers found in a stable state
672 // until we get a full copy of the line
673 WriteMask bytes;
674 if (ctrl_rw != nullptr) {
675 ctrl_rw->functionalRead(line_address, pkt, bytes);
676 // if a RW controllter has the full line that's all uptodate
677 if (bytes.isFull())
678 return true;
679 }
680
681 // Get data from RO and BS
682 for (auto ctrl : ctrl_ro)
683 ctrl->functionalRead(line_address, pkt, bytes);
684
685 if (ctrl_bs)
686 ctrl_bs->functionalRead(line_address, pkt, bytes);
687
688 // if there is any busy controller or bytes still not set, then a partial
689 // and/or dirty copy of the line might be in a message buffer or the
690 // network
691 if (!ctrl_busy.empty() || !bytes.isFull()) {
692 DPRINTF(RubySystem, "Reading from remaining controllers, "
693 "buffers and networks\n");
694 if (ctrl_rw != nullptr)
695 ctrl_rw->functionalReadBuffers(pkt, bytes);
696 for (auto ctrl : ctrl_ro)
697 ctrl->functionalReadBuffers(pkt, bytes);
698 if (ctrl_bs != nullptr)
699 ctrl_bs->functionalReadBuffers(pkt, bytes);
700 for (auto ctrl : ctrl_busy) {
701 ctrl->functionalRead(line_address, pkt, bytes);
702 ctrl->functionalReadBuffers(pkt, bytes);
703 }
704 for (auto& network : m_networks) {
705 network->functionalRead(pkt, bytes);
706 }
707 for (auto ctrl : ctrl_others) {
708 ctrl->functionalRead(line_address, pkt, bytes);
709 ctrl->functionalReadBuffers(pkt, bytes);
710 }
711 }
712 // we either got the full line or couldn't find anything at this point
713 panic_if(!(bytes.isFull() || bytes.isEmpty()),
714 "Inconsistent state on functional read for %#x %s\n",
715 address, bytes);
716
717 return bytes.isFull();
718}
719#endif
720
721// The function searches through all the buffers that exist in different
722// cache, directory and memory controllers, and in the network components
723// and writes the data portion of those that hold the address specified
724// in the packet.
725bool
727{
728 Addr addr(pkt->getAddr());
729 Addr line_addr = makeLineAddress(addr);
730 AccessPermission access_perm = AccessPermission_NotPresent;
731
732 DPRINTF(RubySystem, "Functional Write request for %#x\n", addr);
733
734 [[maybe_unused]] uint32_t num_functional_writes = 0;
735
736 // Only send functional requests within the same network.
737 assert(requestorToNetwork.count(pkt->requestorId()));
738 int request_net_id = requestorToNetwork[pkt->requestorId()];
739 assert(netCntrls.count(request_net_id));
740
741 for (auto& cntrl : netCntrls[request_net_id]) {
742 num_functional_writes += cntrl->functionalWriteBuffers(pkt);
743
744 access_perm = cntrl->getAccessPermission(line_addr);
745 if (access_perm != AccessPermission_Invalid &&
746 access_perm != AccessPermission_NotPresent) {
747 num_functional_writes +=
748 cntrl->functionalWrite(line_addr, pkt);
749 }
750
751 // Also updates requests pending in any sequencer associated
752 // with the controller
753 if (cntrl->getCPUSequencer()) {
754 num_functional_writes +=
755 cntrl->getCPUSequencer()->functionalWrite(pkt);
756 }
757 if (cntrl->getDMASequencer()) {
758 num_functional_writes +=
759 cntrl->getDMASequencer()->functionalWrite(pkt);
760 }
761 }
762
763 for (auto& network : m_networks) {
764 num_functional_writes += network->functionalWrite(pkt);
765 }
766 DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes);
767
768 return true;
769}
770
771} // namespace ruby
772} // namespace gem5
#define DPRINTF(x,...)
Definition trace.hh:210
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:1073
EventQueue * eventq
A pointer to this object's event queue.
Definition eventq.hh:984
Event * getHead() const
Definition eventq.hh:851
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:382
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:295
Addr getAddr() const
Definition packet.hh:807
RequestorID requestorId() const
Definition packet.hh:780
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)
uint64_t getNumRecords() const
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)
static bool m_warmup_enabled
static bool getWarmupEnabled()
Definition RubySystem.hh:75
bool functionalWrite(Packet *ptr)
static uint32_t getBlockSizeBytes()
Definition RubySystem.hh:72
void unserialize(CheckpointIn &cp) override
Unserialize an object.
void init() override
init() is called after all C++ SimObjects have been created and all ports are connected.
static bool m_cooldown_enabled
std::vector< std::map< uint32_t, AbstractController * > > m_abstract_controls
void registerMachineID(const MachineID &mach_id, Network *network)
static bool m_randomization
static unsigned m_systems_to_warmup
std::unordered_map< RequestorID, unsigned > requestorToNetwork
static void writeCompressedTrace(uint8_t *raw_data, std::string file, uint64_t uncompressed_trace_size)
RubySystem(const Params &p)
Definition RubySystem.cc:79
void registerNetwork(Network *)
void startup() override
startup() is the final initialization call before simulation.
std::unordered_map< MachineID, unsigned > machineToNetwork
static void readCompressedTrace(std::string filename, uint8_t *&raw_data, uint64_t &uncompressed_trace_size)
void registerAbstractController(AbstractController *)
CacheRecorder * m_cache_recorder
static uint32_t m_block_size_bits
std::vector< std::unique_ptr< Network > > m_networks
void drainResume() override
Resume execution after a successful drain.
static uint32_t m_block_size_bytes
std::vector< AbstractController * > m_abs_cntrl_vec
void resetStats() override
Callback to reset stats.
memory::SimpleMemory * m_phys_mem
std::unordered_map< unsigned, std::vector< AbstractController * > > netCntrls
static uint32_t m_memory_size_bits
bool functionalRead(Packet *ptr)
void makeCacheRecorder(uint8_t *uncompressed_trace, uint64_t cache_trace_size, uint64_t block_size_bytes)
void serialize(CheckpointOut &cp) const override
Serialize an object.
void memWriteback() override
Write back dirty buffers to memory using functional writes.
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:757
void deschedule(Event *event)
Deschedule the specified event.
Definition eventq.hh:790
bool isAutoDelete() const
The function returns true if the object is automatically deleted after the event is processed.
Definition eventq.hh:494
virtual const std::string name() const
Definition eventq.cc:84
bool empty() const
Returns true if no events are queued.
Definition eventq.hh:891
Tick when() const
Get the time that the event is scheduled.
Definition eventq.hh:501
#define fatal_if(cond,...)
Conditional fatal macro that checks the supplied condition and only causes a fatal error if the condi...
Definition logging.hh:236
#define fatal(...)
This implements a cprintf based fatal() function.
Definition logging.hh:200
#define panic_if(cond,...)
Conditional panic macro that checks the supplied condition and only panics if the condition is true a...
Definition logging.hh:214
#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:157
const Params & params() const
virtual void resetStats()
Callback to reset stats.
Definition group.cc:86
#define warn(...)
Definition logging.hh:256
#define warn_once(...)
Definition logging.hh:260
Bitfield< 14, 12 > fd
Definition types.hh:150
Bitfield< 33 > id
Bitfield< 10, 5 > event
Bitfield< 0 > p
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.
Copyright (c) 2024 - Pranith Kumar Copyright (c) 2020 Inria All rights reserved.
Definition binary32.hh:36
GlobalSimLoopExitEvent * simulate_limit_event
Definition simulate.cc:64
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)
Definition simulate.cc:189
#define UNSERIALIZE_SCALAR(scalar)
Definition serialize.hh:575
#define SERIALIZE_SCALAR(scalar)
Definition serialize.hh:568
SimpleMemory declaration.
Declaration of Statistics objects.

Generated on Tue Jun 18 2024 16:24:05 for gem5 by doxygen 1.11.0