From 2339a8c9079f534805b1cd7eb2d9157316c8c644 Mon Sep 17 00:00:00 2001 From: Damien Doligez Date: Tue, 8 Sep 2020 12:31:33 +0200 Subject: [PATCH 1/2] Change workflow of caml_gc_dispatch to make sure the major GC does not stall when no minor allocations take place. --- runtime/minor_gc.c | 32 ++++++++++++++++++-------------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/runtime/minor_gc.c b/runtime/minor_gc.c index 76e4d5c98..0ae535f5d 100644 --- a/runtime/minor_gc.c +++ b/runtime/minor_gc.c @@ -460,34 +460,38 @@ extern uintnat caml_instr_alloc_jump; */ void caml_gc_dispatch (void) { - value *trigger = Caml_state->young_trigger; /* save old value of trigger */ - CAML_EVENTLOG_DO({ CAML_EV_COUNTER(EV_C_ALLOC_JUMP, caml_instr_alloc_jump); caml_instr_alloc_jump = 0; }); - if (trigger == Caml_state->young_alloc_start - || Caml_state->requested_minor_gc) { + if (Caml_state->young_trigger == Caml_state->young_alloc_start){ /* The minor heap is full, we must do a minor collection. */ + Caml_state->requested_minor_gc = 1; + }else{ + Caml_state->requested_major_slice = 1; + } + if (caml_gc_phase == Phase_idle){ + /* The major GC needs an empty minor heap in order to start a new cycle. + If a major slice was requested, we need to do a minor collection + before we can do the major slice that starts a new major GC cycle. + If a minor collection was requested, we take the opportunity to start + a new major GC cycle. + In either case, we have to do a minor cycle followed by a major slice. + */ + Caml_state->requested_minor_gc = 1; + Caml_state->requested_major_slice = 1; + } + if (Caml_state->requested_minor_gc) { /* reset the pointers first because the end hooks might allocate */ CAML_EV_BEGIN(EV_MINOR); Caml_state->requested_minor_gc = 0; Caml_state->young_trigger = Caml_state->young_alloc_mid; caml_update_young_limit(); caml_empty_minor_heap (); - /* The minor heap is empty, we can start a major collection. */ CAML_EV_END(EV_MINOR); - if (caml_gc_phase == Phase_idle) - { - CAML_EV_BEGIN(EV_MAJOR); - caml_major_collection_slice (-1); - CAML_EV_END(EV_MAJOR); - } } - if (trigger != Caml_state->young_alloc_start - || Caml_state->requested_major_slice) { - /* The minor heap is half-full, do a major GC slice. */ + if (Caml_state->requested_major_slice) { Caml_state->requested_major_slice = 0; Caml_state->young_trigger = Caml_state->young_alloc_start; caml_update_young_limit(); From dff48afa72e9918725d71c8829ded631b5c79226 Mon Sep 17 00:00:00 2001 From: Damien Doligez Date: Fri, 2 Oct 2020 18:33:57 +0200 Subject: [PATCH 2/2] If the major GC is in Phase_idle, caml_gc_major_slice must start a new major GC cycle instead of just calling caml_major_collection_slice. fixes #7813 --- Changes | 3 +++ runtime/gc_ctrl.c | 13 ++++++++++++- runtime/minor_gc.c | 1 + 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index 8d839dc82..786ee11f0 100644 --- a/Changes +++ b/Changes @@ -543,6 +543,9 @@ OCaml 4.12.0 - #7538, #9669: Check for misplaced attributes on module aliases (Leo White, report by Thomas Leonard, review by Florian Angeletti) +- #7813, #9955: make sure the major GC cycle doesn't get stuck in Idle state + (Damien Doligez, report by Anders Fugmann, review by Jacques-Henri Jourdan) + - #7902, #9556: Type-checker infers recursive type, even though -rectypes is off. (Jacques Garrigue, report by Francois Pottier, review by Leo White) diff --git a/runtime/gc_ctrl.c b/runtime/gc_ctrl.c index 325f3911f..f063f963d 100644 --- a/runtime/gc_ctrl.c +++ b/runtime/gc_ctrl.c @@ -603,10 +603,21 @@ cleanup: CAMLprim value caml_gc_major_slice (value v) { + value exn = Val_unit; CAML_EV_BEGIN(EV_EXPLICIT_GC_MAJOR_SLICE); CAMLassert (Is_long (v)); - caml_major_collection_slice (Long_val (v)); + if (caml_gc_phase == Phase_idle){ + /* We need to start a new major GC cycle. Go through the pending_action + machinery. */ + caml_request_major_slice (); + exn = caml_process_pending_actions_exn (); + /* Calls the major GC without passing [v] but the initial slice + ignores this parameter anyway. */ + }else{ + caml_major_collection_slice (Long_val (v)); + } CAML_EV_END(EV_EXPLICIT_GC_MAJOR_SLICE); + caml_raise_if_exception (exn); return Val_long (0); } diff --git a/runtime/minor_gc.c b/runtime/minor_gc.c index 0ae535f5d..4aa192254 100644 --- a/runtime/minor_gc.c +++ b/runtime/minor_gc.c @@ -469,6 +469,7 @@ void caml_gc_dispatch (void) /* The minor heap is full, we must do a minor collection. */ Caml_state->requested_minor_gc = 1; }else{ + /* The minor heap is half-full, do a major GC slice. */ Caml_state->requested_major_slice = 1; } if (caml_gc_phase == Phase_idle){