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 §ion){ 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 + -
显示快捷键?