* GC improvements
@ 2005-12-20 16:32 Ludovic Courtès
2005-12-23 11:29 ` Han-Wen Nienhuys
0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2005-12-20 16:32 UTC (permalink / raw)
Hi,
I did some profiling with the workload I described earlier[0].
When using the three patches I sent recently[*], around 35% of the
execution time is spent in memory management:
% cumulative self self total
time seconds seconds calls s/call s/call name
28.10 16.63 16.63 41385 0.00 0.00 ceval
18.02 27.29 10.66 32399 0.00 0.00 scm_i_sweep_card
8.54 32.34 5.06 4729114 0.00 0.00 scm_cell
5.11 35.37 3.03 2737955 0.00 0.00 scm_ilookup
3.23 37.28 1.91 7086 0.00 0.00 scm_i_init_card_freelist
2.96 39.03 1.75 383266 0.00 0.00 scm_gc_mark_dependencies
2.64 40.59 1.56 657 0.00 0.01 scm_i_mark_weak_vector_non_weak
Commenting out explicit calls to `scm_gc ()' and `scm_i_gc ()' doesn't
make a big difference.
The workload I used is quite similar to what happens at startup time:
new objects are created, new symbols are defined, and that's it. The
symbols created (and even the numbers created) are expected to stay
alive until the end of the program. Thus, intuitively, one might say
that there is nothing to collect in this program, so no need to
mark/sweep all the time.
Therefore, my question is: how can we improve on this?
As I understand it, generational GC could help solve this. However,
being unfamiliar with this, I fail to see how this could be integrated,
and how much work is required.
Thanks,
Ludovic.
[0] http://lists.gnu.org/archive/html/guile-devel/2005-12/msg00093.html
[*] Improved `scm_from_locale_symbol ()' + `guile-reader', fixed
FREE_COUNT in `scm_i_sweep_card ()', fixed CELLS_COLLECTED in
`scm_i_sweep_some_cards ()')
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2005-12-20 16:32 GC improvements Ludovic Courtès
@ 2005-12-23 11:29 ` Han-Wen Nienhuys
2005-12-23 15:40 ` 1.8 [was: GC improvements] Andy Wingo
2006-01-03 10:16 ` GC improvements Ludovic Courtès
0 siblings, 2 replies; 9+ messages in thread
From: Han-Wen Nienhuys @ 2005-12-23 11:29 UTC (permalink / raw)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1722 bytes --]
In article <87slsnk9u0.fsf@laas.fr>,
Ludovic Courtès <ludovic.courtes@laas.fr> wrote:
>The workload I used is quite similar to what happens at startup time:
>new objects are created, new symbols are defined, and that's it. The
>symbols created (and even the numbers created) are expected to stay
>alive until the end of the program. Thus, intuitively, one might say
>that there is nothing to collect in this program, so no need to
>mark/sweep all the time.
I think that GUILE creates garbage as a side effect of evaluating
code. If think that nothing needs to be swept, try disabling GC during
startup, and see how well it performs memory-wise.
>Therefore, my question is: how can we improve on this?
>
>As I understand it, generational GC could help solve this. However,
>being unfamiliar with this, I fail to see how this could be integrated,
>and how much work is required.
For startup time, I think the best (as in: quickest) would be undump a
previous run, instead of recalculating all the initialization on every
run. Not only does this save on GC time, it also bypasses all evaluation.
Isn't this what Emacs also does?
Personally, I think it is much more interesting to optimize for
efficiency on longer projects.
BTW, I propose that the GC yields are changed a bit. I've heard other
people comment that GUILE is dead slow compared to PLT Scheme. I've
investigated with one Boehm's GC benchmarks, and for this case it
turns out that increasing GC minimum yields sped GUILE up by a factor
1.5 or so.
Han-Wen
P.S. what's keeping back the GUILE 1.8 release?
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* 1.8 [was: GC improvements]
2005-12-23 11:29 ` Han-Wen Nienhuys
@ 2005-12-23 15:40 ` Andy Wingo
2005-12-24 0:59 ` 1.8 Kevin Ryde
2006-01-03 10:16 ` GC improvements Ludovic Courtès
1 sibling, 1 reply; 9+ messages in thread
From: Andy Wingo @ 2005-12-23 15:40 UTC (permalink / raw)
Hi Han-Wen,
On Fri, 2005-12-23 at 11:29 +0000, Han-Wen Nienhuys wrote:
> P.S. what's keeping back the GUILE 1.8 release?
My guess:
1) Marius' time being eaten by work ;-)
2) Lingering GC bugs
3) Lack of a threadsafety audit (although it's tough to say how this
would affect API; e.g. it shouldn't hold back the release)
BTW, I just compiled guile-gnome against 1.7. Seems to run OK, but I get
a segfault in one of the test suites, deep in GC. And of course as I
noted it doesn't even build on x86-64. Will do some bisection when I'm
back from holidays.
Regards,
--
Andy Wingo
http://wingolog.org/
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: 1.8
2005-12-23 15:40 ` 1.8 [was: GC improvements] Andy Wingo
@ 2005-12-24 0:59 ` Kevin Ryde
0 siblings, 0 replies; 9+ messages in thread
From: Kevin Ryde @ 2005-12-24 0:59 UTC (permalink / raw)
Cc: guile-devel
Andy Wingo <wingo@pobox.com> writes:
>
> My guess:
4) Under debug-cell-accesses, goops.test is throwing
Non-pair accessed with SCM_C[AD]R: `#<<class> <foo> b7baf270>'
but I don't know if that's benign in practice.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2005-12-23 11:29 ` Han-Wen Nienhuys
2005-12-23 15:40 ` 1.8 [was: GC improvements] Andy Wingo
@ 2006-01-03 10:16 ` Ludovic Courtès
2006-01-04 1:03 ` Han-Wen Nienhuys
1 sibling, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2006-01-03 10:16 UTC (permalink / raw)
Cc: guile-devel
hanwen@byrd.xs4all.nl (Han-Wen Nienhuys) writes:
> I think that GUILE creates garbage as a side effect of evaluating
> code. If think that nothing needs to be swept, try disabling GC during
> startup, and see how well it performs memory-wise.
I did try commenting out all calls to `scm_i_gc ()' and running my
workload again. Actually, it doesn't make a big difference: a lot of
time is still spent in `scm_i_sweep_card ()', called from
`scm_i_sweep_some_cards ()' and friends.
> For startup time, I think the best (as in: quickest) would be undump a
> previous run, instead of recalculating all the initialization on every
> run. Not only does this save on GC time, it also bypasses all evaluation.
> Isn't this what Emacs also does?
Don't know, we'd have to investigate further. Still, that wouldn't fix
our greedy-GC problem.
Thanks,
Ludovic.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2006-01-03 10:16 ` GC improvements Ludovic Courtès
@ 2006-01-04 1:03 ` Han-Wen Nienhuys
2006-01-04 16:18 ` Ludovic Courtès
0 siblings, 1 reply; 9+ messages in thread
From: Han-Wen Nienhuys @ 2006-01-04 1:03 UTC (permalink / raw)
Cc: guile-devel
Ludovic Courtès wrote:
> hanwen@byrd.xs4all.nl (Han-Wen Nienhuys) writes:
>
>
>>I think that GUILE creates garbage as a side effect of evaluating
>>code. If think that nothing needs to be swept, try disabling GC during
>>startup, and see how well it performs memory-wise.
>
>
> I did try commenting out all calls to `scm_i_gc ()' and running my
> workload again. Actually, it doesn't make a big difference: a lot of
> time is still spent in `scm_i_sweep_card ()', called from
> `scm_i_sweep_some_cards ()' and friends.
the easiest way is to modify
scm_gc_for_newcell()
so it directly passes to the
scm_i_get_new_heap_segment (freelist, abort_on_error);
case
--
Han-Wen Nienhuys - hanwen@xs4all.nl - http://www.xs4all.nl/~hanwen
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2006-01-04 1:03 ` Han-Wen Nienhuys
@ 2006-01-04 16:18 ` Ludovic Courtès
2006-01-05 14:47 ` Ludovic Courtès
0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2006-01-04 16:18 UTC (permalink / raw)
Cc: guile-devel
Hi Han-Wen,
Thanks for your input!
Han-Wen Nienhuys <hanwen@xs4all.nl> writes:
> the easiest way is to modify
>
> scm_gc_for_newcell()
>
>
> so it directly passes to the
>
> scm_i_get_new_heap_segment (freelist, abort_on_error);
>
> case
No, that won't have any impact because this very case is rarely
reached.
I checked this by adding two (static) counters to `scm_gc_for_newcell ()':
one that counts the number of calls, and one that counts the number of
non-EOL returns of the first `scm_i_sweep_some_segments ()' call. The
ratio (still for the same workload) is _always_ very, very close to 1.
This is because `scm_i_sweep_some_segments ()' does not actually only
sweep segments: it sometimes (actually here, most of the time)
*initializes* them. The reason is that it uses `scm_i_sweep_some_cards ()'
which in turn chooses whether to initialize or sweep depending on
whether the segment at hand is already initialized (SWEEPER is chosen
based on SEG->FIRST_TIME).
This interleaving of initialization and sweeping makes it pretty hard to
track exactly where fresh cells come from. I guess one solution might
be to maintain a list of the uninitialized segments and pick cells
directly from there before actually sweeping.
To be continued... Hopefully! ;-)
Thanks,
Ludovic.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2006-01-04 16:18 ` Ludovic Courtès
@ 2006-01-05 14:47 ` Ludovic Courtès
2006-01-06 20:22 ` Han-Wen Nienhuys
0 siblings, 1 reply; 9+ messages in thread
From: Ludovic Courtès @ 2006-01-05 14:47 UTC (permalink / raw)
Cc: guile-devel
Hi,
ludovic.courtes@laas.fr (Ludovic Courtès) writes:
> This interleaving of initialization and sweeping makes it pretty hard to
> track exactly where fresh cells come from. I guess one solution might
> be to maintain a list of the uninitialized segments and pick cells
> directly from there before actually sweeping.
Thinking about it, this solution looks like the beginning of the
generational approach to GC: we'd define uninitialized segments (i.e.,
those whose FIRST_TIME field is true) as one generation, and the others
as another generation.
I think we could even have 3 segment generations:
1. The kids, i.e., the uninitialized segments;
2. The youngsters, i.e., segments recently initialized and where
sweeping gave good results in the past;
3. The elderly, i.e., those for which sweeping has been unproductive for
some time already.
Remarks:
* This is a very coarse approach to generational GC as it's done on a
per-segment basis. For this reason, it doesn't make sense to have
more that 3 generations (due to fragmentation, each segment may
include a variety of kids, youngsters, and elderly). Even 3
generations (instead of just 2) is a questionable approach.
OTOH, even though there is fragmentation, I think it's reasonable to
assume that some segments, those created and populated at startup
time, will actually only contain elderly cells, whereas segments
initialized during the life time of the program (especially for
long-running or interactive applications) may be more fragmented and
may be considered as "young". Hence the intermediary generation.
Additionally, I'm assuming that elderly segments cannot move back to
the "youngsters" generation, which seems to be generally assumed in
generational GC.
* This poor man's generational GC has the advantage of being quite easy
to implement. Basically, instead of having a single segment table as
we have now, we'd have to maintain a set of three segment tables,
which would not be too complicated it seems.
In particular, it's much easier to implement than the per-cell
generational GC, as proposed by Greg Harvey in
http://home.thezone.net/~gharvey/guile/ggc-notes.txt . It's also less
intrusive: basically `scm_i_sweep_some_segments ()' is the only place
where generations would be taken into account. Of course, the outcome
would certainly be better with a per-cell approach, but I'd expect the
per-segment approach to yield a non-null benefit for a pretty low
cost.
What do you think? Are there flaws in this reasoning? :-)
Thanks,
Ludovic.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: GC improvements
2006-01-05 14:47 ` Ludovic Courtès
@ 2006-01-06 20:22 ` Han-Wen Nienhuys
0 siblings, 0 replies; 9+ messages in thread
From: Han-Wen Nienhuys @ 2006-01-06 20:22 UTC (permalink / raw)
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 1978 bytes --]
In article <87psn64tq5.fsf@laas.fr>,
Ludovic Courtès <ludovic.courtes@laas.fr> wrote:
>> This interleaving of initialization and sweeping makes it pretty hard to
>> track exactly where fresh cells come from. I guess one solution might
>> be to maintain a list of the uninitialized segments and pick cells
>> directly from there before actually sweeping.
>* This poor man's generational GC has the advantage of being quite easy
> to implement. Basically, instead of having a single segment table as
> we have now, we'd have to maintain a set of three segment tables,
> which would not be too complicated it seems.
>
> In particular, it's much easier to implement than the per-cell
> generational GC, as proposed by Greg Harvey in
> http://home.thezone.net/~gharvey/guile/ggc-notes.txt . It's also less
> intrusive: basically `scm_i_sweep_some_segments ()' is the only place
> where generations would be taken into account. Of course, the outcome
> would certainly be better with a per-cell approach, but I'd expect the
> per-segment approach to yield a non-null benefit for a pretty low
> cost.
I don't get it. I thought the generational would save on the marking
phase. What's sweeping got to do with it?
>What do you think? Are there flaws in this reasoning? :-)
Yes; it's reasoning. In my experience, nice sounding theories and
approaches are usually meaningless. Programmers (including myself) are
notoriously bad at predicting performance characteristics. Why don't
you do some measurements before trying to design code?
I've tried "poor man's" optimizations before, and I always had to
conclude that optimizations introduced extra overhead, with a net loss
in performance. that
If you want to have generational GC, I recommend to plug in Boehms GC
collector. MzScheme also does this with good results.
_______________________________________________
Guile-devel mailing list
Guile-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/guile-devel
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2006-01-06 20:22 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-12-20 16:32 GC improvements Ludovic Courtès
2005-12-23 11:29 ` Han-Wen Nienhuys
2005-12-23 15:40 ` 1.8 [was: GC improvements] Andy Wingo
2005-12-24 0:59 ` 1.8 Kevin Ryde
2006-01-03 10:16 ` GC improvements Ludovic Courtès
2006-01-04 1:03 ` Han-Wen Nienhuys
2006-01-04 16:18 ` Ludovic Courtès
2006-01-05 14:47 ` Ludovic Courtès
2006-01-06 20:22 ` Han-Wen Nienhuys
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).