base.cc

来自「M5,一个功能强大的多处理器系统模拟器.很多针对处理器架构,性能的研究都使用它作」· CC 代码 · 共 455 行

CC
455
字号
/* * Copyright (c) 2002, 2003, 2004, 2005 * The Regents of The University of Michigan * All Rights Reserved * * This code is part of the M5 simulator. * * Permission is granted to use, copy, create derivative works and * redistribute this software and such derivative works for any * purpose, so long as the copyright notice above, this grant of * permission, and the disclaimer below appear in all copies made; and * so long as the name of The University of Michigan is not used in * any advertising or publicity pertaining to the use or distribution * of this software without specific, written prior authorization. * * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION FROM THE * UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY PURPOSE, AND * WITHOUT WARRANTY BY THE UNIVERSITY OF MICHIGAN OF ANY KIND, EITHER * EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION THE IMPLIED * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE. THE REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE * LIABLE FOR ANY DAMAGES, INCLUDING DIRECT, SPECIAL, INDIRECT, * INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM * ARISING OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF SUCH * DAMAGES. * * Authors: Steven K. Reinhardt *          Nathan L. Binkert */#include <iostream>#include <string>#include <sstream>#include "base/cprintf.hh"#include "base/loader/symtab.hh"#include "base/misc.hh"#include "base/output.hh"#include "cpu/base.hh"#include "cpu/cpuevent.hh"#include "cpu/thread_context.hh"#include "cpu/profile.hh"#include "sim/sim_exit.hh"#include "sim/process.hh"#include "sim/sim_events.hh"#include "sim/system.hh"#include "base/trace.hh"// Hack#include "sim/stat_control.hh"using namespace std;vector<BaseCPU *> BaseCPU::cpuList;// This variable reflects the max number of threads in any CPU.  Be// careful to only use it once all the CPUs that you care about have// been initializedint maxThreadsPerCPU = 1;CPUProgressEvent::CPUProgressEvent(EventQueue *q, Tick ival,                                   BaseCPU *_cpu)    : Event(q, Event::Progress_Event_Pri), interval(ival),      lastNumInst(0), cpu(_cpu){    if (interval)        schedule(curTick + interval);}voidCPUProgressEvent::process(){    Counter temp = cpu->totalInstructions();#ifndef NDEBUG    double ipc = double(temp - lastNumInst) / (interval / cpu->ticks(1));    DPRINTFN("%s progress event, instructions committed: %lli, IPC: %0.8d\n",             cpu->name(), temp - lastNumInst, ipc);    ipc = 0.0;#else    cprintf("%lli: %s progress event, instructions committed: %lli\n",            curTick, cpu->name(), temp - lastNumInst);#endif    lastNumInst = temp;    schedule(curTick + interval);}const char *CPUProgressEvent::description() const{    return "CPU Progress";}#if FULL_SYSTEMBaseCPU::BaseCPU(Params *p)    : MemObject(makeParams(p->name)), clock(p->clock), instCnt(0),      params(p), number_of_threads(p->numberOfThreads), system(p->system),      phase(p->phase)#elseBaseCPU::BaseCPU(Params *p)    : MemObject(makeParams(p->name)), clock(p->clock), params(p),      number_of_threads(p->numberOfThreads), system(p->system),      phase(p->phase)#endif{//    currentTick = curTick;    // add self to global list of CPUs    cpuList.push_back(this);    if (number_of_threads > maxThreadsPerCPU)        maxThreadsPerCPU = number_of_threads;    // allocate per-thread instruction-based event queues    comInstEventQueue = new EventQueue *[number_of_threads];    for (int i = 0; i < number_of_threads; ++i)        comInstEventQueue[i] = new EventQueue("instruction-based event queue");    //    // set up instruction-count-based termination events, if any    //    if (p->max_insts_any_thread != 0)        for (int i = 0; i < number_of_threads; ++i)            schedExitSimLoop("a thread reached the max instruction count",                             p->max_insts_any_thread, 0,                             comInstEventQueue[i]);    if (p->max_insts_all_threads != 0) {        // allocate & initialize shared downcounter: each event will        // decrement this when triggered; simulation will terminate        // when counter reaches 0        int *counter = new int;        *counter = number_of_threads;        for (int i = 0; i < number_of_threads; ++i)            new CountedExitEvent(comInstEventQueue[i],                "all threads reached the max instruction count",                p->max_insts_all_threads, *counter);    }    // allocate per-thread load-based event queues    comLoadEventQueue = new EventQueue *[number_of_threads];    for (int i = 0; i < number_of_threads; ++i)        comLoadEventQueue[i] = new EventQueue("load-based event queue");    //    // set up instruction-count-based termination events, if any    //    if (p->max_loads_any_thread != 0)        for (int i = 0; i < number_of_threads; ++i)            schedExitSimLoop("a thread reached the max load count",                             p->max_loads_any_thread, 0,                             comLoadEventQueue[i]);    if (p->max_loads_all_threads != 0) {        // allocate & initialize shared downcounter: each event will        // decrement this when triggered; simulation will terminate        // when counter reaches 0        int *counter = new int;        *counter = number_of_threads;        for (int i = 0; i < number_of_threads; ++i)            new CountedExitEvent(comLoadEventQueue[i],                "all threads reached the max load count",                p->max_loads_all_threads, *counter);    }    functionTracingEnabled = false;    if (p->functionTrace) {        functionTraceStream = simout.find(csprintf("ftrace.%s", name()));        currentFunctionStart = currentFunctionEnd = 0;        functionEntryTick = p->functionTraceStart;        if (p->functionTraceStart == 0) {            functionTracingEnabled = true;        } else {            new EventWrapper<BaseCPU, &BaseCPU::enableFunctionTrace>(this,                                                                     p->functionTraceStart,                                                                     true);        }    }#if FULL_SYSTEM    profileEvent = NULL;    if (params->profile)        profileEvent = new ProfileEvent(this, params->profile);#endif    tracer = params->tracer;}BaseCPU::Params::Params(){#if FULL_SYSTEM    profile = false;#endif    checker = NULL;    tracer = NULL;}voidBaseCPU::enableFunctionTrace(){    functionTracingEnabled = true;}BaseCPU::~BaseCPU(){}voidBaseCPU::init(){    if (!params->deferRegistration)        registerThreadContexts();}voidBaseCPU::startup(){#if FULL_SYSTEM    if (!params->deferRegistration && profileEvent)        profileEvent->schedule(curTick);#endif    if (params->progress_interval) {        new CPUProgressEvent(&mainEventQueue,                             ticks(params->progress_interval),                             this);    }}voidBaseCPU::regStats(){    using namespace Stats;    numCycles        .name(name() + ".numCycles")        .desc("number of cpu cycles simulated")        ;    int size = threadContexts.size();    if (size > 1) {        for (int i = 0; i < size; ++i) {            stringstream namestr;            ccprintf(namestr, "%s.ctx%d", name(), i);            threadContexts[i]->regStats(namestr.str());        }    } else if (size == 1)        threadContexts[0]->regStats(name());#if FULL_SYSTEM#endif}TickBaseCPU::nextCycle(){    Tick next_tick = curTick - phase + clock - 1;    next_tick -= (next_tick % clock);    next_tick += phase;    return next_tick;}TickBaseCPU::nextCycle(Tick begin_tick){    Tick next_tick = begin_tick;    if (next_tick % clock != 0)        next_tick = next_tick - (next_tick % clock) + clock;    next_tick += phase;    assert(next_tick >= curTick);    return next_tick;}voidBaseCPU::registerThreadContexts(){    for (int i = 0; i < threadContexts.size(); ++i) {        ThreadContext *tc = threadContexts[i];#if FULL_SYSTEM        int id = params->cpu_id;        if (id != -1)            id += i;        tc->setCpuId(system->registerThreadContext(tc, id));#else        tc->setCpuId(tc->getProcessPtr()->registerThreadContext(tc));#endif    }}intBaseCPU::findContext(ThreadContext *tc){    for (int i = 0; i < threadContexts.size(); ++i) {        if (tc == threadContexts[i])            return i;    }    return 0;}voidBaseCPU::switchOut(){//    panic("This CPU doesn't support sampling!");#if FULL_SYSTEM    if (profileEvent && profileEvent->scheduled())        profileEvent->deschedule();#endif}voidBaseCPU::takeOverFrom(BaseCPU *oldCPU, Port *ic, Port *dc){    assert(threadContexts.size() == oldCPU->threadContexts.size());    for (int i = 0; i < threadContexts.size(); ++i) {        ThreadContext *newTC = threadContexts[i];        ThreadContext *oldTC = oldCPU->threadContexts[i];        newTC->takeOverFrom(oldTC);        CpuEvent::replaceThreadContext(oldTC, newTC);        assert(newTC->readCpuId() == oldTC->readCpuId());#if FULL_SYSTEM        system->replaceThreadContext(newTC, newTC->readCpuId());#else        assert(newTC->getProcessPtr() == oldTC->getProcessPtr());        newTC->getProcessPtr()->replaceThreadContext(newTC, newTC->readCpuId());#endif        if (DTRACE(Context))            ThreadContext::compare(oldTC, newTC);    }#if FULL_SYSTEM    interrupts = oldCPU->interrupts;    for (int i = 0; i < threadContexts.size(); ++i)        threadContexts[i]->profileClear();    if (profileEvent)        profileEvent->schedule(curTick);#endif    // Connect new CPU to old CPU's memory only if new CPU isn't    // connected to anything.  Also connect old CPU's memory to new    // CPU.    Port *peer;    if (ic->getPeer() == NULL || ic->getPeer()->isDefaultPort()) {        peer = oldCPU->getPort("icache_port")->getPeer();        ic->setPeer(peer);    } else {        peer = ic->getPeer();    }    peer->setPeer(ic);    if (dc->getPeer() == NULL || dc->getPeer()->isDefaultPort()) {        peer = oldCPU->getPort("dcache_port")->getPeer();        dc->setPeer(peer);    } else {        peer = dc->getPeer();    }    peer->setPeer(dc);}#if FULL_SYSTEMBaseCPU::ProfileEvent::ProfileEvent(BaseCPU *_cpu, int _interval)    : Event(&mainEventQueue), cpu(_cpu), interval(_interval){ }voidBaseCPU::ProfileEvent::process(){    for (int i = 0, size = cpu->threadContexts.size(); i < size; ++i) {        ThreadContext *tc = cpu->threadContexts[i];        tc->profileSample();    }    schedule(curTick + interval);}voidBaseCPU::post_interrupt(int int_num, int index){    interrupts.post(int_num, index);}voidBaseCPU::clear_interrupt(int int_num, int index){    interrupts.clear(int_num, index);}voidBaseCPU::clear_interrupts(){    interrupts.clear_all();}uint64_tBaseCPU::get_interrupts(int int_num){    return interrupts.get_vec(int_num);}voidBaseCPU::serialize(std::ostream &os){    SERIALIZE_SCALAR(instCnt);    interrupts.serialize(os);}voidBaseCPU::unserialize(Checkpoint *cp, const std::string &section){    UNSERIALIZE_SCALAR(instCnt);    interrupts.unserialize(cp, section);}#endif // FULL_SYSTEMvoidBaseCPU::traceFunctionsInternal(Addr pc){    if (!debugSymbolTable)        return;    // if pc enters different function, print new function symbol and    // update saved range.  Otherwise do nothing.    if (pc < currentFunctionStart || pc >= currentFunctionEnd) {        string sym_str;        bool found = debugSymbolTable->findNearestSymbol(pc, sym_str,                                                         currentFunctionStart,                                                         currentFunctionEnd);        if (!found) {            // no symbol found: use addr as label            sym_str = csprintf("0x%x", pc);            currentFunctionStart = pc;            currentFunctionEnd = pc + 1;        }        ccprintf(*functionTraceStream, " (%d)\n%d: %s",                 curTick - functionEntryTick, curTick, sym_str);        functionEntryTick = curTick;    }}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?