54 #include "arch/tlb.hh"
64 #include "debug/Mwait.hh"
65 #include "debug/SyscallVerbose.hh"
67 #include "params/BaseCPU.hh"
87 CPUProgressEvent::CPUProgressEvent(
BaseCPU *_cpu,
Tick ival)
88 :
Event(
Event::Progress_Event_Pri), _interval(ival), lastNumInst(0),
89 cpu(_cpu), _repeatEvent(true)
92 cpu->schedule(
this,
curTick() + _interval);
96 CPUProgressEvent::process()
101 cpu->schedule(
this,
curTick() + _interval);
103 if (cpu->switchedOut()) {
108 double ipc = double(temp - lastNumInst) / (_interval / cpu->clockPeriod());
110 DPRINTFN(
"%s progress event, total committed:%i, progress insts committed: "
111 "%lli, IPC: %0.8d\n", cpu->name(), temp, temp - lastNumInst,
115 cprintf(
"%lli: %s progress event, total committed:%i, progress insts "
116 "committed: %lli\n",
curTick(), cpu->name(), temp,
123 CPUProgressEvent::description()
const
125 return "CPU Progress";
128 BaseCPU::BaseCPU(Params *
p,
bool is_checker)
129 :
MemObject(p), instCnt(0), _cpuId(p->cpu_id), _socketId(p->socket_id),
130 _instMasterId(p->
system->getMasterId(
name() +
".inst")),
131 _dataMasterId(p->
system->getMasterId(
name() +
".data")),
132 _taskId(ContextSwitchTaskId::
Unknown), _pid(invldPid),
133 _switchedOut(p->switched_out), _cacheLineSize(p->
system->cacheLineSize()),
134 interrupts(p->interrupts), profileEvent(NULL),
136 functionTraceStream(nullptr), currentFunctionStart(0),
137 currentFunctionEnd(0), functionEntryTick(0),
138 addressMonitor(p->numThreads),
139 syscallRetryLatency(p->syscallRetryLatency)
143 _cpuId = cpuList.size();
147 cpuList.push_back(
this);
149 DPRINTF(SyscallVerbose,
"Constructing CPU with id %d, socket id %d\n",
156 comInstEventQueue =
new EventQueue *[numThreads];
157 for (
ThreadID tid = 0; tid < numThreads; ++tid)
158 comInstEventQueue[tid] =
159 new EventQueue(
"instruction-based event queue");
164 if (p->max_insts_any_thread != 0) {
165 const char *cause =
"a thread reached the max instruction count";
166 for (
ThreadID tid = 0; tid < numThreads; ++tid)
167 scheduleInstStop(tid, p->max_insts_any_thread, cause);
174 if (!p->simpoint_start_insts.empty()) {
175 const char *cause =
"simpoint starting point found";
176 for (
size_t i = 0;
i < p->simpoint_start_insts.size(); ++
i)
177 scheduleInstStop(0, p->simpoint_start_insts[
i], cause);
180 if (p->max_insts_all_threads != 0) {
181 const char *cause =
"all threads reached the max instruction count";
186 int *counter =
new int;
187 *counter = numThreads;
188 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
190 comInstEventQueue[tid]->schedule(
event, p->max_insts_all_threads);
195 comLoadEventQueue =
new EventQueue *[numThreads];
196 for (
ThreadID tid = 0; tid < numThreads; ++tid)
197 comLoadEventQueue[tid] =
new EventQueue(
"load-based event queue");
202 if (p->max_loads_any_thread != 0) {
203 const char *cause =
"a thread reached the max load count";
204 for (
ThreadID tid = 0; tid < numThreads; ++tid)
205 scheduleLoadStop(tid, p->max_loads_any_thread, cause);
208 if (p->max_loads_all_threads != 0) {
209 const char *cause =
"all threads reached the max load count";
213 int *counter =
new int;
214 *counter = numThreads;
215 for (
ThreadID tid = 0; tid < numThreads; ++tid) {
217 comLoadEventQueue[tid]->schedule(
event, p->max_loads_all_threads);
221 functionTracingEnabled =
false;
222 if (p->function_trace) {
226 currentFunctionStart = currentFunctionEnd = 0;
227 functionEntryTick = p->function_trace_start;
229 if (p->function_trace_start == 0) {
230 functionTracingEnabled =
true;
233 Event *
event =
new wrap(
this,
true);
234 schedule(
event, p->function_trace_start);
240 if (!params()->switched_out && !is_checker) {
241 fatal_if(interrupts.size() != numThreads,
242 "CPU %s has %i interrupt controllers, but is expecting one "
244 name(), interrupts.size(), numThreads);
245 for (
ThreadID tid = 0; tid < numThreads; tid++)
246 interrupts[tid]->setCPU(
this);
250 if (params()->profile)
251 profileEvent =
new ProfileEvent(
this, params()->profile);
253 tracer = params()->tracer;
255 if (params()->isa.size() != numThreads) {
256 fatal(
"Number of ISAs (%i) assigned to the CPU does not equal number "
257 "of threads (%i).\n", params()->isa.size(), numThreads);
262 BaseCPU::enableFunctionTrace()
264 functionTracingEnabled =
true;
270 delete[] comLoadEventQueue;
271 delete[] comInstEventQueue;
277 assert(tid < numThreads);
278 AddressMonitor &monitor = addressMonitor[tid];
280 monitor.armed =
true;
281 monitor.vAddr = address;
283 DPRINTF(Mwait,
"[tid:%d] Armed monitor (vAddr=0x%lx)\n", tid, address);
289 assert(tid < numThreads);
290 AddressMonitor &monitor = addressMonitor[tid];
292 if (!monitor.gotWakeup) {
293 int block_size = cacheLineSize();
294 uint64_t
mask = ~((uint64_t)(block_size - 1));
298 monitor.waiting =
true;
300 DPRINTF(Mwait,
"[tid:%d] mwait called (vAddr=0x%lx, "
301 "line's paddr=0x%lx)\n", tid, monitor.vAddr, monitor.pAddr);
304 monitor.gotWakeup =
false;
312 assert(tid < numThreads);
313 AddressMonitor &monitor = addressMonitor[tid];
317 int block_size = cacheLineSize();
318 uint64_t mask = ~((uint64_t)(block_size - 1));
319 int size = block_size;
324 if (secondAddr > addr)
325 size = secondAddr -
addr;
334 monitor.waiting =
true;
336 DPRINTF(Mwait,
"[tid:%d] mwait called (vAddr=0x%lx, line's paddr=0x%lx)\n",
337 tid, monitor.vAddr, monitor.pAddr);
343 if (!params()->switched_out) {
344 registerThreadContexts();
354 if (!params()->switched_out && profileEvent)
355 schedule(profileEvent,
curTick());
358 if (params()->progress_interval) {
359 new CPUProgressEvent(
this, params()->progress_interval);
369 BaseCPU::pmuProbePoint(
const char *
name)
378 BaseCPU::regProbePoints()
380 ppCycles = pmuProbePoint(
"Cycles");
382 ppRetiredInsts = pmuProbePoint(
"RetiredInsts");
383 ppRetiredLoads = pmuProbePoint(
"RetiredLoads");
384 ppRetiredStores = pmuProbePoint(
"RetiredStores");
385 ppRetiredBranches = pmuProbePoint(
"RetiredBranches");
392 ppRetiredInsts->notify(1);
396 ppRetiredLoads->notify(1);
399 ppRetiredStores->notify(1);
402 ppRetiredBranches->notify(1);
410 using namespace Stats;
413 .name(
name() +
".numCycles")
414 .desc(
"number of cpu cycles simulated")
418 .name(
name() +
".numWorkItemsStarted")
419 .desc(
"number of work items this cpu started")
422 numWorkItemsCompleted
423 .name(
name() +
".numWorkItemsCompleted")
424 .desc(
"number of work items this cpu completed")
427 int size = threadContexts.size();
429 for (
int i = 0;
i <
size; ++
i) {
430 stringstream namestr;
432 threadContexts[
i]->regStats(namestr.str());
434 }
else if (size == 1)
435 threadContexts[0]->regStats(
name());
439 BaseCPU::getMasterPort(
const string &if_name,
PortID idx)
445 if (if_name ==
"dcache_port")
446 return getDataPort();
447 else if (if_name ==
"icache_port")
448 return getInstPort();
454 BaseCPU::registerThreadContexts()
456 assert(
system->multiThread || numThreads == 1);
458 ThreadID size = threadContexts.size();
462 if (
system->multiThread) {
477 ThreadID size = threadContexts.size();
479 if (tc == threadContexts[tid])
486 BaseCPU::activateContext(
ThreadID thread_num)
493 BaseCPU::suspendContext(
ThreadID thread_num)
496 for (
auto t : threadContexts) {
509 assert(!_switchedOut);
511 if (profileEvent && profileEvent->scheduled())
512 deschedule(profileEvent);
522 assert(threadContexts.size() == oldCPU->threadContexts.size());
523 assert(_cpuId == oldCPU->cpuId());
524 assert(_switchedOut);
525 assert(oldCPU !=
this);
526 _pid = oldCPU->getPid();
527 _taskId = oldCPU->taskId();
528 _switchedOut =
false;
530 ThreadID size = threadContexts.size();
558 assert(old_itb_port);
562 new_itb_port->
bind(slavePort);
566 assert(old_dtb_port);
570 new_dtb_port->
bind(slavePort);
579 if (oldChecker && newChecker) {
581 oldChecker->
getITBPtr()->getMasterPort();
583 oldChecker->
getDTBPtr()->getMasterPort();
585 newChecker->
getITBPtr()->getMasterPort();
587 newChecker->
getDTBPtr()->getMasterPort();
593 if (new_checker_itb_port) {
595 assert(old_checker_itb_port);
599 old_checker_itb_port->
unbind();
600 new_checker_itb_port->
bind(slavePort);
602 if (new_checker_dtb_port) {
604 assert(old_checker_dtb_port);
608 old_checker_dtb_port->
unbind();
609 new_checker_dtb_port->
bind(slavePort);
614 interrupts = oldCPU->interrupts;
615 for (
ThreadID tid = 0; tid < numThreads; tid++) {
616 interrupts[tid]->setCPU(
this);
618 oldCPU->interrupts.clear();
622 threadContexts[
i]->profileClear();
625 schedule(profileEvent,
curTick());
632 assert(!getInstPort().isConnected());
633 assert(oldCPU->getInstPort().isConnected());
634 BaseSlavePort &inst_peer_port = oldCPU->getInstPort().getSlavePort();
635 oldCPU->getInstPort().unbind();
636 getInstPort().bind(inst_peer_port);
638 assert(!getDataPort().isConnected());
639 assert(oldCPU->getDataPort().isConnected());
640 BaseSlavePort &data_peer_port = oldCPU->getDataPort().getSlavePort();
641 oldCPU->getDataPort().unbind();
642 getDataPort().bind(data_peer_port);
648 for (
ThreadID i = 0;
i < threadContexts.size(); ++
i) {
655 checker->getITBPtr()->flushAll();
656 checker->getDTBPtr()->flushAll();
662 BaseCPU::ProfileEvent::ProfileEvent(
BaseCPU *_cpu,
Tick _interval)
663 : cpu(_cpu), interval(_interval)
667 BaseCPU::ProfileEvent::process()
669 ThreadID size = cpu->threadContexts.size();
675 cpu->schedule(
this,
curTick() + interval);
692 ScopedCheckpointSection sec(cp,
csprintf(
"xc.%i",
i));
693 interrupts[
i]->serialize(cp);
694 serializeThread(cp,
i);
709 ScopedCheckpointSection sec(cp,
csprintf(
"xc.%i",
i));
710 interrupts[
i]->unserialize(cp);
711 unserializeThread(cp,
i);
717 BaseCPU::scheduleInstStop(
ThreadID tid,
Counter insts,
const char *cause)
719 const Tick now(comInstEventQueue[tid]->getCurTick());
722 comInstEventQueue[tid]->schedule(
event, now + insts);
726 BaseCPU::getCurrentInstCount(
ThreadID tid)
728 return Tick(comInstEventQueue[tid]->getCurTick());
731 AddressMonitor::AddressMonitor() {
737 bool AddressMonitor::doMonitor(
PacketPtr pkt) {
739 if (armed && waiting) {
741 DPRINTF(Mwait,
"pAddr=0x%lx invalidated: waking up core\n",
751 BaseCPU::scheduleLoadStop(
ThreadID tid,
Counter loads,
const char *cause)
753 const Tick now(comLoadEventQueue[tid]->getCurTick());
756 comLoadEventQueue[tid]->schedule(
event, now + loads);
761 BaseCPU::traceFunctionsInternal(
Addr pc)
768 if (pc < currentFunctionStart || pc >= currentFunctionEnd) {
771 currentFunctionStart,
777 currentFunctionStart =
pc;
778 currentFunctionEnd = pc + 1;
781 ccprintf(*functionTraceStream,
" (%d)\n%d: %s",
void ccprintf(cp::Print &print)
std::ostream * stream() const
Get the output underlying output stream.
static void replaceThreadContext(ThreadContext *oldTc, ThreadContext *newTc)
Update all events switching old tc to new tc.
virtual Addr instAddr()=0
decltype(nullptr) constexpr NoFault
const std::string & name()
bool FullSystem
The FullSystem variable can be used to determine the current mode of simulation.
virtual Process * getProcessPtr()=0
SymbolTable * debugSymbolTable
Global unified debugging symbol table (for target).
TheISA::TLB * getITBPtr()
ThreadContext is the external interface to all thread state for anything outside of the CPU...
A BaseSlavePort is a protocol-agnostic slave port, responsible only for the structural connection to ...
#define UNSERIALIZE_SCALAR(scalar)
Tick curTick()
The current simulated tick.
std::string csprintf(const char *format, const Args &...args)
Enums::PwrState pwrState() const
void assignThreadContext(ContextID context_id)
Queue of events sorted in time order.
std::unique_ptr< PMU > PMUUPtr
void takeOverFrom(ThreadContext &ntc, ThreadContext &otc)
Copy state between thread contexts in preparation for CPU handover.
uint64_t Tick
Tick count type.
virtual TheISA::TLB * getDTBPtr()=0
ClockedObject declaration and implementation.
const RequestPtr req
A pointer to the original request.
T roundDown(const T &val, const U &align)
uint64_t Addr
Address type This will probably be moved somewhere else in the near future.
int64_t Counter
Statistics counter type.
A Packet is used to encapsulate a transfer between two objects in the memory system (e...
int maxThreadsPerCPU
The maximum number of active threads across all cpus.
#define SERIALIZE_SCALAR(scalar)
virtual void profileSample()=0
int16_t ThreadID
Thread index/ID type.
OutputStream * findOrCreate(const std::string &name, bool binary=false)
virtual CheckerCPU * getCheckerCpuPtr()=0
ProbePointArg generates a point for the class of Arg.
Declarations of a non-full system Page Table.
virtual void setContextId(int id)=0
TheISA::TLB * getDTBPtr()
virtual void bind(BaseSlavePort &slave_port)=0
std::ostream CheckpointOut
virtual void takeOverFrom(ThreadContext *old_context)=0
The MemObject class extends the ClockedObject with accessor functions to get its master and slave por...
virtual int threadId() const =0
A BaseMasterPort is a protocol-agnostic master port, responsible only for the structural connection t...
virtual int contextId() const =0
void setVirt(int asid, Addr vaddr, unsigned size, Flags flags, MasterID mid, Addr pc)
Set up a virtual (e.g., CPU) request in a previously allocated Request object.
BaseSlavePort & getSlavePort() const
int16_t PortID
Port index/ID type, and a symbolic name for an invalid port id.
bool findNearestSymbol(Addr addr, std::string &symbol, Addr &symaddr, Addr &nextaddr) const
Find the nearest symbol equal to or less than the supplied address (e.g., the label for the enclosing...
void serialize(CheckpointOut &cp) const override
void unserialize(CheckpointIn &cp) override
fatal_if(p->js_features.size() > 16,"Too many job slot feature registers specified (%i)\n", p->js_features.size())
bool isLastMicroop() const
std::shared_ptr< FaultBase > Fault
void regStats() override
Register statistics for this object.
virtual BaseMasterPort & getMasterPort(const std::string &if_name, PortID idx=InvalidPortID)
Get a master port with a given name and index.
const FlagsType init
This Stat is Initialized.
virtual TheISA::TLB * getITBPtr()=0
bool hasPaddr() const
Accessor for paddr.
void cprintf(const char *format, const Args &...args)