So I think I figured out the right way to handle drain, but I don't know how
soon I'll have time to get to it, so I wanted to write it down and send it
out for feedback, in case someone else has time to do it, and so I don't
forget what I came up with.  So here's the idea:

Basically the C++ mechanisms all hang off of SimObject, so any SimObject can
serve as the root of a subtree that gets drained.  The "callback" pointer
that gets passed to each SimObject's drain() method is just the pointer to
the root of the hierarchy that's being drained; when the object wants to
invoke the callback, it calls a specific new method on that root SimObject
(like notifyDrainComplete() or something) that replaces the current
DrainEvent::process() method.

As I mentioned before, this logically requires an extra int per SimObject so
that the SimObject can maintain the drain count while it's acting as root.
Given that this is not performance critical, I suggest we have a global data
structure that's logically a map from SimObject* to int.  Then when we
initiate a drain we just allocate a <SimObject*,int> pair for the root and
use that as the drain counter, and we can deallocate it when the drain is
over.  In the near term since we don't support concurrent drains we could
simplify this as just two global variables, the drain count and a SimObject*
just to track the current root and print a warning if someone does manage to
fire off two concurrent drains somehow.

I'll even provide the diff for the Python side of the change:

--- a/src/python/m5/simulate.py
+++ b/src/python/m5/simulate.py
@@ -147,15 +147,13 @@
 # be drained.
 def drain(root):
     all_drained = False
-    drain_event = internal.event.createCountedDrain()
-    unready_objs = sum(obj.drain(drain_event) for obj in
root.descendants())
+    unready_objs = sum(obj.drain(root) for obj in root.descendants())
     # If we've got some objects that can't drain immediately, then simulate
     if unready_objs > 0:
-        drain_event.setCount(unready_objs)
+        root.setDrainCount(unready_objs)
         simulate()
     else:
         all_drained = True
-    internal.event.cleanupCountedDrain(drain_event)
     return all_drained

(Not counting all the CountedDrainEvent swig stuff that can get whacked.)

One nice side-effect is that we don't have to expose any particular callback
or event object to python for it to allocate dynamically... whatever dynamic
allocation happens is hidden behind the SimObject interface.  (I know Nate
will say this isn't hard, but I still feel like we should be keeping the
python/c++ interface as narrow and clean as possible.)

Another nice thing about this setup is that once a node knows that it is the
root of a drain, it can easily detect if a drain is started somewhere
further up the hierarchy, and in the long run maybe we'd want to do
something to combine the two drain operations dynamically.  We don't need to
figure out the details yet, but I feel like this puts us in a good position
to handle it intelligently if we need to.

Steve
_______________________________________________
m5-dev mailing list
m5-dev@m5sim.org
http://m5sim.org/mailman/listinfo/m5-dev

Reply via email to