RubySystem.cc revision 10917
17008Snate@binkert.org/* 27008Snate@binkert.org * Copyright (c) 1999-2011 Mark D. Hill and David A. Wood 37008Snate@binkert.org * All rights reserved. 47008Snate@binkert.org * 57008Snate@binkert.org * Redistribution and use in source and binary forms, with or without 67008Snate@binkert.org * modification, are permitted provided that the following conditions are 77008Snate@binkert.org * met: redistributions of source code must retain the above copyright 87008Snate@binkert.org * notice, this list of conditions and the following disclaimer; 97008Snate@binkert.org * redistributions in binary form must reproduce the above copyright 107008Snate@binkert.org * notice, this list of conditions and the following disclaimer in the 117008Snate@binkert.org * documentation and/or other materials provided with the distribution; 127008Snate@binkert.org * neither the name of the copyright holders nor the names of its 137008Snate@binkert.org * contributors may be used to endorse or promote products derived from 147008Snate@binkert.org * this software without specific prior written permission. 157008Snate@binkert.org * 167008Snate@binkert.org * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 177008Snate@binkert.org * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 187008Snate@binkert.org * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 197008Snate@binkert.org * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 207008Snate@binkert.org * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 217008Snate@binkert.org * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 227008Snate@binkert.org * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 237008Snate@binkert.org * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 247008Snate@binkert.org * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 257008Snate@binkert.org * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 267008Snate@binkert.org * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 277008Snate@binkert.org */ 286285Snate@binkert.org 2910472Sandreas.hansson@arm.com#include <fcntl.h> 3010472Sandreas.hansson@arm.com#include <zlib.h> 3110518Snilay@cs.wisc.edu 3210518Snilay@cs.wisc.edu#include <cstdio> 338232Snate@binkert.org 349104Shestness@cs.utexas.edu#include "base/intmath.hh" 357039Snate@binkert.org#include "base/statistics.hh" 367039Snate@binkert.org#include "debug/RubyCacheTrace.hh" 376285Snate@binkert.org#include "debug/RubySystem.hh" 3810518Snilay@cs.wisc.edu#include "mem/ruby/common/Address.hh" 396285Snate@binkert.org#include "mem/ruby/network/Network.hh" 406876Ssteve.reinhardt@amd.com#include "mem/ruby/system/System.hh" 4110919Sbrandon.potter@amd.com#include "mem/simple_mem.hh" 4210919Sbrandon.potter@amd.com#include "sim/eventq.hh" 4310919Sbrandon.potter@amd.com#include "sim/simulate.hh" 4410706Spower.jg@gmail.com 4510706Spower.jg@gmail.comusing namespace std; 4610913Sandreas.sandberg@arm.com 476285Snate@binkert.orgint RubySystem::m_random_seed; 4810518Snilay@cs.wisc.edubool RubySystem::m_randomization; 496285Snate@binkert.orguint32_t RubySystem::m_block_size_bytes; 506285Snate@binkert.orguint32_t RubySystem::m_block_size_bits; 517039Snate@binkert.orguint32_t RubySystem::m_memory_size_bits; 527039Snate@binkert.orgbool RubySystem::m_warmup_enabled = false; 536285Snate@binkert.org// To look forward to allowing multiple RubySystem instances, track the number 5410518Snilay@cs.wisc.edu// of RubySystems that need to be warmed up on checkpoint restore. 5510518Snilay@cs.wisc.eduunsigned RubySystem::m_systems_to_warmup = 0; 5610518Snilay@cs.wisc.edubool RubySystem::m_cooldown_enabled = false; 5710518Snilay@cs.wisc.edu 587039Snate@binkert.orgRubySystem::RubySystem(const Params *p) 597039Snate@binkert.org : ClockedObject(p), m_access_backing_store(p->access_backing_store) 6010519Snilay@cs.wisc.edu{ 6110519Snilay@cs.wisc.edu if (g_system_ptr != NULL) 626285Snate@binkert.org fatal("Only one RubySystem object currently allowed.\n"); 636285Snate@binkert.org 6410518Snilay@cs.wisc.edu m_random_seed = p->random_seed; 6510518Snilay@cs.wisc.edu srandom(m_random_seed); 6610518Snilay@cs.wisc.edu m_randomization = p->randomization; 6710518Snilay@cs.wisc.edu 6810518Snilay@cs.wisc.edu m_block_size_bytes = p->block_size_bytes; 6910518Snilay@cs.wisc.edu assert(isPowerOf2(m_block_size_bytes)); 7010518Snilay@cs.wisc.edu m_block_size_bits = floorLog2(m_block_size_bytes); 7110518Snilay@cs.wisc.edu m_memory_size_bits = p->memory_size_bits; 7210518Snilay@cs.wisc.edu 7310518Snilay@cs.wisc.edu // Setup the global variables used in Ruby 7410518Snilay@cs.wisc.edu g_system_ptr = this; 7510518Snilay@cs.wisc.edu 7610518Snilay@cs.wisc.edu // Resize to the size of different machine types 7710518Snilay@cs.wisc.edu g_abs_controls.resize(MachineType_NUM); 7810706Spower.jg@gmail.com 7910706Spower.jg@gmail.com // Collate the statistics before they are printed. 8010706Spower.jg@gmail.com Stats::registerDumpCallback(new RubyStatsCallback(this)); 8110919Sbrandon.potter@amd.com // Create the profiler 8210518Snilay@cs.wisc.edu m_profiler = new Profiler(p); 8310518Snilay@cs.wisc.edu m_phys_mem = p->phys_mem; 8410518Snilay@cs.wisc.edu} 8510518Snilay@cs.wisc.edu 8610518Snilay@cs.wisc.eduvoid 8710518Snilay@cs.wisc.eduRubySystem::registerNetwork(Network* network_ptr) 8810518Snilay@cs.wisc.edu{ 8910518Snilay@cs.wisc.edu m_network = network_ptr; 9010518Snilay@cs.wisc.edu} 9110518Snilay@cs.wisc.edu 9210518Snilay@cs.wisc.eduvoid 9310518Snilay@cs.wisc.eduRubySystem::registerAbstractController(AbstractController* cntrl) 9410518Snilay@cs.wisc.edu{ 9510518Snilay@cs.wisc.edu m_abs_cntrl_vec.push_back(cntrl); 9610518Snilay@cs.wisc.edu 9711025Snilay@cs.wisc.edu MachineID id = cntrl->getMachineID(); 9810518Snilay@cs.wisc.edu g_abs_controls[id.getType()][id.getNum()] = cntrl; 9910518Snilay@cs.wisc.edu} 10010518Snilay@cs.wisc.edu 10110518Snilay@cs.wisc.eduRubySystem::~RubySystem() 10210518Snilay@cs.wisc.edu{ 10310518Snilay@cs.wisc.edu delete m_network; 10410518Snilay@cs.wisc.edu delete m_profiler; 10510518Snilay@cs.wisc.edu} 10610518Snilay@cs.wisc.edu 10710518Snilay@cs.wisc.eduvoid 10810518Snilay@cs.wisc.eduRubySystem::writeCompressedTrace(uint8_t *raw_data, string filename, 10910518Snilay@cs.wisc.edu uint64 uncompressed_trace_size) 11010518Snilay@cs.wisc.edu{ 11110518Snilay@cs.wisc.edu // Create the checkpoint file for the memory 11210518Snilay@cs.wisc.edu string thefile = CheckpointIn::dir() + "/" + filename.c_str(); 11310518Snilay@cs.wisc.edu 11410518Snilay@cs.wisc.edu int fd = creat(thefile.c_str(), 0664); 11510518Snilay@cs.wisc.edu if (fd < 0) { 11610518Snilay@cs.wisc.edu perror("creat"); 11710518Snilay@cs.wisc.edu fatal("Can't open memory trace file '%s'\n", filename); 11810518Snilay@cs.wisc.edu } 11910518Snilay@cs.wisc.edu 12010518Snilay@cs.wisc.edu gzFile compressedMemory = gzdopen(fd, "wb"); 12110518Snilay@cs.wisc.edu if (compressedMemory == NULL) 12210518Snilay@cs.wisc.edu fatal("Insufficient memory to allocate compression state for %s\n", 12310518Snilay@cs.wisc.edu filename); 12410518Snilay@cs.wisc.edu 12510518Snilay@cs.wisc.edu if (gzwrite(compressedMemory, raw_data, uncompressed_trace_size) != 12610518Snilay@cs.wisc.edu uncompressed_trace_size) { 12710518Snilay@cs.wisc.edu fatal("Write failed on memory trace file '%s'\n", filename); 12810518Snilay@cs.wisc.edu } 12910518Snilay@cs.wisc.edu 13010518Snilay@cs.wisc.edu if (gzclose(compressedMemory)) { 13110518Snilay@cs.wisc.edu fatal("Close failed on memory trace file '%s'\n", filename); 13210518Snilay@cs.wisc.edu } 13310518Snilay@cs.wisc.edu delete[] raw_data; 13410518Snilay@cs.wisc.edu} 13510518Snilay@cs.wisc.edu 13610518Snilay@cs.wisc.eduvoid 13710518Snilay@cs.wisc.eduRubySystem::serializeOld(CheckpointOut &cp) 13810518Snilay@cs.wisc.edu{ 13910518Snilay@cs.wisc.edu m_cooldown_enabled = true; 14010518Snilay@cs.wisc.edu vector<Sequencer*> sequencer_map; 14110518Snilay@cs.wisc.edu Sequencer* sequencer_ptr = NULL; 14210713Sandreas.hansson@arm.com 14310518Snilay@cs.wisc.edu for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 14410518Snilay@cs.wisc.edu sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getSequencer()); 14510518Snilay@cs.wisc.edu if (sequencer_ptr == NULL) { 14610518Snilay@cs.wisc.edu sequencer_ptr = sequencer_map[cntrl]; 14710518Snilay@cs.wisc.edu } 14810518Snilay@cs.wisc.edu } 14910518Snilay@cs.wisc.edu 15010518Snilay@cs.wisc.edu assert(sequencer_ptr != NULL); 15110518Snilay@cs.wisc.edu 15210913Sandreas.sandberg@arm.com for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 15310518Snilay@cs.wisc.edu if (sequencer_map[cntrl] == NULL) { 15410518Snilay@cs.wisc.edu sequencer_map[cntrl] = sequencer_ptr; 15510518Snilay@cs.wisc.edu } 15610518Snilay@cs.wisc.edu } 15710913Sandreas.sandberg@arm.com 15810518Snilay@cs.wisc.edu // Store the cache-block size, so we are able to restore on systems with a 15910518Snilay@cs.wisc.edu // different cache-block size. CacheRecorder depends on the correct 16010518Snilay@cs.wisc.edu // cache-block size upon unserializing. 16110518Snilay@cs.wisc.edu uint64 block_size_bytes = getBlockSizeBytes(); 16210913Sandreas.sandberg@arm.com SERIALIZE_SCALAR(block_size_bytes); 16310913Sandreas.sandberg@arm.com 16410518Snilay@cs.wisc.edu DPRINTF(RubyCacheTrace, "Recording Cache Trace\n"); 16510518Snilay@cs.wisc.edu // Create the CacheRecorder and record the cache trace 16610518Snilay@cs.wisc.edu m_cache_recorder = new CacheRecorder(NULL, 0, sequencer_map, 16710518Snilay@cs.wisc.edu block_size_bytes); 16810518Snilay@cs.wisc.edu 16910518Snilay@cs.wisc.edu for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 17010913Sandreas.sandberg@arm.com m_abs_cntrl_vec[cntrl]->recordCacheTrace(cntrl, m_cache_recorder); 17110518Snilay@cs.wisc.edu } 17210518Snilay@cs.wisc.edu 17310518Snilay@cs.wisc.edu DPRINTF(RubyCacheTrace, "Cache Trace Complete\n"); 17410913Sandreas.sandberg@arm.com // save the current tick value 17510518Snilay@cs.wisc.edu Tick curtick_original = curTick(); 17610913Sandreas.sandberg@arm.com // save the event queue head 17710913Sandreas.sandberg@arm.com Event* eventq_head = eventq->replaceHead(NULL); 17810913Sandreas.sandberg@arm.com DPRINTF(RubyCacheTrace, "Recording current tick %ld and event queue\n", 17910518Snilay@cs.wisc.edu curtick_original); 18010518Snilay@cs.wisc.edu 18110518Snilay@cs.wisc.edu // Schedule an event to start cache cooldown 18210518Snilay@cs.wisc.edu DPRINTF(RubyCacheTrace, "Starting cache flush\n"); 18310518Snilay@cs.wisc.edu enqueueRubyEvent(curTick()); 18410518Snilay@cs.wisc.edu simulate(); 18510518Snilay@cs.wisc.edu DPRINTF(RubyCacheTrace, "Cache flush complete\n"); 18610518Snilay@cs.wisc.edu 18710518Snilay@cs.wisc.edu // Restore eventq head 18810518Snilay@cs.wisc.edu eventq_head = eventq->replaceHead(eventq_head); 18910518Snilay@cs.wisc.edu // Restore curTick 19010518Snilay@cs.wisc.edu setCurTick(curtick_original); 19110518Snilay@cs.wisc.edu 19210706Spower.jg@gmail.com // Aggregate the trace entries together into a single array 19310706Spower.jg@gmail.com uint8_t *raw_data = new uint8_t[4096]; 19410919Sbrandon.potter@amd.com uint64 cache_trace_size = m_cache_recorder->aggregateRecords(&raw_data, 19510706Spower.jg@gmail.com 4096); 19610706Spower.jg@gmail.com string cache_trace_file = name() + ".cache.gz"; 19710706Spower.jg@gmail.com writeCompressedTrace(raw_data, cache_trace_file, cache_trace_size); 19810706Spower.jg@gmail.com 19910518Snilay@cs.wisc.edu SERIALIZE_SCALAR(cache_trace_file); 20010518Snilay@cs.wisc.edu SERIALIZE_SCALAR(cache_trace_size); 20110518Snilay@cs.wisc.edu 20210919Sbrandon.potter@amd.com m_cooldown_enabled = false; 20310919Sbrandon.potter@amd.com} 20410919Sbrandon.potter@amd.com 20510518Snilay@cs.wisc.eduvoid 20610518Snilay@cs.wisc.eduRubySystem::readCompressedTrace(string filename, uint8_t *&raw_data, 20710518Snilay@cs.wisc.edu uint64& uncompressed_trace_size) 20810519Snilay@cs.wisc.edu{ 20910518Snilay@cs.wisc.edu // Read the trace file 21010518Snilay@cs.wisc.edu gzFile compressedTrace; 21110518Snilay@cs.wisc.edu 21210518Snilay@cs.wisc.edu // trace file 21310518Snilay@cs.wisc.edu int fd = open(filename.c_str(), O_RDONLY); 21410518Snilay@cs.wisc.edu if (fd < 0) { 21510518Snilay@cs.wisc.edu perror("open"); 21610518Snilay@cs.wisc.edu fatal("Unable to open trace file %s", filename); 21710518Snilay@cs.wisc.edu } 21810518Snilay@cs.wisc.edu 2197039Snate@binkert.org compressedTrace = gzdopen(fd, "rb"); 2208615Snilay@cs.wisc.edu if (compressedTrace == NULL) { 2216285Snate@binkert.org fatal("Insufficient memory to allocate compression state for %s\n", 2227544SBrad.Beckmann@amd.com filename); 2237544SBrad.Beckmann@amd.com } 2247544SBrad.Beckmann@amd.com 2257544SBrad.Beckmann@amd.com raw_data = new uint8_t[uncompressed_trace_size]; 22611025Snilay@cs.wisc.edu if (gzread(compressedTrace, raw_data, uncompressed_trace_size) < 22710562Sandreas.hansson@arm.com uncompressed_trace_size) { 2288615Snilay@cs.wisc.edu fatal("Unable to read complete trace from file %s\n", filename); 2298615Snilay@cs.wisc.edu } 2306285Snate@binkert.org 2317039Snate@binkert.org if (gzclose(compressedTrace)) { 2327039Snate@binkert.org fatal("Failed to close cache trace file '%s'\n", filename); 2336285Snate@binkert.org } 2347039Snate@binkert.org} 2357039Snate@binkert.org 2367039Snate@binkert.orgvoid 2377039Snate@binkert.orgRubySystem::unserialize(CheckpointIn &cp) 2387039Snate@binkert.org{ 2397039Snate@binkert.org uint8_t *uncompressed_trace = NULL; 2408615Snilay@cs.wisc.edu 2416285Snate@binkert.org // This value should be set to the checkpoint-system's block-size. 24210472Sandreas.hansson@arm.com // Optional, as checkpoints without it can be run if the 24310472Sandreas.hansson@arm.com // checkpoint-system's block-size == current block-size. 24411025Snilay@cs.wisc.edu uint64 block_size_bytes = getBlockSizeBytes(); 24511025Snilay@cs.wisc.edu UNSERIALIZE_OPT_SCALAR(block_size_bytes); 2467453Snate@binkert.org 2477039Snate@binkert.org string cache_trace_file; 2486888SBrad.Beckmann@amd.com uint64 cache_trace_size = 0; 2497453Snate@binkert.org 2507039Snate@binkert.org UNSERIALIZE_SCALAR(cache_trace_file); 2516888SBrad.Beckmann@amd.com UNSERIALIZE_SCALAR(cache_trace_size); 2527915SBrad.Beckmann@amd.com cache_trace_file = cp.cptDir + "/" + cache_trace_file; 2537915SBrad.Beckmann@amd.com 2547915SBrad.Beckmann@amd.com readCompressedTrace(cache_trace_file, uncompressed_trace, 2557915SBrad.Beckmann@amd.com cache_trace_size); 2567039Snate@binkert.org m_warmup_enabled = true; 2576888SBrad.Beckmann@amd.com m_systems_to_warmup++; 2587039Snate@binkert.org 2597039Snate@binkert.org vector<Sequencer*> sequencer_map; 2607453Snate@binkert.org Sequencer* t = NULL; 2616285Snate@binkert.org for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 2627039Snate@binkert.org sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getSequencer()); 2636285Snate@binkert.org if (t == NULL) t = sequencer_map[cntrl]; 2646285Snate@binkert.org } 2657039Snate@binkert.org 2667039Snate@binkert.org assert(t != NULL); 2676285Snate@binkert.org 26810231Ssteve.reinhardt@amd.com for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 2697039Snate@binkert.org if (sequencer_map[cntrl] == NULL) { 2707039Snate@binkert.org sequencer_map[cntrl] = t; 2718162SBrad.Beckmann@amd.com } 2728162SBrad.Beckmann@amd.com } 2738162SBrad.Beckmann@amd.com 2748162SBrad.Beckmann@amd.com m_cache_recorder = new CacheRecorder(uncompressed_trace, cache_trace_size, 2758162SBrad.Beckmann@amd.com sequencer_map, block_size_bytes); 2768162SBrad.Beckmann@amd.com} 2777039Snate@binkert.org 2787039Snate@binkert.orgvoid 2797039Snate@binkert.orgRubySystem::startup() 2806285Snate@binkert.org{ 28110472Sandreas.hansson@arm.com 28210472Sandreas.hansson@arm.com // Ruby restores state from a checkpoint by resetting the clock to 0 and 28311025Snilay@cs.wisc.edu // playing the requests that can possibly re-generate the cache state. 28411025Snilay@cs.wisc.edu // The clock value is set to the actual checkpointed value once all the 2856888SBrad.Beckmann@amd.com // requests have been executed. 28611025Snilay@cs.wisc.edu // 28711025Snilay@cs.wisc.edu // This way of restoring state is pretty finicky. For example, if a 2886888SBrad.Beckmann@amd.com // Ruby component reads time before the state has been restored, it would 2897453Snate@binkert.org // cache this value and hence its clock would not be reset to 0, when 2907039Snate@binkert.org // Ruby resets the global clock. This can potentially result in a 2916888SBrad.Beckmann@amd.com // deadlock. 2927453Snate@binkert.org // 2937039Snate@binkert.org // The solution is that no Ruby component should read time before the 2947039Snate@binkert.org // simulation starts. And then one also needs to hope that the time 2957039Snate@binkert.org // Ruby finishes restoring the state is less than the time when the 2967039Snate@binkert.org // state was checkpointed. 2976888SBrad.Beckmann@amd.com 2987039Snate@binkert.org if (m_warmup_enabled) { 2997453Snate@binkert.org // save the current tick value 3007039Snate@binkert.org Tick curtick_original = curTick(); 3017453Snate@binkert.org // save the event queue head 3027039Snate@binkert.org Event* eventq_head = eventq->replaceHead(NULL); 3036888SBrad.Beckmann@amd.com // set curTick to 0 and reset Ruby System's clock 3047039Snate@binkert.org setCurTick(0); 3057039Snate@binkert.org resetClock(); 3067453Snate@binkert.org 30710917Sbrandon.potter@amd.com // Schedule an event to start cache warmup 3088160SBrad.Beckmann@amd.com enqueueRubyEvent(curTick()); 3098160SBrad.Beckmann@amd.com simulate(); 3108160SBrad.Beckmann@amd.com 3116285Snate@binkert.org delete m_cache_recorder; 3126285Snate@binkert.org m_cache_recorder = NULL; 3137039Snate@binkert.org m_systems_to_warmup--; 3147039Snate@binkert.org if (m_systems_to_warmup == 0) { 3156285Snate@binkert.org m_warmup_enabled = false; 31610231Ssteve.reinhardt@amd.com } 3177039Snate@binkert.org 3187039Snate@binkert.org // Restore eventq head 3197039Snate@binkert.org eventq_head = eventq->replaceHead(eventq_head); 3207039Snate@binkert.org // Restore curTick and Ruby System's clock 32110231Ssteve.reinhardt@amd.com setCurTick(curtick_original); 3227915SBrad.Beckmann@amd.com resetClock(); 3237915SBrad.Beckmann@amd.com } 3247915SBrad.Beckmann@amd.com 3257915SBrad.Beckmann@amd.com resetStats(); 3267039Snate@binkert.org} 3276285Snate@binkert.org 3286285Snate@binkert.orgvoid 3297039Snate@binkert.orgRubySystem::RubyEvent::process() 3307039Snate@binkert.org{ 3316285Snate@binkert.org if (RubySystem::getWarmupEnabled()) { 3327039Snate@binkert.org ruby_system->m_cache_recorder->enqueueNextFetchRequest(); 3336285Snate@binkert.org } else if (RubySystem::getCooldownEnabled()) { 3346285Snate@binkert.org ruby_system->m_cache_recorder->enqueueNextFlushRequest(); 3357039Snate@binkert.org } 33610518Snilay@cs.wisc.edu} 33710518Snilay@cs.wisc.edu 3389104Shestness@cs.utexas.eduvoid 3399104Shestness@cs.utexas.eduRubySystem::resetStats() 3409104Shestness@cs.utexas.edu{ 3419104Shestness@cs.utexas.edu g_ruby_start = curCycle(); 3426876Ssteve.reinhardt@amd.com} 3436876Ssteve.reinhardt@amd.com 3446876Ssteve.reinhardt@amd.combool 3456876Ssteve.reinhardt@amd.comRubySystem::functionalRead(PacketPtr pkt) 3466876Ssteve.reinhardt@amd.com{ 347 Address address(pkt->getAddr()); 348 Address line_address(address); 349 line_address.makeLineAddress(); 350 351 AccessPermission access_perm = AccessPermission_NotPresent; 352 int num_controllers = m_abs_cntrl_vec.size(); 353 354 DPRINTF(RubySystem, "Functional Read request for %s\n",address); 355 356 unsigned int num_ro = 0; 357 unsigned int num_rw = 0; 358 unsigned int num_busy = 0; 359 unsigned int num_backing_store = 0; 360 unsigned int num_invalid = 0; 361 362 // In this loop we count the number of controllers that have the given 363 // address in read only, read write and busy states. 364 for (unsigned int i = 0; i < num_controllers; ++i) { 365 access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address); 366 if (access_perm == AccessPermission_Read_Only) 367 num_ro++; 368 else if (access_perm == AccessPermission_Read_Write) 369 num_rw++; 370 else if (access_perm == AccessPermission_Busy) 371 num_busy++; 372 else if (access_perm == AccessPermission_Backing_Store) 373 // See RubySlicc_Exports.sm for details, but Backing_Store is meant 374 // to represent blocks in memory *for Broadcast/Snooping protocols*, 375 // where memory has no idea whether it has an exclusive copy of data 376 // or not. 377 num_backing_store++; 378 else if (access_perm == AccessPermission_Invalid || 379 access_perm == AccessPermission_NotPresent) 380 num_invalid++; 381 } 382 assert(num_rw <= 1); 383 384 // This if case is meant to capture what happens in a Broadcast/Snoop 385 // protocol where the block does not exist in the cache hierarchy. You 386 // only want to read from the Backing_Store memory if there is no copy in 387 // the cache hierarchy, otherwise you want to try to read the RO or RW 388 // copies existing in the cache hierarchy (covered by the else statement). 389 // The reason is because the Backing_Store memory could easily be stale, if 390 // there are copies floating around the cache hierarchy, so you want to read 391 // it only if it's not in the cache hierarchy at all. 392 if (num_invalid == (num_controllers - 1) && num_backing_store == 1) { 393 DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n"); 394 for (unsigned int i = 0; i < num_controllers; ++i) { 395 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 396 if (access_perm == AccessPermission_Backing_Store) { 397 m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); 398 return true; 399 } 400 } 401 } else if (num_ro > 0 || num_rw == 1) { 402 // In Broadcast/Snoop protocols, this covers if you know the block 403 // exists somewhere in the caching hierarchy, then you want to read any 404 // valid RO or RW block. In directory protocols, same thing, you want 405 // to read any valid readable copy of the block. 406 DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n", 407 num_busy, num_ro, num_rw); 408 // In this loop, we try to figure which controller has a read only or 409 // a read write copy of the given address. Any valid copy would suffice 410 // for a functional read. 411 for (unsigned int i = 0;i < num_controllers;++i) { 412 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 413 if (access_perm == AccessPermission_Read_Only || 414 access_perm == AccessPermission_Read_Write) { 415 m_abs_cntrl_vec[i]->functionalRead(line_address, pkt); 416 return true; 417 } 418 } 419 } 420 421 return false; 422} 423 424// The function searches through all the buffers that exist in different 425// cache, directory and memory controllers, and in the network components 426// and writes the data portion of those that hold the address specified 427// in the packet. 428bool 429RubySystem::functionalWrite(PacketPtr pkt) 430{ 431 Address addr(pkt->getAddr()); 432 Address line_addr = line_address(addr); 433 AccessPermission access_perm = AccessPermission_NotPresent; 434 int num_controllers = m_abs_cntrl_vec.size(); 435 436 DPRINTF(RubySystem, "Functional Write request for %s\n",addr); 437 438 uint32_t M5_VAR_USED num_functional_writes = 0; 439 440 for (unsigned int i = 0; i < num_controllers;++i) { 441 num_functional_writes += 442 m_abs_cntrl_vec[i]->functionalWriteBuffers(pkt); 443 444 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr); 445 if (access_perm != AccessPermission_Invalid && 446 access_perm != AccessPermission_NotPresent) { 447 num_functional_writes += 448 m_abs_cntrl_vec[i]->functionalWrite(line_addr, pkt); 449 } 450 } 451 452 num_functional_writes += m_network->functionalWrite(pkt); 453 DPRINTF(RubySystem, "Messages written = %u\n", num_functional_writes); 454 455 return true; 456} 457 458#ifdef CHECK_COHERENCE 459// This code will check for cases if the given cache block is exclusive in 460// one node and shared in another-- a coherence violation 461// 462// To use, the SLICC specification must call sequencer.checkCoherence(address) 463// when the controller changes to a state with new permissions. Do this 464// in setState. The SLICC spec must also define methods "isBlockShared" 465// and "isBlockExclusive" that are specific to that protocol 466// 467void 468RubySystem::checkGlobalCoherenceInvariant(const Address& addr) 469{ 470#if 0 471 NodeID exclusive = -1; 472 bool sharedDetected = false; 473 NodeID lastShared = -1; 474 475 for (int i = 0; i < m_chip_vector.size(); i++) { 476 if (m_chip_vector[i]->isBlockExclusive(addr)) { 477 if (exclusive != -1) { 478 // coherence violation 479 WARN_EXPR(exclusive); 480 WARN_EXPR(m_chip_vector[i]->getID()); 481 WARN_EXPR(addr); 482 WARN_EXPR(getTime()); 483 ERROR_MSG("Coherence Violation Detected -- 2 exclusive chips"); 484 } else if (sharedDetected) { 485 WARN_EXPR(lastShared); 486 WARN_EXPR(m_chip_vector[i]->getID()); 487 WARN_EXPR(addr); 488 WARN_EXPR(getTime()); 489 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); 490 } else { 491 exclusive = m_chip_vector[i]->getID(); 492 } 493 } else if (m_chip_vector[i]->isBlockShared(addr)) { 494 sharedDetected = true; 495 lastShared = m_chip_vector[i]->getID(); 496 497 if (exclusive != -1) { 498 WARN_EXPR(lastShared); 499 WARN_EXPR(exclusive); 500 WARN_EXPR(addr); 501 WARN_EXPR(getTime()); 502 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); 503 } 504 } 505 } 506#endif 507} 508#endif 509 510RubySystem * 511RubySystemParams::create() 512{ 513 return new RubySystem(this); 514} 515