Hi Steve and Brandon, Per your emails on the other thread <http://permalink.gmane.org/gmane.comp.emulators.m5.devel/25402>:
Brandon: [...] I have also encountered problems with global/static > variables in Ruby as well. This past December, I spent a couple of weeks > trying to clean up the Ruby code so that we could invoke two instances of > Ruby at the same time in the simulator. It was not trivial as the problems > extended into slicc auto-generated code as well and I ended up temporarily > abandoning it. The high level code organization and design decisions > should not prevent us from doing simple straight-forward things like > invoking two Ruby instances at the same time. > When I was trying to solve the problem, I independently followed the same > method as Nilay. I added ruby system pointers to most of the objects so > that they could back-reference the system object (since it's the central > point of that Ruby instance) and obtain access to the other subsidiary > objects. I felt really dirty while writing the code and frankly the code > was painful to look at, but there didn't appear to be a better method (at > least not one that I could see). A couple of folks that I spoke with here > at AMD felt that the global/static variables needed to be fixed, but agreed > that there was no easy solution. Steve: I'm glad to have a discussion on the list if anyone has any great > ideas > about how we should enable multiple instantiations of Ruby other than the > approach Nilay and Brandon have taken; as Brandon says, it's ugly and > painful, but we don't really see any viable alternatives, and (for better > or for worse) abandoning the goal is simply not on the table for us. > I've thought a bit about this; In the past, I'd put together a couple patches to get some of the benefits of multiple Ruby instances. Overall, my impression is that Ruby just needs to better embrace gem5's component modularity principle in order to reduce or eliminate the ugly/painful aspects of the RubySystem. Here are some examples: 1) The global RubySystem pointer, g_system_ptr, is largely used to access its clock. This is very inconsistent with gem5 common practice: if a component needs a clock, give it its own clock. It would be a fair amount of refactoring, but it should be straightforward to remove the RubySystem's clock, change the Ruby components to ClockedObjects, and connect them to a common ClockDomain during their instantiation. I've implemented a bit of this to allow independent clock domains in Ruby cache hierarchies/network, and it's not really difficult. Taking this approach can also remove the generated code accesses to g_system_ptr. Many generated controllers set their component name by appending a statically-defined string onto the RubySystem's name. However, this naming process can already taken care of with gem5's SimObject Python parameter handling. Changing Ruby components to inherit from SimObject (e.g. through ClockedObject) will remove the need to access the g_system_ptr for component naming. 2) The RubySystem also contains common variables like cache block size and bits, and memory size. Currently, these variables are poorly scoped (static) in the RubySystem, when in fact, they are actually instance-specific: Simulating multiple separate RubySystems in a single simulation should allow, for example, cache block sizes to be different between the systems. Further, it's not actually true that cache block size needs to be consistent throughout a single cache hierarchy (though there would be numerous challenges to allowing multiple block sizes within Ruby). To move toward both these goals, I'd suggest taking a page from the classic memory hierarchy: Remove these variables from the RubySystem and distribute them to Ruby components. ^^ These first two things alone would eliminate >90% of references to the g_system_ptr and RubySystem static members/functions, and in so doing, eliminate most of the hairy scoping problems for multithreading and/or multiple RubySystem instances. 3) The remaining references to the RubySystem are to perform 4 operations: (A) recording cache contents when taking a checkpoint, (B) warming up caches from a trace during checkpoint restore, (C) profiling memory accesses, and (D) functional memory accesses. These operations are aggregated within the RubySystem, because they perform functionality across many Ruby components. As currently architected, with the exception of (C), these could all be performed without any Ruby subcomponents maintaining pointers to the RubySystem. The RubySystem just needs pointers to its subcomponents as is already does. Profiling is partially disaggregated across the sequencers in this direction, but it too looks like it could be completely disaggregated to be performed by the RubySystem rather than the components calling into the RubySystem. The big question left is whether the community wants each of these RubySystem functionalities to be per-RubySystem-instance, or if they should be simulation-wide functionality. Based on the way that the RubySystem accesses components for each of these operations, it looks like it would be very straightforward to make these per-RubySystem-instance operations. This would also provide the most flexibility to use multiple separate systems with their own stats, cache warmup traces, and independent functional access paths. Overall, when actually implementing this, I'm sure there will be other tricky parts to address. However, up to this point, I don't see any real gotchas that would make RubySystem cleaning truly ugly/painful. I'd probably need more context to know if I'd have any thoughts to offer RE: SLICC challenges. Joel -- Joel Hestness PhD Candidate, Computer Architecture Dept. of Computer Science, University of Wisconsin - Madison http://pages.cs.wisc.edu/~hestness/ _______________________________________________ gem5-dev mailing list [email protected] http://m5sim.org/mailman/listinfo/gem5-dev
