aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-03-31 08:21:35 +0000
committerko1 <ko1@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2016-03-31 08:21:35 +0000
commit49369ef17316cd5d5819b038f286e1d951972b52 (patch)
tree066c6523eeac5b5c6ccd3d348ffdf681c7b05d70
parent555f6cb089a63204587fb7555ce92751d28ec89f (diff)
downloadruby-49369ef17316cd5d5819b038f286e1d951972b52.tar.gz
* gc.c: simplify allocate/free detecting logic at the end of marking.
Before this change, heap_pages_min_slots are calculated at the beggining sweeping phase. And this value is used at the end of *next* marking phase. To simplify it, we use this value at the end of this marking phase. It means that we don't need to store this value as global state. Also heap_pages_max_slots is calculated at the begging of sweeping phase and used at the end of sweeping phase. To simplify this logic, we introduced new global value heap_pages_freeable_pages it means extra pages count we can free. gc_sweep_step() checks this value and moves empty pages to tomb_heap not more than this value. Because of this fix, heap_pages_swept_slots is no longer needed. * gc.c (rb_objspace_t::heap_pages): restruct the objspace global status. remove the following fileds * swept_slots (and heap_pages_swept_slots) * min_free_slots (and heap_pages_min_free_slots) * max_free_slots (and heap_pages_max_free_slots) And add the following filed. * freeable_pages (and heap_pages_freeable_pages) * gc.c (heap_pages_free_unused_pages): unlink tomb heap pages because tomb heap should have only freeable pages. * gc.c (heap_extend_pages): add parameters for future extension. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@54451 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog35
-rw-r--r--gc.c133
2 files changed, 97 insertions, 71 deletions
diff --git a/ChangeLog b/ChangeLog
index 82e58d4b6f..ae14ca9412 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+Thu Mar 31 16:49:36 2016 Koichi Sasada <ko1@atdot.net>
+
+ * gc.c: simplify allocate/free detecting logic at the end of marking.
+
+ Before this change, heap_pages_min_slots are calculated at the
+ beggining sweeping phase. And this value is used at the end of
+ *next* marking phase.
+
+ To simplify it, we use this value at the end of this marking phase.
+ It means that we don't need to store this value as global state.
+
+ Also heap_pages_max_slots is calculated at the begging of sweeping
+ phase and used at the end of sweeping phase.
+ To simplify this logic, we introduced new global value
+ heap_pages_freeable_pages it means extra pages count we can free.
+ gc_sweep_step() checks this value and moves empty pages to tomb_heap
+ not more than this value.
+
+ Because of this fix, heap_pages_swept_slots is no longer needed.
+
+ * gc.c (rb_objspace_t::heap_pages): restruct the objspace global
+ status.
+
+ remove the following fileds
+ * swept_slots (and heap_pages_swept_slots)
+ * min_free_slots (and heap_pages_min_free_slots)
+ * max_free_slots (and heap_pages_max_free_slots)
+ And add the following filed.
+ * freeable_pages (and heap_pages_freeable_pages)
+
+ * gc.c (heap_pages_free_unused_pages): unlink tomb heap pages
+ because tomb heap should have only freeable pages.
+
+ * gc.c (heap_extend_pages): add parameters for future extension.
+
Thu Mar 31 16:43:02 2016 Koichi Sasada <ko1@atdot.net>
* gc.c: add GC parameters to configure the following values:
diff --git a/gc.c b/gc.c
index 9a614ff1ce..170964b957 100644
--- a/gc.c
+++ b/gc.c
@@ -541,10 +541,7 @@ typedef struct rb_objspace {
size_t allocatable_pages;
size_t sorted_length;
RVALUE *range[2];
-
- size_t swept_slots;
- size_t min_free_slots;
- size_t max_free_slots;
+ size_t freeable_pages;
/* final */
size_t final_slots;
@@ -724,10 +721,8 @@ VALUE *ruby_initial_gc_stress_ptr = &ruby_initial_gc_stress;
#define heap_pages_sorted_length objspace->heap_pages.sorted_length
#define heap_pages_lomem objspace->heap_pages.range[0]
#define heap_pages_himem objspace->heap_pages.range[1]
-#define heap_pages_swept_slots objspace->heap_pages.swept_slots
#define heap_allocatable_pages objspace->heap_pages.allocatable_pages
-#define heap_pages_min_free_slots objspace->heap_pages.min_free_slots
-#define heap_pages_max_free_slots objspace->heap_pages.max_free_slots
+#define heap_pages_freeable_pages objspace->heap_pages.freeable_pages
#define heap_pages_final_slots objspace->heap_pages.final_slots
#define heap_pages_deferred_final objspace->heap_pages.deferred_final
#define heap_eden (&objspace->eden_heap)
@@ -1452,27 +1447,20 @@ heap_pages_free_unused_pages(rb_objspace_t *objspace)
{
size_t i, j;
- if (heap_tomb->pages && heap_pages_swept_slots > heap_pages_max_free_slots) {
+ if (heap_tomb->pages) {
for (i = j = 1; j < heap_allocated_pages; i++) {
struct heap_page *page = heap_pages_sorted[i];
if (page->flags.in_tomb && page->free_slots == page->total_slots) {
- if (heap_pages_swept_slots - page->total_slots > heap_pages_max_free_slots) {
- if (0) fprintf(stderr, "heap_pages_free_unused_pages: %d free page %p, heap_pages_swept_slots: %d, heap_pages_max_free_slots: %d\n",
- (int)i, page, (int)heap_pages_swept_slots, (int)heap_pages_max_free_slots);
- heap_pages_swept_slots -= page->total_slots;
- heap_unlink_page(objspace, heap_tomb, page);
- heap_page_free(objspace, page);
- continue;
- }
- else if (i == j) {
- return; /* no need to check rest pages */
- }
+ heap_unlink_page(objspace, heap_tomb, page);
+ heap_page_free(objspace, page);
}
- if (i != j) {
- heap_pages_sorted[j] = page;
+ else {
+ if (i != j) {
+ heap_pages_sorted[j] = page;
+ }
+ j++;
}
- j++;
}
if (RGENGC_CHECK_MODE) assert(j == heap_allocated_pages);
}
@@ -1613,7 +1601,7 @@ heap_add_pages(rb_objspace_t *objspace, rb_heap_t *heap, size_t add)
}
static size_t
-heap_extend_pages(rb_objspace_t *objspace)
+heap_extend_pages(rb_objspace_t *objspace, size_t free_slots, size_t total_slots)
{
size_t used = heap_allocated_pages - heap_tomb->total_pages;
size_t next_used_limit = (size_t)(used * gc_params.growth_factor);
@@ -2735,7 +2723,6 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
page->free_slots++;
heap_page_add_freeobj(objspace, GET_HEAP_PAGE(zombie), zombie);
- heap_pages_swept_slots++;
objspace->profile.total_freed_objects++;
zombie = next_zombie;
@@ -3455,7 +3442,7 @@ gc_page_sweep(rb_objspace_t *objspace, rb_heap_t *heap, struct heap_page *sweep_
(int)sweep_page->total_slots,
freed_slots, empty_slots, final_slots);
- heap_pages_swept_slots += sweep_page->free_slots = freed_slots + empty_slots;
+ sweep_page->free_slots = freed_slots + empty_slots;
objspace->profile.total_freed_objects += freed_slots;
heap_pages_final_slots += final_slots;
sweep_page->final_slots += final_slots;
@@ -3537,40 +3524,16 @@ __attribute__((noinline))
static void
gc_sweep_start(rb_objspace_t *objspace)
{
- rb_heap_t *heap;
- size_t total_limit_slot;
-
gc_mode_transition(objspace, gc_mode_sweeping);
-
- /* sometimes heap_allocatable_pages is not 0 */
- heap_pages_swept_slots = heap_allocatable_pages * HEAP_PAGE_OBJ_LIMIT;
- total_limit_slot = objspace_available_slots(objspace);
-
- heap_pages_min_free_slots = (size_t)(total_limit_slot * gc_params.heap_free_slots_min_ratio);
- if (heap_pages_min_free_slots < gc_params.heap_free_slots) {
- heap_pages_min_free_slots = gc_params.heap_free_slots;
- }
- heap_pages_max_free_slots = (size_t)(total_limit_slot * gc_params.heap_free_slots_max_ratio);
- if (heap_pages_max_free_slots < gc_params.heap_init_slots) {
- heap_pages_max_free_slots = gc_params.heap_init_slots;
- }
- if (0) fprintf(stderr, "heap_pages_min_free_slots: %d, heap_pages_max_free_slots: %d\n",
- (int)heap_pages_min_free_slots, (int)heap_pages_max_free_slots);
-
- heap = heap_eden;
- gc_sweep_start_heap(objspace, heap);
+ gc_sweep_start_heap(objspace, heap_eden);
}
static void
gc_sweep_finish(rb_objspace_t *objspace)
{
- rb_heap_t *heap = heap_eden;
-
- gc_report(1, objspace, "gc_sweep_finish: heap->total_slots: %d, heap->swept_slots: %d, min_free_slots: %d\n",
- (int)heap->total_slots, (int)heap_pages_swept_slots, (int)heap_pages_min_free_slots);
+ gc_report(1, objspace, "gc_sweep_finish");
gc_prof_set_heap_info(objspace);
-
heap_pages_free_unused_pages(objspace);
/* if heap_pages has unused pages, then assign them to increment */
@@ -3610,7 +3573,9 @@ gc_sweep_step(rb_objspace_t *objspace, rb_heap_t *heap)
int free_slots = gc_page_sweep(objspace, heap, sweep_page);
if (sweep_page->final_slots + free_slots == sweep_page->total_slots &&
+ heap_pages_freeable_pages > 0 &&
unlink_limit > 0) {
+ heap_pages_freeable_pages--;
unlink_limit--;
/* there are no living objects -> move this page to tomb heap */
heap_unlink_page(objspace, heap, sweep_page);
@@ -5392,35 +5357,60 @@ gc_marks_finish(rb_objspace_t *objspace)
gc_marks_check(objspace, gc_check_after_marks_i, "after_marks");
#endif
- { /* decide full GC is needed or not */
+ {
+ /* decide full GC is needed or not */
rb_heap_t *heap = heap_eden;
- size_t sweep_slots =
- (heap_allocatable_pages * HEAP_PAGE_OBJ_LIMIT) + /* allocatable slots in empty pages */
- (heap->total_slots - objspace->marked_slots); /* will be sweep slots */
+ size_t total_slots = heap_allocatable_pages * HEAP_PAGE_OBJ_LIMIT + heap->total_slots;
+ size_t sweep_slots = total_slots - objspace->marked_slots; /* will be swept slots */
+ size_t max_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_max_ratio);
+ size_t min_free_slots = (size_t)(total_slots * gc_params.heap_free_slots_min_ratio);
+ int full_marking = is_full_marking(objspace);
#if RGENGC_CHECK_MODE
assert(heap->total_slots >= objspace->marked_slots);
#endif
- if (sweep_slots < heap_pages_min_free_slots) {
+ /* setup free-able page counts */
+ if (max_free_slots < gc_params.heap_init_slots) max_free_slots = gc_params.heap_init_slots;
+
+ if (sweep_slots > max_free_slots) {
+ heap_pages_freeable_pages = (sweep_slots - max_free_slots) / HEAP_PAGE_OBJ_LIMIT;
+ }
+ else {
+ heap_pages_freeable_pages = 0;
+ }
+
+ /* check free_min */
+ if (min_free_slots < gc_params.heap_free_slots) min_free_slots = gc_params.heap_free_slots;
+
+ if (sweep_slots < min_free_slots) {
#if USE_RGENGC
- if (!is_full_marking(objspace) && objspace->profile.count - objspace->rgengc.last_major_gc > 3 /* magic number */) {
- gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
- objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ if (!full_marking) {
+ if (objspace->profile.count - objspace->rgengc.last_major_gc < RVALUE_OLD_AGE) {
+ full_marking = TRUE;
+ /* do not update last_major_gc, because full marking is not done. */
+ goto increment;
+ }
+ else {
+ gc_report(1, objspace, "gc_marks_finish: next is full GC!!)\n");
+ objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_NOFREE;
+ }
}
else {
+ increment:
gc_report(1, objspace, "gc_marks_finish: heap_set_increment!!\n");
- heap_set_increment(objspace, heap_extend_pages(objspace));
+ heap_set_increment(objspace, heap_extend_pages(objspace, sweep_slots, total_slots));
heap_increment(objspace, heap);
}
-#else
- gc_report(1, objspace, "gc_marks_finish: heap_set_increment!!\n");
- heap_set_increment(objspace, heap_extend_pages(objspace));
- heap_increment(objspace, heap);
-#endif
}
-#if USE_RGENGC
+ if (full_marking) {
+ /* See the comment about RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR */
+ const double r = gc_params.oldobject_limit_factor;
+ objspace->rgengc.uncollectible_wb_unprotected_objects_limit = (size_t)(objspace->rgengc.uncollectible_wb_unprotected_objects * r);
+ objspace->rgengc.old_objects_limit = (size_t)(objspace->rgengc.old_objects * r);
+ }
+
if (objspace->rgengc.uncollectible_wb_unprotected_objects > objspace->rgengc.uncollectible_wb_unprotected_objects_limit) {
objspace->rgengc.need_major_gc |= GPR_FLAG_MAJOR_BY_SHADY;
}
@@ -5434,7 +5424,13 @@ gc_marks_finish(rb_objspace_t *objspace)
gc_report(1, objspace, "gc_marks_finish (marks %d objects, old %d objects, total %d slots, sweep %d slots, increment: %d, next GC: %s)\n",
(int)objspace->marked_slots, (int)objspace->rgengc.old_objects, (int)heap->total_slots, (int)sweep_slots, (int)heap_allocatable_pages,
objspace->rgengc.need_major_gc ? "major" : "minor");
+
+#else /* USE_RGENGC */
+ gc_report(1, objspace, "gc_marks_finish: heap_set_increment!!\n");
+ heap_set_increment(objspace, heap_extend_pages(objspace, sweep_slot, total_slot));
+ heap_increment(objspace, heap);
#endif
+ }
}
gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_END_MARK, 0);
@@ -6756,7 +6752,6 @@ enum gc_stat_sym {
gc_stat_sym_heap_free_slots,
gc_stat_sym_heap_final_slots,
gc_stat_sym_heap_marked_slots,
- gc_stat_sym_heap_swept_slots,
gc_stat_sym_heap_eden_pages,
gc_stat_sym_heap_tomb_pages,
gc_stat_sym_total_allocated_pages,
@@ -6833,7 +6828,6 @@ setup_gc_stat_symbols(void)
S(heap_free_slots);
S(heap_final_slots);
S(heap_marked_slots);
- S(heap_swept_slots);
S(heap_eden_pages);
S(heap_tomb_pages);
S(total_allocated_pages);
@@ -6905,7 +6899,6 @@ setup_gc_stat_symbols(void)
rb_hash_aset(table, OLD_SYM(heap_live_slot), NEW_SYM(heap_live_slots));
rb_hash_aset(table, OLD_SYM(heap_free_slot), NEW_SYM(heap_free_slots));
rb_hash_aset(table, OLD_SYM(heap_final_slot), NEW_SYM(heap_final_slots));
- rb_hash_aset(table, OLD_SYM(heap_swept_slot), NEW_SYM(heap_swept_slots));
#if USE_RGEGC
rb_hash_aset(table, OLD_SYM(remembered_shady_object), NEW_SYM(remembered_wb_unprotected_objects));
rb_hash_aset(table, OLD_SYM(remembered_shady_object_limit), NEW_SYM(remembered_wb_unprotected_objects_limit));
@@ -7007,7 +7000,6 @@ gc_stat_internal(VALUE hash_or_sym)
SET(heap_free_slots, objspace_free_slots(objspace));
SET(heap_final_slots, heap_pages_final_slots);
SET(heap_marked_slots, objspace->marked_slots);
- SET(heap_swept_slots, heap_pages_swept_slots);
SET(heap_eden_pages, heap_eden->total_pages);
SET(heap_tomb_pages, heap_tomb->total_pages);
SET(total_allocated_pages, objspace->profile.total_allocated_pages);
@@ -7082,7 +7074,6 @@ gc_stat_internal(VALUE hash_or_sym)
* :heap_free_slots=>2070,
* :heap_final_slots=>0,
* :heap_marked_slots=>0,
- * :heap_swept_slots=>0,
* :heap_eden_pages=>24,
* :heap_tomb_pages=>0,
* :total_allocated_pages=>24,