sim: revamp unserialization procedure
authorSteve Reinhardt <steve.reinhardt@amd.com>
Tue, 17 Aug 2010 12:17:06 +0000 (05:17 -0700)
committerSteve Reinhardt <steve.reinhardt@amd.com>
Tue, 17 Aug 2010 12:17:06 +0000 (05:17 -0700)
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().

27 files changed:
src/arch/alpha/process.cc
src/arch/alpha/process.hh
src/arch/arm/process.cc
src/arch/mips/process.cc
src/arch/mips/process.hh
src/arch/power/linux/process.cc
src/arch/power/linux/process.hh
src/arch/power/process.cc
src/arch/power/process.hh
src/arch/sparc/process.cc
src/arch/sparc/process.hh
src/arch/x86/linux/system.cc
src/arch/x86/linux/system.hh
src/arch/x86/process.cc
src/arch/x86/process.hh
src/arch/x86/system.cc
src/arch/x86/system.hh
src/python/m5/simulate.py
src/python/swig/core.i
src/python/swig/pyobject.hh
src/python/swig/sim_object.i
src/sim/process.cc
src/sim/process.hh
src/sim/serialize.cc
src/sim/serialize.hh
src/sim/sim_object.cc
src/sim/sim_object.hh

index 1c83f64b27ec403382247a9fde02e50a33b316e7..431ef86c0639b3c1be17fb99724cc43df365789f 100644 (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);
index 36b25a48efd88f300ec251aae3524a80296706e3..40d6bf48a0bc3f366620287e1d6b4bbfd6712b1c 100644 (file)
 
 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);
 
index 555fdf56e299de9bb99d66586965268769bbec22..e7748ad50b10c895899fddf5027dcea780938f9a 100644 (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);
 
index 2fd9114e982e1c5157aa877112697a681ed7457e..7f1e9470962ed89d8961ded1d20853a44d7f36d6 100644 (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);
index f1238b41fdbb373e5ce82b1923d30df32a99c5a3..a065feb8f59b155c3f8744090bc1ed5c205be6e2 100644 (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);
index 504d0e33421f3097b2ce9c78d62beb60df2dc5f4..c2587d5e7e9a2aed1240f4f8ffec1cc4bbe627b8 100644 (file)
@@ -432,9 +432,9 @@ PowerLinuxProcess::getDesc(int callnum)
 }
 
 void
-PowerLinuxProcess::startup()
+PowerLinuxProcess::initState()
 {
-    PowerLiveProcess::startup();
+    PowerLiveProcess::initState();
 }
 
 PowerISA::IntReg
index db6759a7737d083b0b860680782a3c44e26e57bb..bef7e8dae1159946ccffa01a97c05d49efcea3f8 100644 (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);
index 12b216e500f9253b26492894132c66e029cbfc3e..9fb69b9f8f85dea6927a2ff8c29f6aa605143d3b 100644 (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);
 
index ede75f05f10ec07fe21fa79e6db5c4754e32f643..473b7e02841c46f7a2c28920a356abfe910af0ab 100644 (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);
index 7e01f6b07a029b053afac1aecc8ae1c6b047222a..0cd8889a988f23b6611f535c5cd4ea2cda4851fe 100644 (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
index cca312e0ab9d54cde4dd9dafb9cf125dc988d086..2d68fb3fc952f3614f8aa20f68ea4d3a2f6f0c19 100644 (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:
 
index 4ae6d0ca4a7e680845e3bdaeae498dbeab750476..1a113d3658ce5b3840b052c8edc8949a70895f20 100644 (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;
index e3c52ae50aa0b7feea4130d01f0227d6a53985e1..ae7e93f3daa8b9c48ce6e55d1e5f075a80ed360b 100644 (file)
@@ -58,7 +58,7 @@ class LinuxX86System : public X86System
     LinuxX86System(Params *p);
     ~LinuxX86System();
 
-    void startup();
+    void initState();
 };
 
 #endif
index 2a2d43d3b793db02eac59d0581d632c2aa63b3cb..02cd454785e21ace7c0dc16aad71e734d52abe58 100644 (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);
 
index 8063898d7b52d25b0932efd9e256885a1a617772..34275b2d30672d171018b0f0f3998b72ec27ae4e 100644 (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);
index 01416e544d21e18366b84300d65cc6a67984b7be..46d17cdb3dcedfd9a762a2ea654d54261aa1abde 100644 (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
index 4a61193e6dba62593818cda2565b03b40a078acc..0b5da3145f4319298b1beb6f57469c6e32da9dd9 100644 (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:
 
index 0cf0a254e9734c2432bf31a6e00dd34c70cf8a11..cd2f8bb64a71daace934b8d61002d3cb39b5113b 100644 (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()
index 81085dd06426eb5c23f55705855acf9a6e574b8f..f48fe9590927ae4fd767164aa760a843c6d7baa1 100644 (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;
index a27080d08210691e78da2b9e7572114d51cc79d2..b18a2a76c1b44a976e1aa951d0ff078e1b76389c 100644 (file)
@@ -52,8 +52,14 @@ serializeAll(const std::string &cpt_dir)
     Serializable::serializeAll(cpt_dir);
 }
 
+inline Checkpoint *
+getCheckpoint(const std::string &cpt_dir)
+{
+    return new Checkpoint(cpt_dir);
+}
+
 inline void
-unserializeAll(const std::string &cpt_dir)
+unserializeGlobals(Checkpoint *cp)
 {
-    Serializable::unserializeAll(cpt_dir);
+    Serializable::unserializeGlobals(cp);
 }
index 8cd8e8beb74361832a43ec6c00e427426a0ddc1d..af9afd057a62d6e7cf5f9ebbd71ab93720af697e 100644 (file)
@@ -51,6 +51,8 @@ class SimObject {
     };
 
     void init();
+    void loadState(Checkpoint *cp);
+    void initState();
     void regStats();
     void regFormulas();
     void resetStats();
index f11fdcac829ad990484d9291bc950b2208955b54..d4b1fba900df0d20e6ae6e94701ad4ecc8a7caaf 100644 (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;
-
 }
 
 
index e73f93fa55be7876eae986b8a9df5b9d9a0529b1..3b78cb0012e6a757c3013afa9a2cbf2a551323c9 100644 (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)
index d95092629a725af8b32439df5a10902da7567549..d6d5ac0947d8373cddc65967043f1f961dc5f9a8 100644 (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);
     }
index 677a3fd92ec898041dd09916ba1a4e340b42d43e..d785605f3cda6dd8f41b834d997c5a6bdf84811a 100644 (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);
 };
 
index 157bf1395305801c6d3f6fd374c3614880fa79f8..503ac56502ee6599449f00bf3a3c8ad521c06bab 100644 (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()
 {
index 1b22c5825c45db804c54782aefbcfba22b4b1218..876501be2579be25ac2c37d5fc0aa379a646a49d 100644 (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