cpu: Fix broken thread context handover
The thread context handover code used to break when multiple handovers were performed during the same quiesce period. Previously, the thread contexts would assign the TC pointer in the old quiesce event to the new TC. This obviously broke in cases where multiple switches were performed within the same quiesce period, in which case the TC pointer in the quiesce event would point to an old CPU. The new implementation deschedules pending quiesce events in the old TC and schedules a new quiesce event in the new TC. The code has been refactored to remove most of the code duplication.
This commit is contained in:
parent
fca4fea769
commit
52ff37caa3
6 changed files with 57 additions and 79 deletions
|
@ -93,18 +93,10 @@ InOrderThreadContext::profileSample()
|
||||||
void
|
void
|
||||||
InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
|
InOrderThreadContext::takeOverFrom(ThreadContext *old_context)
|
||||||
{
|
{
|
||||||
// some things should already be set up
|
::takeOverFrom(*this, *old_context);
|
||||||
assert(getSystemPtr() == old_context->getSystemPtr());
|
|
||||||
assert(getProcessPtr() == old_context->getProcessPtr());
|
|
||||||
|
|
||||||
// copy over functional state
|
|
||||||
setStatus(old_context->status());
|
|
||||||
copyArchRegs(old_context);
|
|
||||||
|
|
||||||
thread->funcExeInst = old_context->readFuncExeInst();
|
thread->funcExeInst = old_context->readFuncExeInst();
|
||||||
|
|
||||||
old_context->setStatus(ThreadContext::Halted);
|
|
||||||
|
|
||||||
thread->noSquashFromTC = false;
|
thread->noSquashFromTC = false;
|
||||||
thread->trapPending = false;
|
thread->trapPending = false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,34 +66,10 @@ template <class Impl>
|
||||||
void
|
void
|
||||||
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
|
O3ThreadContext<Impl>::takeOverFrom(ThreadContext *old_context)
|
||||||
{
|
{
|
||||||
// some things should already be set up
|
::takeOverFrom(*this, *old_context);
|
||||||
assert(getSystemPtr() == old_context->getSystemPtr());
|
|
||||||
assert(getProcessPtr() == old_context->getProcessPtr());
|
|
||||||
|
|
||||||
// copy over functional state
|
thread->kernelStats = old_context->getKernelStats();
|
||||||
setStatus(old_context->status());
|
thread->funcExeInst = old_context->readFuncExeInst();
|
||||||
copyArchRegs(old_context);
|
|
||||||
setContextId(old_context->contextId());
|
|
||||||
setThreadId(old_context->threadId());
|
|
||||||
|
|
||||||
if (FullSystem) {
|
|
||||||
EndQuiesceEvent *other_quiesce = old_context->getQuiesceEvent();
|
|
||||||
if (other_quiesce) {
|
|
||||||
// Point the quiesce event's TC at this TC so that it wakes up
|
|
||||||
// the proper CPU.
|
|
||||||
other_quiesce->tc = this;
|
|
||||||
}
|
|
||||||
if (thread->quiesceEvent) {
|
|
||||||
thread->quiesceEvent->tc = this;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transfer kernel stats from one CPU to the other.
|
|
||||||
thread->kernelStats = old_context->getKernelStats();
|
|
||||||
} else {
|
|
||||||
thread->funcExeInst = old_context->readFuncExeInst();
|
|
||||||
}
|
|
||||||
|
|
||||||
old_context->setStatus(ThreadContext::Halted);
|
|
||||||
|
|
||||||
thread->noSquashFromTC = false;
|
thread->noSquashFromTC = false;
|
||||||
thread->trapPending = false;
|
thread->trapPending = false;
|
||||||
|
|
|
@ -107,49 +107,11 @@ SimpleThread::~SimpleThread()
|
||||||
void
|
void
|
||||||
SimpleThread::takeOverFrom(ThreadContext *oldContext)
|
SimpleThread::takeOverFrom(ThreadContext *oldContext)
|
||||||
{
|
{
|
||||||
// some things should already be set up
|
::takeOverFrom(*tc, *oldContext);
|
||||||
if (FullSystem)
|
|
||||||
assert(system == oldContext->getSystemPtr());
|
|
||||||
assert(process == oldContext->getProcessPtr());
|
|
||||||
|
|
||||||
copyState(oldContext);
|
|
||||||
if (FullSystem) {
|
|
||||||
EndQuiesceEvent *quiesce = oldContext->getQuiesceEvent();
|
|
||||||
if (quiesce) {
|
|
||||||
// Point the quiesce event's TC at this TC so that it wakes up
|
|
||||||
// the proper CPU.
|
|
||||||
quiesce->tc = tc;
|
|
||||||
}
|
|
||||||
if (quiesceEvent) {
|
|
||||||
quiesceEvent->tc = tc;
|
|
||||||
}
|
|
||||||
|
|
||||||
TheISA::Kernel::Statistics *stats = oldContext->getKernelStats();
|
|
||||||
if (stats) {
|
|
||||||
kernelStats = stats;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
kernelStats = oldContext->getKernelStats();
|
||||||
|
funcExeInst = oldContext->readFuncExeInst();
|
||||||
storeCondFailures = 0;
|
storeCondFailures = 0;
|
||||||
|
|
||||||
oldContext->setStatus(ThreadContext::Halted);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
SimpleThread::copyTC(ThreadContext *context)
|
|
||||||
{
|
|
||||||
copyState(context);
|
|
||||||
|
|
||||||
if (FullSystem) {
|
|
||||||
EndQuiesceEvent *quiesce = context->getQuiesceEvent();
|
|
||||||
if (quiesce) {
|
|
||||||
quiesceEvent = quiesce;
|
|
||||||
}
|
|
||||||
TheISA::Kernel::Statistics *stats = context->getKernelStats();
|
|
||||||
if (stats) {
|
|
||||||
kernelStats = stats;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -146,8 +146,6 @@ class SimpleThread : public ThreadState
|
||||||
|
|
||||||
void regStats(const std::string &name);
|
void regStats(const std::string &name);
|
||||||
|
|
||||||
void copyTC(ThreadContext *context);
|
|
||||||
|
|
||||||
void copyState(ThreadContext *oldContext);
|
void copyState(ThreadContext *oldContext);
|
||||||
|
|
||||||
void serialize(std::ostream &os);
|
void serialize(std::ostream &os);
|
||||||
|
|
|
@ -43,8 +43,11 @@
|
||||||
#include "base/misc.hh"
|
#include "base/misc.hh"
|
||||||
#include "base/trace.hh"
|
#include "base/trace.hh"
|
||||||
#include "config/the_isa.hh"
|
#include "config/the_isa.hh"
|
||||||
|
#include "cpu/base.hh"
|
||||||
|
#include "cpu/quiesce_event.hh"
|
||||||
#include "cpu/thread_context.hh"
|
#include "cpu/thread_context.hh"
|
||||||
#include "debug/Context.hh"
|
#include "debug/Context.hh"
|
||||||
|
#include "sim/full_system.hh"
|
||||||
|
|
||||||
void
|
void
|
||||||
ThreadContext::compare(ThreadContext *one, ThreadContext *two)
|
ThreadContext::compare(ThreadContext *one, ThreadContext *two)
|
||||||
|
@ -136,3 +139,37 @@ unserialize(ThreadContext &tc, Checkpoint *cp, const std::string §ion)
|
||||||
|
|
||||||
// thread_num and cpu_id are deterministic from the config
|
// thread_num and cpu_id are deterministic from the config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
takeOverFrom(ThreadContext &ntc, ThreadContext &otc)
|
||||||
|
{
|
||||||
|
assert(ntc.getProcessPtr() == otc.getProcessPtr());
|
||||||
|
|
||||||
|
ntc.setStatus(otc.status());
|
||||||
|
ntc.copyArchRegs(&otc);
|
||||||
|
ntc.setContextId(otc.contextId());
|
||||||
|
ntc.setThreadId(otc.threadId());
|
||||||
|
|
||||||
|
if (FullSystem) {
|
||||||
|
assert(ntc.getSystemPtr() == otc.getSystemPtr());
|
||||||
|
|
||||||
|
BaseCPU *ncpu(ntc.getCpuPtr());
|
||||||
|
assert(ncpu);
|
||||||
|
EndQuiesceEvent *oqe(otc.getQuiesceEvent());
|
||||||
|
assert(oqe);
|
||||||
|
assert(oqe->tc == &otc);
|
||||||
|
|
||||||
|
BaseCPU *ocpu(otc.getCpuPtr());
|
||||||
|
assert(ocpu);
|
||||||
|
EndQuiesceEvent *nqe(ntc.getQuiesceEvent());
|
||||||
|
assert(nqe);
|
||||||
|
assert(nqe->tc == &ntc);
|
||||||
|
|
||||||
|
if (oqe->scheduled()) {
|
||||||
|
ncpu->schedule(nqe, oqe->when());
|
||||||
|
ocpu->deschedule(oqe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
otc.setStatus(ThreadContext::Halted);
|
||||||
|
}
|
||||||
|
|
|
@ -481,4 +481,17 @@ void unserialize(ThreadContext &tc, Checkpoint *cp, const std::string §ion);
|
||||||
|
|
||||||
/** @} */
|
/** @} */
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Copy state between thread contexts in preparation for CPU handover.
|
||||||
|
*
|
||||||
|
* @note This method modifies the old thread contexts as well as the
|
||||||
|
* new thread context. The old thread context will have its quiesce
|
||||||
|
* event descheduled if it is scheduled and its status set to halted.
|
||||||
|
*
|
||||||
|
* @param new_tc Destination ThreadContext.
|
||||||
|
* @param old_tc Source ThreadContext.
|
||||||
|
*/
|
||||||
|
void takeOverFrom(ThreadContext &new_tc, ThreadContext &old_tc);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Reference in a new issue