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 &section)
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