Skip to content
This repository was archived by the owner on Nov 18, 2021. It is now read-only.

Commit 951ca6a

Browse files
author
Evan Weaver
committed
Merge branch 'preemptive_gc_api'
2 parents 584cdea + 19485ce commit 951ca6a

1 file changed

Lines changed: 60 additions & 17 deletions

File tree

gc.c

Lines changed: 60 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -698,11 +698,16 @@ static int heaps_used = 0;
698698
/* Too large a heap size and you can never free a page, due to fragmentation. Too
699699
small, and you have too many heaps and get stack errors. */
700700
static int heap_size = 32768;
701+
static int heap_increase_rate = 4;
702+
701703
static int eden_heaps = 24;
704+
static int eden_preemptive_heaps = 4;
705+
static int eden_preemptive_total_free_slots;
702706

703707
typedef struct heaps_space {
704-
int heap_slots_total;
705708
int num_heaps;
709+
unsigned int total_slots;
710+
unsigned int total_free_slots;
706711
enum lifetime lifetime;
707712
RVALUE *freelist;
708713
} heaps_space_t;
@@ -781,7 +786,11 @@ static void set_gc_parameters()
781786
#endif
782787

783788
SET_INT_ENV_VAR("RUBY_GC_HEAP_SIZE", heap_size)
789+
SET_INT_ENV_VAR("RUBY_GC_HEAP_INCREASE_RATE", heap_increase_rate)
784790
SET_INT_ENV_VAR("RUBY_GC_EDEN_HEAPS", eden_heaps)
791+
SET_INT_ENV_VAR("RUBY_GC_EDEN_PREEMPTIVE_HEAPS", eden_preemptive_heaps)
792+
793+
eden_preemptive_total_free_slots = eden_preemptive_heaps * heap_size;
785794

786795
WITH_FLOAT_ENV_VAR("RUBY_GC_LONGLIFE_LAZINESS", longlife_laziness)
787796
if (val >= 1) {
@@ -895,7 +904,8 @@ add_heap(heaps_space_t *heaps_space)
895904
if (himem < pend) {
896905
himem = pend;
897906
}
898-
heaps_space->heap_slots_total += new_heap_size;
907+
heaps_space->total_slots += new_heap_size;
908+
heaps_space->total_free_slots += new_heap_size;
899909
heaps_space->num_heaps++;
900910
heaps_used++;
901911

@@ -921,6 +931,7 @@ pop_freelist(heaps_space_t* heaps_space)
921931
{
922932
VALUE obj = (VALUE)heaps_space->freelist;
923933
heaps_space->freelist = heaps_space->freelist->as.free.next;
934+
heaps_space->total_free_slots--;
924935
RANY(obj)->as.free.next = 0;
925936
#ifdef GC_DEBUG
926937
MEMZERO((void*)obj, RVALUE, 1);
@@ -1763,18 +1774,25 @@ static int obj_free _((VALUE));
17631774
static void add_to_correct_freelist(RVALUE *p)
17641775
{
17651776
int longlived = OBJ_LONGLIVED(p);
1777+
heaps_space_t *heaps_space;
1778+
17661779
// Has explicit longlife flag
17671780
if(longlived) {
1768-
push_freelist(&longlife_heaps_space, p);
1781+
heaps_space = &longlife_heaps_space;
17691782
}
17701783
// Has some flags (so they weren't cleared), but not longlife
17711784
else if(p->as.free.flags != 0 && !longlived) {
1772-
push_freelist(&eden_heaps_space, p);
1785+
heaps_space = &eden_heaps_space;
17731786
}
17741787
// If all else fails, use slower is_pointer_to_longlife_heap()
1775-
else {
1776-
push_freelist(is_pointer_to_longlife_heap(p) ? &longlife_heaps_space : &eden_heaps_space, p);
1788+
else if (is_pointer_to_longlife_heap(p)) {
1789+
heaps_space = &longlife_heaps_space;
1790+
} else {
1791+
heaps_space = &eden_heaps_space;
17771792
}
1793+
1794+
push_freelist(heaps_space, p);
1795+
heaps_space->total_free_slots++;
17781796
}
17791797

17801798
static void
@@ -2129,13 +2147,14 @@ gc_sweep(heaps_space_t *heaps_space)
21292147
#endif
21302148
if (gc_debug_stress ||
21312149
/* Shrink longlife if it's too lazy */
2132-
(lt == lifetime_longlife && (total_free_slots > (heaps_space->heap_slots_total - heap->limit) * longlife_laziness)) ||
2150+
(lt == lifetime_longlife && (total_free_slots > (heaps_space->total_slots - heap->limit) * longlife_laziness)) ||
21332151
/* Shrink eden if there is a freeable heap and we are over our target size */
21342152
(lt == lifetime_eden && (heaps_space->num_heaps > eden_heaps))) {
21352153
GC_DEBUG_PRINTF(" %s heap freed (size %d)\n", heaps_space_name, heap->limit)
21362154
RVALUE *pp;
2137-
heaps_space->heap_slots_total -= heap->limit;
2155+
heaps_space->total_slots -= heap->limit;
21382156
heaps_space->num_heaps--;
2157+
total_free_slots -= heap->limit;
21392158
heap->limit = 0;
21402159
heap->slotlimit = heap->slot;
21412160
for (pp = final_list; pp != final; pp = pp->as.free.next) {
@@ -2146,18 +2165,19 @@ gc_sweep(heaps_space_t *heaps_space)
21462165
}
21472166
}
21482167

2149-
if ((lt == lifetime_longlife &&
2168+
for (i = 0;
2169+
i < heap_increase_rate &&
2170+
((lt == lifetime_longlife &&
21502171
/* Expand longlife if it's not lazy enough */
2151-
(total_free_slots < heaps_space->heap_slots_total * longlife_laziness)) ||
2172+
(total_free_slots < heaps_space->total_slots * longlife_laziness)) ||
21522173
(lt == lifetime_eden &&
2153-
/* Add one eden heap at a time (to reduce initial fragmentation) until we reach
2174+
/* Add four eden heaps at a time (to reduce initial fragmentation) until we reach
21542175
the target size */
2155-
(heaps_space->num_heaps < eden_heaps))) {
2176+
(heaps_space->num_heaps < eden_heaps)));
2177+
i++) {
21562178
new_heap_size = add_heap(heaps_space);
21572179
GC_DEBUG_PRINTF(" %s heap added (size %d)\n", heaps_space_name, new_heap_size)
2158-
#ifdef GC_DEBUG
21592180
total_free_slots += new_heap_size;
2160-
#endif
21612181
}
21622182

21632183
if (lt == lifetime_longlife) {
@@ -2181,11 +2201,14 @@ gc_sweep(heaps_space_t *heaps_space)
21812201
free_unused_heaps();
21822202
}
21832203

2204+
/* reset free slot count; we do it in bulk to avoid a cache penalty on every decrement */
2205+
heaps_space->total_free_slots = total_free_slots;
2206+
21842207
#ifdef GC_DEBUG
21852208
if (GC_DEBUG_ON) {
21862209
fprintf(gc_data_file, " %s heaps in heapspace: %8d\n", heaps_space_name, heaps_space->num_heaps);
21872210
fprintf(gc_data_file, " %s empty heaps: %8d\n", heaps_space_name, empty_heaps);
2188-
fprintf(gc_data_file, " %s total slots: %8lu\n", heaps_space_name, total_live_slots + total_free_slots);
2211+
fprintf(gc_data_file, " %s total slots: %8u\n", heaps_space_name, heaps_space->total_slots);
21892212
fprintf(gc_data_file, " %s already free slots: %8lu\n", heaps_space_name, total_already_freed_slots);
21902213
fprintf(gc_data_file, " %s finalized free slots: %8lu\n", heaps_space_name, total_finalized_slots);
21912214
fprintf(gc_data_file, " %s live objects: %8lu\n", heaps_space_name, total_live_slots);
@@ -2792,7 +2815,7 @@ garbage_collect_0(VALUE *top_frame)
27922815

27932816
/*** Schedule optional longlife GC based on allocation rate ***/
27942817

2795-
if (longlife_recent_allocations > longlife_heaps_space.heap_slots_total * longlife_laziness) {
2818+
if (longlife_recent_allocations > longlife_heaps_space.total_slots * longlife_laziness) {
27962819
longlife_collection = Qtrue;
27972820
}
27982821

@@ -2974,6 +2997,24 @@ rb_gc()
29742997
rb_gc_finalize_deferred();
29752998
}
29762999

3000+
VALUE
3001+
rb_gc_preemptive_start()
3002+
{
3003+
if (GC_DEBUG_ON) {
3004+
fprintf(gc_data_file, "*** Preemptive check ***\n");
3005+
fprintf(gc_data_file, " Eden slots: %8u\n", eden_heaps_space.total_slots);
3006+
fprintf(gc_data_file, " Free eden slots: %8u\n", eden_heaps_space.total_free_slots);
3007+
fprintf(gc_data_file, " Required free slots: %8u\n", eden_preemptive_total_free_slots);
3008+
}
3009+
if (eden_heaps_space.total_free_slots < eden_preemptive_total_free_slots) {
3010+
garbage_collect("preemptive collection request");
3011+
return Qtrue;
3012+
} else {
3013+
GC_DEBUG_PRINT(" Collection skipped\n");
3014+
return Qfalse;
3015+
}
3016+
}
3017+
29773018
/*
29783019
* call-seq:
29793020
* GC.start => nil
@@ -3132,7 +3173,8 @@ void ruby_init_stack(VALUE *addr
31323173

31333174
static void init_heaps_space(heaps_space_t* heaps_space, enum lifetime lifetime)
31343175
{
3135-
heaps_space->heap_slots_total = 0;
3176+
heaps_space->total_slots = 0;
3177+
heaps_space->total_free_slots = 0;
31363178
heaps_space->lifetime = lifetime;
31373179
}
31383180
/*
@@ -3664,6 +3706,7 @@ Init_GC()
36643706

36653707
rb_mGC = rb_define_module("GC");
36663708
rb_define_singleton_method(rb_mGC, "start", rb_gc_start, 0);
3709+
rb_define_singleton_method(rb_mGC, "preemptive_start", rb_gc_preemptive_start, 0);
36673710
rb_define_singleton_method(rb_mGC, "enable", rb_gc_enable, 0);
36683711
rb_define_singleton_method(rb_mGC, "disable", rb_gc_disable, 0);
36693712
rb_define_method(rb_mGC, "garbage_collect", rb_gc_start, 0);

0 commit comments

Comments
 (0)