sim: revamp unserialization procedure

Replace direct call to unserialize() on each SimObject with a pair of
calls for better control over initialization in both ckpt and non-ckpt
cases.

If restoring from a checkpoint, loadState(ckpt) is called on each
SimObject.  The default implementation simply calls unserialize() if
there is a corresponding checkpoint section, so we get backward
compatibility for existing objects.  However, objects can override
loadState() to get other behaviors, e.g., doing other programmed
initializations after unserialize(), or complaining if no checkpoint
section is found.  (Note that the default warning for a missing
checkpoint section is now gone.)

If not restoring from a checkpoint, we call the new initState() method
on each SimObject instead.  This provides a hook for state
initializations that are only required when *not* restoring from a
checkpoint.

Given this new framework, do some cleanup of LiveProcess subclasses
and X86System, which were (in some cases) emulating initState()
behavior in startup via a local flag or (in other cases) erroneously
doing initializations in startup() that clobbered state loaded earlier
by unserialize().
This commit is contained in:
Steve Reinhardt 2010-08-17 05:17:06 -07:00
parent 2519d116c9
commit f064aa3060
27 changed files with 132 additions and 87 deletions

View file

@ -173,19 +173,35 @@ AlphaLiveProcess::argsInit(int intSize, int pageSize)
}
void
AlphaLiveProcess::startup()
AlphaLiveProcess::setupASNReg()
{
ThreadContext *tc = system->getThreadContext(contextIds[0]);
tc->setMiscRegNoEffect(IPR_DTB_ASN, M5_pid << 57);
}
if (checkpointRestored) {
return;
}
Process::startup();
void
AlphaLiveProcess::loadState(Checkpoint *cp)
{
LiveProcess::loadState(cp);
// need to set up ASN after unserialization since M5_pid value may
// come from checkpoint
setupASNReg();
}
void
AlphaLiveProcess::initState()
{
// need to set up ASN before further initialization since init
// will involve writing to virtual memory addresses
setupASNReg();
LiveProcess::initState();
argsInit(MachineBytes, VMPageSize);
ThreadContext *tc = system->getThreadContext(contextIds[0]);
tc->setIntReg(GlobalPointerReg, objFile->globalPointer());
//Operate in user mode
tc->setMiscRegNoEffect(IPR_ICM, 0x18);

View file

@ -36,10 +36,14 @@
class AlphaLiveProcess : public LiveProcess
{
private:
void setupASNReg();
protected:
AlphaLiveProcess(LiveProcessParams *params, ObjectFile *objFile);
void startup();
void loadState(Checkpoint *cp);
void initState();
void argsInit(int intSize, int pageSize);

View file

@ -76,6 +76,7 @@ ArmLiveProcess::ArmLiveProcess(LiveProcessParams *params, ObjectFile *objFile,
void
ArmLiveProcess::startup()
{
LiveProcess::startup();
argsInit(MachineBytes, VMPageSize);
}
@ -114,9 +115,6 @@ ArmLiveProcess::argsInit(int intSize, int pageSize)
//We want 16 byte alignment
uint64_t align = 16;
// Overloaded argsInit so that we can fine-tune for ARM architecture
Process::startup();
// load object file into target memory
objFile->loadSections(initVirtMem);

View file

@ -67,9 +67,9 @@ MipsLiveProcess::MipsLiveProcess(LiveProcessParams * params,
}
void
MipsLiveProcess::startup()
MipsLiveProcess::initState()
{
Process::startup();
LiveProcess::initState();
argsInit<uint32_t>(VMPageSize);
}
@ -79,7 +79,6 @@ void
MipsLiveProcess::argsInit(int pageSize)
{
int intSize = sizeof(IntType);
Process::startup();
// load object file into target memory
objFile->loadSections(initVirtMem);

View file

@ -45,7 +45,7 @@ class MipsLiveProcess : public LiveProcess
protected:
MipsLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
void startup();
void initState();
template<class IntType>
void argsInit(int pageSize);

View file

@ -432,9 +432,9 @@ PowerLinuxProcess::getDesc(int callnum)
}
void
PowerLinuxProcess::startup()
PowerLinuxProcess::initState()
{
PowerLiveProcess::startup();
PowerLiveProcess::initState();
}
PowerISA::IntReg

View file

@ -44,7 +44,7 @@ class PowerLinuxProcess : public PowerLiveProcess
virtual SyscallDesc* getDesc(int callnum);
void startup();
void initState();
PowerISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
void setSyscallArg(ThreadContext *tc, int i, PowerISA::IntReg val);

View file

@ -63,8 +63,10 @@ PowerLiveProcess::PowerLiveProcess(LiveProcessParams *params,
}
void
PowerLiveProcess::startup()
PowerLiveProcess::initState()
{
Process::initState();
argsInit(MachineBytes, VMPageSize);
}
@ -83,9 +85,6 @@ PowerLiveProcess::argsInit(int intSize, int pageSize)
//We want 16 byte alignment
uint64_t align = 16;
// Overloaded argsInit so that we can fine-tune for POWER architecture
Process::startup();
// load object file into target memory
objFile->loadSections(initVirtMem);

View file

@ -46,7 +46,7 @@ class PowerLiveProcess : public LiveProcess
protected:
PowerLiveProcess(LiveProcessParams * params, ObjectFile *objFile);
void startup();
void initState();
public:
void argsInit(int intSize, int pageSize);

View file

@ -111,9 +111,9 @@ void SparcLiveProcess::handleTrap(int trapNum, ThreadContext *tc)
}
void
SparcLiveProcess::startup()
SparcLiveProcess::initState()
{
Process::startup();
LiveProcess::initState();
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//From the SPARC ABI
@ -157,12 +157,9 @@ SparcLiveProcess::startup()
}
void
Sparc32LiveProcess::startup()
Sparc32LiveProcess::initState()
{
if (checkpointRestored)
return;
SparcLiveProcess::startup();
SparcLiveProcess::initState();
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//The process runs in user mode with 32 bit addresses
@ -172,12 +169,9 @@ Sparc32LiveProcess::startup()
}
void
Sparc64LiveProcess::startup()
Sparc64LiveProcess::initState()
{
if (checkpointRestored)
return;
SparcLiveProcess::startup();
SparcLiveProcess::initState();
ThreadContext *tc = system->getThreadContext(contextIds[0]);
//The process runs in user mode

View file

@ -52,7 +52,7 @@ class SparcLiveProcess : public LiveProcess
SparcLiveProcess(LiveProcessParams * params,
ObjectFile *objFile, Addr _StackBias);
void startup();
void initState();
template<class IntType>
void argsInit(int pageSize);
@ -87,7 +87,7 @@ class Sparc32LiveProcess : public SparcLiveProcess
mmap_start = mmap_end = 0x70000000;
}
void startup();
void initState();
public:
@ -115,7 +115,7 @@ class Sparc64LiveProcess : public SparcLiveProcess
mmap_start = mmap_end = 0xfffff80000000000ULL;
}
void startup();
void initState();
public:

View file

@ -59,9 +59,9 @@ LinuxX86System::~LinuxX86System()
}
void
LinuxX86System::startup()
LinuxX86System::initState()
{
X86System::startup();
X86System::initState();
// The location of the real mode data structure.
const Addr realModeData = 0x90200;

View file

@ -58,7 +58,7 @@ class LinuxX86System : public X86System
LinuxX86System(Params *p);
~LinuxX86System();
void startup();
void initState();
};
#endif

View file

@ -157,12 +157,9 @@ X86LiveProcess::getDesc(int callnum)
}
void
X86_64LiveProcess::startup()
X86_64LiveProcess::initState()
{
LiveProcess::startup();
if (checkpointRestored)
return;
X86LiveProcess::initState();
argsInit(sizeof(uint64_t), VMPageSize);
@ -255,12 +252,9 @@ X86_64LiveProcess::startup()
}
void
I386LiveProcess::startup()
I386LiveProcess::initState()
{
LiveProcess::startup();
if (checkpointRestored)
return;
X86LiveProcess::initState();
argsInit(sizeof(uint32_t), VMPageSize);

View file

@ -99,7 +99,7 @@ namespace X86ISA
public:
void argsInit(int intSize, int pageSize);
void startup();
void initState();
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);
void setSyscallArg(ThreadContext *tc, int i, X86ISA::IntReg val);
@ -123,7 +123,7 @@ namespace X86ISA
public:
void argsInit(int intSize, int pageSize);
void startup();
void initState();
void syscall(int64_t callnum, ThreadContext *tc);
X86ISA::IntReg getSyscallArg(ThreadContext *tc, int &i);

View file

@ -109,9 +109,10 @@ installSegDesc(ThreadContext *tc, SegmentRegIndex seg,
}
void
X86System::startup()
X86System::initState()
{
System::startup();
System::initState();
ThreadContext *tc = threadContexts[0];
// This is the boot strap processor (BSP). Initialize it to look like
// the boot loader has just turned control over to the 64 bit OS. We

View file

@ -77,7 +77,7 @@ class X86System : public System
void serialize(std::ostream &os);
void unserialize(Checkpoint *cp, const std::string &section);
void startup();
void initState();
protected:

View file

@ -88,8 +88,12 @@ def instantiate(ckpt_dir=None):
# Restore checkpoint (if any)
if ckpt_dir:
internal.core.unserializeAll(ckpt_dir)
ckpt = internal.core.getCheckpoint(ckpt_dir)
internal.core.unserializeGlobals(ckpt);
for obj in root.descendants(): obj.loadState(ckpt)
need_resume.append(root)
else:
for obj in root.descendants(): obj.initState()
# Reset to put the stats in a consistent state.
stats.reset()

View file

@ -75,8 +75,11 @@ void setClockFrequency(Tick ticksPerSecond);
%immutable curTick;
Tick curTick;
class Checkpoint;
void serializeAll(const std::string &cpt_dir);
void unserializeAll(const std::string &cpt_dir);
Checkpoint *getCheckpoint(const std::string &cpt_dir);
void unserializeGlobals(Checkpoint *cp);
bool want_warn, warn_verbose;
bool want_info, info_verbose;

View file

@ -52,8 +52,14 @@ serializeAll(const std::string &cpt_dir)
Serializable::serializeAll(cpt_dir);
}
inline void
unserializeAll(const std::string &cpt_dir)
inline Checkpoint *
getCheckpoint(const std::string &cpt_dir)
{
Serializable::unserializeAll(cpt_dir);
return new Checkpoint(cpt_dir);
}
inline void
unserializeGlobals(Checkpoint *cp)
{
Serializable::unserializeGlobals(cp);
}

View file

@ -51,6 +51,8 @@ class SimObject {
};
void init();
void loadState(Checkpoint *cp);
void initState();
void regStats();
void regFormulas();
void resetStats();

View file

@ -100,8 +100,8 @@ template class AuxVector<uint32_t>;
template class AuxVector<uint64_t>;
Process::Process(ProcessParams * params)
: SimObject(params), system(params->system), checkpointRestored(false),
max_stack_size(params->max_stack_size)
: SimObject(params), system(params->system),
max_stack_size(params->max_stack_size)
{
string in = params->input;
string out = params->output;
@ -233,7 +233,7 @@ Process::findFreeContext()
}
void
Process::startup()
Process::initState()
{
if (contextIds.empty())
fatal("Process %s is not associated with any HW contexts!\n", name());
@ -537,9 +537,6 @@ Process::unserialize(Checkpoint *cp, const std::string &section)
// find the param in the checkpoint if you wanted to, like set a default
// but in this case we'll just stick with the instantianted value if not
// found.
checkpointRestored = true;
}

View file

@ -79,8 +79,6 @@ class Process : public SimObject
/// running on.
System *system;
bool checkpointRestored;
// thread contexts associated with this process
std::vector<int> contextIds;
@ -130,8 +128,7 @@ class Process : public SimObject
// constructor
Process(ProcessParams * params);
// post initialization startup
virtual void startup();
virtual void initState();
protected:
/// Memory object for initialization (image loading)

View file

@ -451,17 +451,6 @@ Serializable::serializeAll(const string &cpt_dir)
SimObject::serializeAll(outstream);
}
void
Serializable::unserializeAll(const string &cpt_dir)
{
string dir = Checkpoint::setDir(cpt_dir);
DPRINTFR(Config, "Loading checkpoint dir '%s'\n", dir);
Checkpoint *cp = new Checkpoint(dir);
unserializeGlobals(cp);
SimObject::unserializeAll(cp);
}
void
Serializable::unserializeGlobals(Checkpoint *cp)
{
@ -561,9 +550,9 @@ Checkpoint::dir()
Checkpoint::Checkpoint(const string &cpt_dir)
: db(new IniFile), cptDir(cpt_dir)
: db(new IniFile), cptDir(setDir(cpt_dir))
{
string filename = cpt_dir + "/" + Checkpoint::baseFilename;
string filename = cptDir + "/" + Checkpoint::baseFilename;
if (!db->load(filename)) {
fatal("Can't load checkpoint file '%s'\n", filename);
}

View file

@ -141,7 +141,6 @@ class Serializable
static int ckptMaxCount;
static int ckptPrevCount;
static void serializeAll(const std::string &cpt_dir);
static void unserializeAll(const std::string &cpt_dir);
static void unserializeGlobals(Checkpoint *cp);
};

View file

@ -73,6 +73,18 @@ SimObject::init()
{
}
void
SimObject::loadState(Checkpoint *cp)
{
if (cp->sectionExists(name()))
unserialize(cp, name());
}
void
SimObject::initState()
{
}
void
SimObject::startup()
{

View file

@ -91,17 +91,48 @@ class SimObject : public EventManager, public Serializable
virtual const std::string name() const { return params()->name; }
// initialization pass of all objects.
// Gets invoked after construction, before unserialize.
// The following SimObject initialization methods are called from
// the instantiate() method in src/python/m5/simulate.py. See
// that function for details on how/when these methods are
// invoked.
/**
* init() is called after all C++ SimObjects have been created and
* all ports are connected. Initializations that are independent
* of unserialization but rely on a fully instantiated and
* connected SimObject graph should be done here.
*/
virtual void init();
/**
* loadState() is called on each SimObject when restoring from a
* checkpoint. The default implementation simply calls
* unserialize() if there is a corresponding section in the
* checkpoint. However, objects can override loadState() to get
* other behaviors, e.g., doing other programmed initializations
* after unserialize(), or complaining if no checkpoint section is
* found.
*/
virtual void loadState(Checkpoint *cp);
/**
* initState() is called on each SimObject when *not* restoring
* from a checkpoint. This provides a hook for state
* initializations that are only required for a "cold start".
*/
virtual void initState();
// register statistics for this object
virtual void regStats();
virtual void regFormulas();
virtual void resetStats();
// final initialization before simulation
// all state is unserialized so
/**
* startup() is the final initialization call before simulation.
* All state is initialized (including unserialized state, if any,
* such as the curTick value), so this is the appropriate place to
* schedule initial event(s) for objects that need them.
*/
virtual void startup();
// static: call nameOut() & serialize() on all SimObjects