So we've got a bit of a muddle with initialization, and I'm looking
for advice on how best to clean it up.

RIght now we have the following phases for initializing SimObjects:
1. user script calls instantiate()
   a. call constructors
   b. connect ports
   c. call init()
2. user script optionally calls restoreCheckpoint()
   a. call unserialize()
3. user script calls simulate() for the first time
   a. call startup()

The problem is that there's some initialization that doesn't fit this
model well.  The two similar cases I see are in Process and X86System,
where you have a set of threads assigned to the process/system, and
you need to identify one of them as the main thread and set it up to
run/boot, knowing that the other threads will get initialized later by
that main thread.

Right now this initialization happens in startup().  Unfortunately
that means that if you're not careful (as is currently the case with
X86System), you can clobber the state that you restored in
unserialize().  The Process hierarchy avoids this problem by setting a
flag in unserialize() to remember that the state was restored, and
then skipping most of startup() if the flag is set.  However this is
ad hoc (the flag only exists in Process), the code to check the flag
and skip setup() is replicated in each of the ISA-specific Process
derivatives (since it has to come before any ISA-specific
initialization), and obviously as the X86System case shows this makes
it very easy to get confused (in fact once I figured out the problem
with X86System it took a while to track down why it was that Process
didn't have this same problem).

Moving this initialization up into init() doesn't work directly, since
it has to happen after the System/Process object knows which threads
are assigned to it, but this relationship itself gets set up in the
init() phase, where BaseCPU::init() calls registerThreadContexts() on
the System/Process object.

I can think of several possible fixes:

1. Replicate the Process hack using the checkpointRestored flag in
X86System.  Two variants:
   a. Just do another one-off hack in System.
   b. Add a checkpointRestored flag to SimObject so every object has
one automatically.
2. Try to push registerThreadContexts() up into the BaseCPU
constructor, so the initialization code in question can be moved to
init().  I'm not 100% sure this will work, though I can't prove it
won't.  However, it seems fragile even if it does.  Also it means a
lot of redundant setup will be done in the cases where we do
ovewrwrite the state with a restored checkpoint, which may or may not
be a concern.
3. Add a phase to the initialization process to make this cleaner.
Possibilities:
   a. Add a second-stage init() call in step 1d so that we can keep
the code in question occurring after the current init(), but move it
before the checkpoint restore.
   b. Add a new call in step 3 before startup() that's only called on
objects that don't get unserialized (this is basically an
even-more-first-class variant of solution 1b above, since it moves the
checking of checkpointRestored up into SimObject as well).

Now that I've typed these options out and looked at them, I'm leaning
toward 3b.  Any comments?  Other ideas?  Preferences for a different
option?

On a more mundane note, I'd like to take the opportunity to get rid of
the StartupCallback class and integrate that code in SimObject, since
that's the only class that derives from it now.  (I think it was split
out to support the old defunct ParamContext class.)  Having everything
in SimObject makes the process clearer.

Steve
_______________________________________________
m5-dev mailing list
[email protected]
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to