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

Reply via email to