RubySystem.cc revision 9300
12623SN/A/* 211147Smitch.hayenga@arm.com * Copyright (c) 1999-2011 Mark D. Hill and David A. Wood 39442SAndreas.Sandberg@ARM.com * All rights reserved. 49442SAndreas.Sandberg@ARM.com * 59442SAndreas.Sandberg@ARM.com * Redistribution and use in source and binary forms, with or without 69442SAndreas.Sandberg@ARM.com * modification, are permitted provided that the following conditions are 79442SAndreas.Sandberg@ARM.com * met: redistributions of source code must retain the above copyright 89442SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer; 99442SAndreas.Sandberg@ARM.com * redistributions in binary form must reproduce the above copyright 109442SAndreas.Sandberg@ARM.com * notice, this list of conditions and the following disclaimer in the 119442SAndreas.Sandberg@ARM.com * documentation and/or other materials provided with the distribution; 129442SAndreas.Sandberg@ARM.com * neither the name of the copyright holders nor the names of its 139442SAndreas.Sandberg@ARM.com * contributors may be used to endorse or promote products derived from 142623SN/A * this software without specific prior written permission. 152623SN/A * 162623SN/A * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 172623SN/A * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 182623SN/A * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 192623SN/A * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 202623SN/A * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 212623SN/A * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 222623SN/A * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 232623SN/A * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 242623SN/A * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 252623SN/A * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 262623SN/A * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 272623SN/A */ 282623SN/A 292623SN/A#include <fcntl.h> 302623SN/A#include <zlib.h> 312623SN/A 322623SN/A#include <cstdio> 332623SN/A 342623SN/A#include "base/intmath.hh" 352623SN/A#include "base/output.hh" 362623SN/A#include "debug/RubyCacheTrace.hh" 372623SN/A#include "debug/RubySystem.hh" 382623SN/A#include "mem/ruby/common/Address.hh" 392665Ssaidi@eecs.umich.edu#include "mem/ruby/network/Network.hh" 402665Ssaidi@eecs.umich.edu#include "mem/ruby/profiler/Profiler.hh" 412623SN/A#include "mem/ruby/system/System.hh" 422623SN/A#include "sim/eventq.hh" 432623SN/A#include "sim/simulate.hh" 442623SN/A 452623SN/Ausing namespace std; 462623SN/A 4711147Smitch.hayenga@arm.comint RubySystem::m_random_seed; 486973Stjones1@inf.ed.ac.ukbool RubySystem::m_randomization; 495529Snate@binkert.orgint RubySystem::m_block_size_bytes; 505529Snate@binkert.orgint RubySystem::m_block_size_bits; 512623SN/Auint64 RubySystem::m_memory_size_bytes; 522623SN/Aint RubySystem::m_memory_size_bits; 532623SN/A 542623SN/ARubySystem::RubySystem(const Params *p) 555529Snate@binkert.org : ClockedObject(p) 562623SN/A{ 572623SN/A if (g_system_ptr != NULL) 582623SN/A fatal("Only one RubySystem object currently allowed.\n"); 592623SN/A 602623SN/A m_random_seed = p->random_seed; 612623SN/A srandom(m_random_seed); 625728Sgblack@eecs.umich.edu m_randomization = p->randomization; 635728Sgblack@eecs.umich.edu 645728Sgblack@eecs.umich.edu m_block_size_bytes = p->block_size_bytes; 655728Sgblack@eecs.umich.edu assert(isPowerOf2(m_block_size_bytes)); 665728Sgblack@eecs.umich.edu m_block_size_bits = floorLog2(m_block_size_bytes); 675728Sgblack@eecs.umich.edu 685728Sgblack@eecs.umich.edu m_memory_size_bytes = p->mem_size; 695728Sgblack@eecs.umich.edu if (m_memory_size_bytes == 0) { 705728Sgblack@eecs.umich.edu m_memory_size_bits = 0; 715728Sgblack@eecs.umich.edu } else { 725728Sgblack@eecs.umich.edu m_memory_size_bits = floorLog2(m_memory_size_bytes); 735728Sgblack@eecs.umich.edu } 745728Sgblack@eecs.umich.edu 755728Sgblack@eecs.umich.edu g_system_ptr = this; 765728Sgblack@eecs.umich.edu if (p->no_mem_vec) { 775728Sgblack@eecs.umich.edu m_mem_vec_ptr = NULL; 785728Sgblack@eecs.umich.edu } else { 795728Sgblack@eecs.umich.edu m_mem_vec_ptr = new MemoryVector; 805728Sgblack@eecs.umich.edu m_mem_vec_ptr->resize(m_memory_size_bytes); 815728Sgblack@eecs.umich.edu } 825728Sgblack@eecs.umich.edu 835728Sgblack@eecs.umich.edu // Print ruby configuration and stats at exit 845728Sgblack@eecs.umich.edu registerExitCallback(new RubyExitCallback(p->stats_filename, this)); 855728Sgblack@eecs.umich.edu 865728Sgblack@eecs.umich.edu m_warmup_enabled = false; 875728Sgblack@eecs.umich.edu m_cooldown_enabled = false; 885728Sgblack@eecs.umich.edu} 895728Sgblack@eecs.umich.edu 905728Sgblack@eecs.umich.eduvoid 915728Sgblack@eecs.umich.eduRubySystem::init() 925728Sgblack@eecs.umich.edu{ 935728Sgblack@eecs.umich.edu m_profiler_ptr->clearStats(); 945728Sgblack@eecs.umich.edu} 955728Sgblack@eecs.umich.edu 965728Sgblack@eecs.umich.eduvoid 975728Sgblack@eecs.umich.eduRubySystem::registerNetwork(Network* network_ptr) 985728Sgblack@eecs.umich.edu{ 995728Sgblack@eecs.umich.edu m_network_ptr = network_ptr; 1005728Sgblack@eecs.umich.edu} 1015728Sgblack@eecs.umich.edu 1025728Sgblack@eecs.umich.eduvoid 1035728Sgblack@eecs.umich.eduRubySystem::registerProfiler(Profiler* profiler_ptr) 1045728Sgblack@eecs.umich.edu{ 1055728Sgblack@eecs.umich.edu m_profiler_ptr = profiler_ptr; 1065728Sgblack@eecs.umich.edu} 1075728Sgblack@eecs.umich.edu 1085728Sgblack@eecs.umich.eduvoid 1095894Sgblack@eecs.umich.eduRubySystem::registerAbstractController(AbstractController* cntrl) 1105894Sgblack@eecs.umich.edu{ 1115894Sgblack@eecs.umich.edu m_abs_cntrl_vec.push_back(cntrl); 1125894Sgblack@eecs.umich.edu} 1135894Sgblack@eecs.umich.edu 1145894Sgblack@eecs.umich.eduvoid 1156023Snate@binkert.orgRubySystem::registerSparseMemory(SparseMemory* s) 1166023Snate@binkert.org{ 1175894Sgblack@eecs.umich.edu m_sparse_memory_vector.push_back(s); 1185894Sgblack@eecs.umich.edu} 1196023Snate@binkert.org 1207944SGiacomo.Gabrielli@arm.comvoid 1217945SAli.Saidi@ARM.comRubySystem::registerMemController(MemoryControl *mc) { 1229342SAndreas.Sandberg@arm.com m_memory_controller_vec.push_back(mc); 1237945SAli.Saidi@ARM.com} 1247945SAli.Saidi@ARM.com 1257944SGiacomo.Gabrielli@arm.comRubySystem::~RubySystem() 1267944SGiacomo.Gabrielli@arm.com{ 12710379Sandreas.hansson@arm.com delete m_network_ptr; 1286023Snate@binkert.org delete m_profiler_ptr; 1295894Sgblack@eecs.umich.edu if (m_mem_vec_ptr) 1305894Sgblack@eecs.umich.edu delete m_mem_vec_ptr; 1315894Sgblack@eecs.umich.edu} 1325894Sgblack@eecs.umich.edu 1335894Sgblack@eecs.umich.eduvoid 1345894Sgblack@eecs.umich.eduRubySystem::printStats(ostream& out) 13511148Smitch.hayenga@arm.com{ 1366973Stjones1@inf.ed.ac.uk const time_t T = time(NULL); 1376973Stjones1@inf.ed.ac.uk tm *localTime = localtime(&T); 1386973Stjones1@inf.ed.ac.uk char buf[100]; 1395894Sgblack@eecs.umich.edu strftime(buf, 100, "%b/%d/%Y %H:%M:%S", localTime); 14010379Sandreas.hansson@arm.com 1415894Sgblack@eecs.umich.edu out << "Real time: " << buf << endl; 14210653Sandreas.hansson@arm.com 1435894Sgblack@eecs.umich.edu m_profiler_ptr->printStats(out); 1445894Sgblack@eecs.umich.edu m_network_ptr->printStats(out); 1455894Sgblack@eecs.umich.edu} 1465744Sgblack@eecs.umich.edu 1475728Sgblack@eecs.umich.eduvoid 1485728Sgblack@eecs.umich.eduRubySystem::writeCompressedTrace(uint8_t *raw_data, string filename, 1495728Sgblack@eecs.umich.edu uint64 uncompressed_trace_size) 1505728Sgblack@eecs.umich.edu{ 1518707Sandreas.hansson@arm.com // Create the checkpoint file for the memory 1528707Sandreas.hansson@arm.com string thefile = Checkpoint::dir() + "/" + filename.c_str(); 1538707Sandreas.hansson@arm.com 1548707Sandreas.hansson@arm.com int fd = creat(thefile.c_str(), 0664); 1558707Sandreas.hansson@arm.com if (fd < 0) { 1568707Sandreas.hansson@arm.com perror("creat"); 1579608Sandreas.hansson@arm.com fatal("Can't open memory trace file '%s'\n", filename); 1582623SN/A } 1592623SN/A 1602623SN/A gzFile compressedMemory = gzdopen(fd, "wb"); 1618707Sandreas.hansson@arm.com if (compressedMemory == NULL) 16210713Sandreas.hansson@arm.com fatal("Insufficient memory to allocate compression state for %s\n", 1632623SN/A filename); 1642623SN/A 1652623SN/A if (gzwrite(compressedMemory, raw_data, uncompressed_trace_size) != 1662623SN/A uncompressed_trace_size) { 1678948Sandreas.hansson@arm.com fatal("Write failed on memory trace file '%s'\n", filename); 1688948Sandreas.hansson@arm.com } 1698948Sandreas.hansson@arm.com 17010030SAli.Saidi@ARM.com if (gzclose(compressedMemory)) { 1718948Sandreas.hansson@arm.com fatal("Close failed on memory trace file '%s'\n", filename); 1728707Sandreas.hansson@arm.com } 1732948Ssaidi@eecs.umich.edu delete raw_data; 1742948Ssaidi@eecs.umich.edu} 1752948Ssaidi@eecs.umich.edu 1763349Sbinkertn@umich.eduvoid 1772948Ssaidi@eecs.umich.eduRubySystem::serialize(std::ostream &os) 1782948Ssaidi@eecs.umich.edu{ 1798707Sandreas.hansson@arm.com m_cooldown_enabled = true; 1805336Shines@cs.fsu.edu 1813349Sbinkertn@umich.edu vector<Sequencer*> sequencer_map; 1822948Ssaidi@eecs.umich.edu Sequencer* sequencer_ptr = NULL; 1832948Ssaidi@eecs.umich.edu int cntrl_id = -1; 18410713Sandreas.hansson@arm.com 1852623SN/A 1862623SN/A for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 1878707Sandreas.hansson@arm.com sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getSequencer()); 1882623SN/A if (sequencer_ptr == NULL) { 1892623SN/A sequencer_ptr = sequencer_map[cntrl]; 1902623SN/A cntrl_id = cntrl; 1918707Sandreas.hansson@arm.com } 1929095Sandreas.hansson@arm.com } 1938707Sandreas.hansson@arm.com 1942623SN/A assert(sequencer_ptr != NULL); 1952623SN/A 1962623SN/A for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 1972623SN/A if (sequencer_map[cntrl] == NULL) { 1988975Sandreas.hansson@arm.com sequencer_map[cntrl] = sequencer_ptr; 1992623SN/A } 20010713Sandreas.hansson@arm.com } 2012948Ssaidi@eecs.umich.edu 2022948Ssaidi@eecs.umich.edu DPRINTF(RubyCacheTrace, "Recording Cache Trace\n"); 2032948Ssaidi@eecs.umich.edu // Create the CacheRecorder and record the cache trace 2042948Ssaidi@eecs.umich.edu m_cache_recorder = new CacheRecorder(NULL, 0, sequencer_map); 2052948Ssaidi@eecs.umich.edu 2062948Ssaidi@eecs.umich.edu for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 2072948Ssaidi@eecs.umich.edu m_abs_cntrl_vec[cntrl]->recordCacheTrace(cntrl, m_cache_recorder); 2085336Shines@cs.fsu.edu } 2092948Ssaidi@eecs.umich.edu 2102948Ssaidi@eecs.umich.edu DPRINTF(RubyCacheTrace, "Cache Trace Complete\n"); 2112948Ssaidi@eecs.umich.edu // save the current tick value 2122948Ssaidi@eecs.umich.edu Tick curtick_original = curTick(); 2132623SN/A // save the event queue head 2142623SN/A Event* eventq_head = eventq->replaceHead(NULL); 2158707Sandreas.hansson@arm.com DPRINTF(RubyCacheTrace, "Recording current tick %ld and event queue\n", 2162623SN/A curtick_original); 2172623SN/A 2182623SN/A // Schedule an event to start cache cooldown 2198707Sandreas.hansson@arm.com DPRINTF(RubyCacheTrace, "Starting cache flush\n"); 2209095Sandreas.hansson@arm.com enqueueRubyEvent(curTick()); 2219095Sandreas.hansson@arm.com simulate(); 22210030SAli.Saidi@ARM.com DPRINTF(RubyCacheTrace, "Cache flush complete\n"); 22310030SAli.Saidi@ARM.com 22410030SAli.Saidi@ARM.com // Restore eventq head 2252623SN/A eventq_head = eventq->replaceHead(eventq_head); 22610030SAli.Saidi@ARM.com // Restore curTick 2272623SN/A curTick(curtick_original); 2282623SN/A 22910030SAli.Saidi@ARM.com uint8_t *raw_data = NULL; 23010030SAli.Saidi@ARM.com 23110030SAli.Saidi@ARM.com if (m_mem_vec_ptr != NULL) { 23210030SAli.Saidi@ARM.com uint64 memory_trace_size = m_mem_vec_ptr->collatePages(raw_data); 23310529Smorr@cs.wisc.edu 23410030SAli.Saidi@ARM.com string memory_trace_file = name() + ".memory.gz"; 2358975Sandreas.hansson@arm.com writeCompressedTrace(raw_data, memory_trace_file, 2362623SN/A memory_trace_size); 23710713Sandreas.hansson@arm.com 2382948Ssaidi@eecs.umich.edu SERIALIZE_SCALAR(memory_trace_file); 23910529Smorr@cs.wisc.edu SERIALIZE_SCALAR(memory_trace_size); 24010529Smorr@cs.wisc.edu 24110529Smorr@cs.wisc.edu } else { 24210529Smorr@cs.wisc.edu for (int i = 0; i < m_sparse_memory_vector.size(); ++i) { 2432948Ssaidi@eecs.umich.edu m_sparse_memory_vector[i]->recordBlocks(cntrl_id, 2442948Ssaidi@eecs.umich.edu m_cache_recorder); 2452948Ssaidi@eecs.umich.edu } 2462948Ssaidi@eecs.umich.edu } 2472948Ssaidi@eecs.umich.edu 2485336Shines@cs.fsu.edu // Aggergate the trace entries together into a single array 2492948Ssaidi@eecs.umich.edu raw_data = new uint8_t[4096]; 2502948Ssaidi@eecs.umich.edu uint64 cache_trace_size = m_cache_recorder->aggregateRecords(&raw_data, 2512948Ssaidi@eecs.umich.edu 4096); 2522948Ssaidi@eecs.umich.edu string cache_trace_file = name() + ".cache.gz"; 2532623SN/A writeCompressedTrace(raw_data, cache_trace_file, cache_trace_size); 2542623SN/A 25510464SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(cache_trace_file); 25610464SAndreas.Sandberg@ARM.com SERIALIZE_SCALAR(cache_trace_size); 2572623SN/A 2582623SN/A m_cooldown_enabled = false; 2592623SN/A} 2603349Sbinkertn@umich.edu 2613349Sbinkertn@umich.eduvoid 2622623SN/ARubySystem::readCompressedTrace(string filename, uint8_t *&raw_data, 26310464SAndreas.Sandberg@ARM.com uint64& uncompressed_trace_size) 2643170Sstever@eecs.umich.edu{ 2658850Sandreas.hansson@arm.com // Read the trace file 2668850Sandreas.hansson@arm.com gzFile compressedTrace; 2678850Sandreas.hansson@arm.com 2689608Sandreas.hansson@arm.com // trace file 2698850Sandreas.hansson@arm.com int fd = open(filename.c_str(), O_RDONLY); 2708850Sandreas.hansson@arm.com if (fd < 0) { 2719608Sandreas.hansson@arm.com perror("open"); 2728850Sandreas.hansson@arm.com fatal("Unable to open trace file %s", filename); 2732623SN/A } 2742623SN/A 27511168Sandreas.hansson@arm.com compressedTrace = gzdopen(fd, "rb"); 27611168Sandreas.hansson@arm.com if (compressedTrace == NULL) { 2772798Sktlim@umich.edu fatal("Insufficient memory to allocate compression state for %s\n", 2782798Sktlim@umich.edu filename); 2792623SN/A } 2802623SN/A 2819523SAndreas.Sandberg@ARM.com raw_data = new uint8_t[uncompressed_trace_size]; 2829523SAndreas.Sandberg@ARM.com if (gzread(compressedTrace, raw_data, uncompressed_trace_size) < 28310407Smitch.hayenga@arm.com uncompressed_trace_size) { 2848737Skoansin.tan@gmail.com fatal("Unable to read complete trace from file %s\n", filename); 2852623SN/A } 2868444Sgblack@eecs.umich.edu 2877520Sgblack@eecs.umich.edu if (gzclose(compressedTrace)) { 2888444Sgblack@eecs.umich.edu fatal("Failed to close cache trace file '%s'\n", filename); 2898444Sgblack@eecs.umich.edu } 2907520Sgblack@eecs.umich.edu} 2912623SN/A 29210379Sandreas.hansson@arm.comvoid 2933349Sbinkertn@umich.eduRubySystem::unserialize(Checkpoint *cp, const string §ion) 2945894Sgblack@eecs.umich.edu{ 29510379Sandreas.hansson@arm.com // 2964471Sstever@eecs.umich.edu // The main purpose for clearing stats in the unserialize process is so 2979258SAli.Saidi@ARM.com // that the profiler can correctly set its start time to the unserialized 2989258SAli.Saidi@ARM.com // value of curTick() 2999258SAli.Saidi@ARM.com // 3009258SAli.Saidi@ARM.com clearStats(); 3019258SAli.Saidi@ARM.com uint8_t *uncompressed_trace = NULL; 3029258SAli.Saidi@ARM.com 3039258SAli.Saidi@ARM.com if (m_mem_vec_ptr != NULL) { 3049258SAli.Saidi@ARM.com string memory_trace_file; 3055315Sstever@gmail.com uint64 memory_trace_size = 0; 3065315Sstever@gmail.com 3075315Sstever@gmail.com UNSERIALIZE_SCALAR(memory_trace_file); 3085315Sstever@gmail.com UNSERIALIZE_SCALAR(memory_trace_size); 3095315Sstever@gmail.com memory_trace_file = cp->cptDir + "/" + memory_trace_file; 3105315Sstever@gmail.com 3116973Stjones1@inf.ed.ac.uk readCompressedTrace(memory_trace_file, uncompressed_trace, 3126973Stjones1@inf.ed.ac.uk memory_trace_size); 3136973Stjones1@inf.ed.ac.uk m_mem_vec_ptr->populatePages(uncompressed_trace); 3146973Stjones1@inf.ed.ac.uk 3156973Stjones1@inf.ed.ac.uk delete uncompressed_trace; 3166973Stjones1@inf.ed.ac.uk uncompressed_trace = NULL; 3172798Sktlim@umich.edu } 3184471Sstever@eecs.umich.edu 3194471Sstever@eecs.umich.edu string cache_trace_file; 3205710Scws3k@cs.virginia.edu uint64 cache_trace_size = 0; 3214471Sstever@eecs.umich.edu 3225103Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(cache_trace_file); 3235103Ssaidi@eecs.umich.edu UNSERIALIZE_SCALAR(cache_trace_size); 3245103Ssaidi@eecs.umich.edu cache_trace_file = cp->cptDir + "/" + cache_trace_file; 3255103Ssaidi@eecs.umich.edu 3265103Ssaidi@eecs.umich.edu readCompressedTrace(cache_trace_file, uncompressed_trace, 3275336Shines@cs.fsu.edu cache_trace_size); 3285103Ssaidi@eecs.umich.edu m_warmup_enabled = true; 3295103Ssaidi@eecs.umich.edu 3309442SAndreas.Sandberg@ARM.com vector<Sequencer*> sequencer_map; 3319442SAndreas.Sandberg@ARM.com Sequencer* t = NULL; 3329442SAndreas.Sandberg@ARM.com for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 3339442SAndreas.Sandberg@ARM.com sequencer_map.push_back(m_abs_cntrl_vec[cntrl]->getSequencer()); 3349442SAndreas.Sandberg@ARM.com if (t == NULL) t = sequencer_map[cntrl]; 3359442SAndreas.Sandberg@ARM.com } 3369442SAndreas.Sandberg@ARM.com 3379442SAndreas.Sandberg@ARM.com assert(t != NULL); 3389442SAndreas.Sandberg@ARM.com 3399442SAndreas.Sandberg@ARM.com for (int cntrl = 0; cntrl < m_abs_cntrl_vec.size(); cntrl++) { 3409830Sandreas.hansson@arm.com if (sequencer_map[cntrl] == NULL) { 3419830Sandreas.hansson@arm.com sequencer_map[cntrl] = t; 3429840Sandreas.hansson@arm.com } 3439840Sandreas.hansson@arm.com } 3449442SAndreas.Sandberg@ARM.com 3459442SAndreas.Sandberg@ARM.com m_cache_recorder = new CacheRecorder(uncompressed_trace, cache_trace_size, 3469442SAndreas.Sandberg@ARM.com sequencer_map); 34711147Smitch.hayenga@arm.com} 34811147Smitch.hayenga@arm.com 34911147Smitch.hayenga@arm.comvoid 35011147Smitch.hayenga@arm.comRubySystem::startup() 35111147Smitch.hayenga@arm.com{ 3529442SAndreas.Sandberg@ARM.com if (m_warmup_enabled) { 3539442SAndreas.Sandberg@ARM.com // save the current tick value 3549442SAndreas.Sandberg@ARM.com Tick curtick_original = curTick(); 3559442SAndreas.Sandberg@ARM.com // save the event queue head 3569442SAndreas.Sandberg@ARM.com Event* eventq_head = eventq->replaceHead(NULL); 3579442SAndreas.Sandberg@ARM.com // set curTick to 0 and reset Ruby System's clock 3589442SAndreas.Sandberg@ARM.com curTick(0); 3599442SAndreas.Sandberg@ARM.com resetClock(); 3602623SN/A 3612623SN/A // Schedule an event to start cache warmup 3622623SN/A enqueueRubyEvent(curTick()); 363 simulate(); 364 365 delete m_cache_recorder; 366 m_cache_recorder = NULL; 367 m_warmup_enabled = false; 368 369 // reset DRAM so that it's not waiting for events on the old event 370 // queue 371 for (int i = 0; i < m_memory_controller_vec.size(); ++i) { 372 m_memory_controller_vec[i]->reset(); 373 } 374 375 // Restore eventq head 376 eventq_head = eventq->replaceHead(eventq_head); 377 // Restore curTick and Ruby System's clock 378 curTick(curtick_original); 379 resetClock(); 380 } 381} 382 383void 384RubySystem::RubyEvent::process() 385{ 386 if (ruby_system->m_warmup_enabled) { 387 ruby_system->m_cache_recorder->enqueueNextFetchRequest(); 388 } else if (ruby_system->m_cooldown_enabled) { 389 ruby_system->m_cache_recorder->enqueueNextFlushRequest(); 390 } 391} 392 393void 394RubySystem::clearStats() const 395{ 396 m_profiler_ptr->clearStats(); 397 m_network_ptr->clearStats(); 398} 399 400bool 401RubySystem::functionalRead(PacketPtr pkt) 402{ 403 Address address(pkt->getAddr()); 404 Address line_address(address); 405 line_address.makeLineAddress(); 406 407 AccessPermission access_perm = AccessPermission_NotPresent; 408 int num_controllers = m_abs_cntrl_vec.size(); 409 410 DPRINTF(RubySystem, "Functional Read request for %s\n",address); 411 412 unsigned int num_ro = 0; 413 unsigned int num_rw = 0; 414 unsigned int num_busy = 0; 415 unsigned int num_backing_store = 0; 416 unsigned int num_invalid = 0; 417 418 // In this loop we count the number of controllers that have the given 419 // address in read only, read write and busy states. 420 for (int i = 0; i < num_controllers; ++i) { 421 access_perm = m_abs_cntrl_vec[i]-> getAccessPermission(line_address); 422 if (access_perm == AccessPermission_Read_Only) 423 num_ro++; 424 else if (access_perm == AccessPermission_Read_Write) 425 num_rw++; 426 else if (access_perm == AccessPermission_Busy) 427 num_busy++; 428 else if (access_perm == AccessPermission_Backing_Store) 429 // See RubySlicc_Exports.sm for details, but Backing_Store is meant 430 // to represent blocks in memory *for Broadcast/Snooping protocols*, 431 // where memory has no idea whether it has an exclusive copy of data 432 // or not. 433 num_backing_store++; 434 else if (access_perm == AccessPermission_Invalid || 435 access_perm == AccessPermission_NotPresent) 436 num_invalid++; 437 } 438 assert(num_rw <= 1); 439 440 uint8_t *data = pkt->getPtr<uint8_t>(true); 441 unsigned int size_in_bytes = pkt->getSize(); 442 unsigned startByte = address.getAddress() - line_address.getAddress(); 443 444 // This if case is meant to capture what happens in a Broadcast/Snoop 445 // protocol where the block does not exist in the cache hierarchy. You 446 // only want to read from the Backing_Store memory if there is no copy in 447 // the cache hierarchy, otherwise you want to try to read the RO or RW 448 // copies existing in the cache hierarchy (covered by the else statement). 449 // The reason is because the Backing_Store memory could easily be stale, if 450 // there are copies floating around the cache hierarchy, so you want to read 451 // it only if it's not in the cache hierarchy at all. 452 if (num_invalid == (num_controllers - 1) && 453 num_backing_store == 1) { 454 DPRINTF(RubySystem, "only copy in Backing_Store memory, read from it\n"); 455 for (int i = 0; i < num_controllers; ++i) { 456 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 457 if (access_perm == AccessPermission_Backing_Store) { 458 DataBlock& block = m_abs_cntrl_vec[i]-> 459 getDataBlock(line_address); 460 461 DPRINTF(RubySystem, "reading from %s block %s\n", 462 m_abs_cntrl_vec[i]->name(), block); 463 for (unsigned i = 0; i < size_in_bytes; ++i) { 464 data[i] = block.getByte(i + startByte); 465 } 466 return true; 467 } 468 } 469 } else { 470 // In Broadcast/Snoop protocols, this covers if you know the block 471 // exists somewhere in the caching hierarchy, then you want to read any 472 // valid RO or RW block. In directory protocols, same thing, you want 473 // to read any valid readable copy of the block. 474 DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n", 475 num_busy, num_ro, num_rw); 476 // In this loop, we try to figure which controller has a read only or 477 // a read write copy of the given address. Any valid copy would suffice 478 // for a functional read. 479 for (int i = 0;i < num_controllers;++i) { 480 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_address); 481 if (access_perm == AccessPermission_Read_Only || 482 access_perm == AccessPermission_Read_Write) { 483 DataBlock& block = m_abs_cntrl_vec[i]-> 484 getDataBlock(line_address); 485 486 DPRINTF(RubySystem, "reading from %s block %s\n", 487 m_abs_cntrl_vec[i]->name(), block); 488 for (unsigned i = 0; i < size_in_bytes; ++i) { 489 data[i] = block.getByte(i + startByte); 490 } 491 return true; 492 } 493 } 494 } 495 return false; 496} 497 498bool 499RubySystem::functionalWrite(PacketPtr pkt) 500{ 501 Address addr(pkt->getAddr()); 502 Address line_addr = line_address(addr); 503 AccessPermission access_perm = AccessPermission_NotPresent; 504 int num_controllers = m_abs_cntrl_vec.size(); 505 506 DPRINTF(RubySystem, "Functional Write request for %s\n",addr); 507 508 unsigned int num_ro = 0; 509 unsigned int num_rw = 0; 510 unsigned int num_busy = 0; 511 unsigned int num_backing_store = 0; 512 unsigned int num_invalid = 0; 513 514 // In this loop we count the number of controllers that have the given 515 // address in read only, read write and busy states. 516 for (int i = 0;i < num_controllers;++i) { 517 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr); 518 if (access_perm == AccessPermission_Read_Only) 519 num_ro++; 520 else if (access_perm == AccessPermission_Read_Write) 521 num_rw++; 522 else if (access_perm == AccessPermission_Busy) 523 num_busy++; 524 else if (access_perm == AccessPermission_Backing_Store) 525 // See RubySlicc_Exports.sm for details, but Backing_Store is meant 526 // to represent blocks in memory *for Broadcast/Snooping protocols*, 527 // where memory has no idea whether it has an exclusive copy of data 528 // or not. 529 num_backing_store++; 530 else if (access_perm == AccessPermission_Invalid || 531 access_perm == AccessPermission_NotPresent) 532 num_invalid++; 533 } 534 535 // If the number of read write copies is more than 1, then there is bug in 536 // coherence protocol. Otherwise, if all copies are in stable states, i.e. 537 // num_busy == 0, we update all the copies. If there is at least one copy 538 // in busy state, then we check if there is read write copy. If yes, then 539 // also we let the access go through. Or, if there is no copy in the cache 540 // hierarchy at all, we still want to do the write to the memory 541 // (Backing_Store) instead of failing. 542 543 DPRINTF(RubySystem, "num_busy = %d, num_ro = %d, num_rw = %d\n", 544 num_busy, num_ro, num_rw); 545 assert(num_rw <= 1); 546 547 uint8_t *data = pkt->getPtr<uint8_t>(true); 548 unsigned int size_in_bytes = pkt->getSize(); 549 unsigned startByte = addr.getAddress() - line_addr.getAddress(); 550 551 if ((num_busy == 0 && num_ro > 0) || num_rw == 1 || 552 (num_invalid == (num_controllers - 1) && num_backing_store == 1)) { 553 for (int i = 0; i < num_controllers;++i) { 554 access_perm = m_abs_cntrl_vec[i]->getAccessPermission(line_addr); 555 if (access_perm == AccessPermission_Read_Only || 556 access_perm == AccessPermission_Read_Write|| 557 access_perm == AccessPermission_Maybe_Stale || 558 access_perm == AccessPermission_Backing_Store) { 559 560 DataBlock& block = m_abs_cntrl_vec[i]->getDataBlock(line_addr); 561 DPRINTF(RubySystem, "%s\n",block); 562 for (unsigned i = 0; i < size_in_bytes; ++i) { 563 block.setByte(i + startByte, data[i]); 564 } 565 DPRINTF(RubySystem, "%s\n",block); 566 } 567 } 568 return true; 569 } 570 return false; 571} 572 573#ifdef CHECK_COHERENCE 574// This code will check for cases if the given cache block is exclusive in 575// one node and shared in another-- a coherence violation 576// 577// To use, the SLICC specification must call sequencer.checkCoherence(address) 578// when the controller changes to a state with new permissions. Do this 579// in setState. The SLICC spec must also define methods "isBlockShared" 580// and "isBlockExclusive" that are specific to that protocol 581// 582void 583RubySystem::checkGlobalCoherenceInvariant(const Address& addr) 584{ 585#if 0 586 NodeID exclusive = -1; 587 bool sharedDetected = false; 588 NodeID lastShared = -1; 589 590 for (int i = 0; i < m_chip_vector.size(); i++) { 591 if (m_chip_vector[i]->isBlockExclusive(addr)) { 592 if (exclusive != -1) { 593 // coherence violation 594 WARN_EXPR(exclusive); 595 WARN_EXPR(m_chip_vector[i]->getID()); 596 WARN_EXPR(addr); 597 WARN_EXPR(getTime()); 598 ERROR_MSG("Coherence Violation Detected -- 2 exclusive chips"); 599 } else if (sharedDetected) { 600 WARN_EXPR(lastShared); 601 WARN_EXPR(m_chip_vector[i]->getID()); 602 WARN_EXPR(addr); 603 WARN_EXPR(getTime()); 604 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); 605 } else { 606 exclusive = m_chip_vector[i]->getID(); 607 } 608 } else if (m_chip_vector[i]->isBlockShared(addr)) { 609 sharedDetected = true; 610 lastShared = m_chip_vector[i]->getID(); 611 612 if (exclusive != -1) { 613 WARN_EXPR(lastShared); 614 WARN_EXPR(exclusive); 615 WARN_EXPR(addr); 616 WARN_EXPR(getTime()); 617 ERROR_MSG("Coherence Violation Detected -- exclusive chip with >=1 shared"); 618 } 619 } 620 } 621#endif 622} 623#endif 624 625RubySystem * 626RubySystemParams::create() 627{ 628 return new RubySystem(this); 629} 630 631/** 632 * virtual process function that is invoked when the callback 633 * queue is executed. 634 */ 635void 636RubyExitCallback::process() 637{ 638 std::ostream *os = simout.create(stats_filename); 639 ruby_system->printStats(*os); 640} 641