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