GC performance - was Re: [gclist] GC topics

Darius Blasband darius@phidani.be
Sat, 24 Feb 1996 14:06:03 +0100 (MET)


> 
> >Perhaps you should tell us how you keep track of pointers in YAFL.  We are
> >mixing together many issues here.  Assuming you are generating C code, I think
> >the possibilities are roughly:
> >
> >1) In the single-threaded case, you could explicitly keep a data structure that
> >allows the collector to find all roots.  All evidence I've seen so far suggests
> >that this costs on the order of a factor of 2 for pointer-intensive C/C++ code.
> >Either pointer assignments and/or pointer variable creation become expensive.
> >Much of the cost here is often associated with preventing the C compiler form
> >keeping pointer variables in registers.
> 
[Missed an intermediate message, I am afraid...]
  
Well, I am afraid this is a little long to explain in full length here,
Let's say that we use a rather naive system:

- First, some data dictionary information tells us at which offsets
  we have pointers within objects.
- All allocations refer to their meta class where so that I can mark
  an instance generically, by querying its attached metaclass.
- We keep 2 stacks: the reference stack and the value stack. Whenever
  we enter a method (understand function , procedure), the addresses
  of all locals and formals which might refer to separate allocations
  are pushed on the reference stack, and this stack's state is restored
  when exiting the method. The value stack is only required for
  short-lived objects before they can be referred to by a recognized
  reference (evaluating parameters before actually calling the function,
  for instance).
(I know that given the kind of vigorous talk which has been going on around
here recently, many might find this excessively simple, but the results
are pretty good)
- When the system want to reclaim memory, it marks all references accessible
  from these two stacks, and all references recursively accessible from
  these, and basically frees all the others.
  
Well, this is the basic idea behind YAFL's GC system. However, there
are several other things worth mentioning:

- We have our own allocator for small allocations which are allocated
  in fixed size slots within pages. These pages are allocated using
  malloc, and larger allocations use malloc as well. The rationale
  behind this was simply that since C is a very system-oriented language
  where performance has always been an issue, we can expect its
  allocator to be at least average. Frankly, so far, we accepted this
  as a fact of life, but we have not been investigating the true impact
  of the use of the standard C allocator for our purpose. We are conscious
  of the fact that it does limit our ability to implement some of the
  more sophisticated stuff which is sometimes mentioned in this mailing list.
- Pushing and popping on our two stacks can be done by using register 
  global variables as supported by gcc, typically on RISC machines. Well,
  William Nicora tried this on a SGI machine, and it happened to be much
  slower than the original scheme. I would not take this as an ultimate
  answer, and I think we can get better results if we plunge a bit more
  in the intricaties of GCC.
- YAFL's compiler is optimized in the sense that quite a lot
  of static analysis goes into finding methods which do not require
  that their locals and formals must be pushed on these stacks. The original
  compiler does this locally, and the global optimizer which has been built
  on top of YAFL does that globally. The global version is not in production
  yet, so I have no figures available...
- YAFL is a high-level language, which does not support "inside pointers".  
  Of course, it also makes things much simpler.


> 
> >  If you can do this with only 20%
> >overhead for pointer-intensive optimized C code, I'm impressed.
> 
> Anybody have stats on this?  
>
(If "this" refers to the stack management described above, yes I do).
It does indeed take just 20% of the execution time after careful measures...
Of course, there is nothing in YAFL which can really be compared with
"pointer-intensive" code in the C sense: references are implemented using
plain pointers, but there is no arithmetic with pointers (This is by far
not only a question of GC, it is a far more fundamental language design
issue).
 
Regards...

Darius