8319313: G1: Rename G1EvacFailureInjector appropriately

Reviewed-by: mli, iwalulya, ayang
This commit is contained in:
Thomas Schatzl 2023-12-07 16:44:32 +00:00
parent a7f6016406
commit 86f9b3f52a
17 changed files with 297 additions and 289 deletions

View File

@ -70,7 +70,7 @@
#include "gc/g1/g1UncommitRegionTask.hpp"
#include "gc/g1/g1VMOperations.hpp"
#include "gc/g1/g1YoungCollector.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/g1/heapRegion.inline.hpp"
#include "gc/g1/heapRegionRemSet.inline.hpp"
#include "gc/g1/heapRegionSet.inline.hpp"
@ -1144,7 +1144,7 @@ G1CollectedHeap::G1CollectedHeap() :
_numa(G1NUMA::create()),
_hrm(),
_allocator(nullptr),
_evac_failure_injector(),
_allocation_failure_injector(),
_verifier(nullptr),
_summary_bytes_used(0),
_bytes_used_during_gc(0),
@ -1432,7 +1432,7 @@ jint G1CollectedHeap::initialize() {
_collection_set.initialize(max_reserved_regions());
evac_failure_injector()->reset();
allocation_failure_injector()->reset();
CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::gc_parallel_workers);
CPUTimeCounters::create_counter(CPUTimeGroups::CPUTimeType::gc_conc_mark);
@ -3002,9 +3002,6 @@ void G1CollectedHeap::unregister_nmethod(nmethod* nm) {
void G1CollectedHeap::update_used_after_gc(bool evacuation_failed) {
if (evacuation_failed) {
// Reset the G1EvacuationFailureALot counters and flags
evac_failure_injector()->reset();
set_used(recalculate_used());
} else {
// The "used" of the collection set have already been subtracted

View File

@ -44,7 +44,7 @@
#include "gc/g1/g1MonotonicArenaFreePool.hpp"
#include "gc/g1/g1NUMA.hpp"
#include "gc/g1/g1SurvivorRegions.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/g1/heapRegionManager.hpp"
#include "gc/g1/heapRegionSet.hpp"
#include "gc/shared/barrierSet.hpp"
@ -220,7 +220,7 @@ private:
// Manages all allocations with regions except humongous object allocations.
G1Allocator* _allocator;
G1YoungGCEvacFailureInjector _evac_failure_injector;
G1YoungGCAllocationFailureInjector _allocation_failure_injector;
// Manages all heap verification.
G1HeapVerifier* _verifier;
@ -550,7 +550,7 @@ public:
return _allocator;
}
G1YoungGCEvacFailureInjector* evac_failure_injector() { return &_evac_failure_injector; }
G1YoungGCAllocationFailureInjector* allocation_failure_injector() { return &_allocation_failure_injector; }
G1HeapVerifier* verifier() {
return _verifier;

View File

@ -32,7 +32,7 @@
#include "gc/g1/g1RootClosures.hpp"
#include "gc/g1/g1StringDedup.hpp"
#include "gc/g1/g1Trace.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.inline.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp"
#include "gc/shared/continuationGCSupport.inline.hpp"
#include "gc/shared/partialArrayTaskStepper.inline.hpp"
#include "gc/shared/preservedMarks.inline.hpp"
@ -85,7 +85,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
_max_num_optional_regions(collection_set->optional_region_length()),
_numa(g1h->numa()),
_obj_alloc_stat(nullptr),
EVAC_FAILURE_INJECTOR_ONLY(_evac_failure_inject_counter(0) COMMA)
ALLOCATION_FAILURE_INJECTOR_ONLY(_allocation_failure_inject_counter(0) COMMA)
_preserved_marks(preserved_marks),
_evacuation_failed_info(),
_evac_failure_regions(evac_failure_regions),
@ -427,9 +427,9 @@ HeapWord* G1ParScanThreadState::allocate_copy_slow(G1HeapRegionAttr* dest_attr,
return obj_ptr;
}
#if EVAC_FAILURE_INJECTOR
#if ALLOCATION_FAILURE_INJECTOR
bool G1ParScanThreadState::inject_allocation_failure(uint region_idx) {
return _g1h->evac_failure_injector()->evacuation_should_fail(_evac_failure_inject_counter, region_idx);
return _g1h->allocation_failure_injector()->allocation_should_fail(_allocation_failure_inject_counter, region_idx);
}
#endif

View File

@ -28,7 +28,7 @@
#include "gc/g1/g1CollectedHeap.hpp"
#include "gc/g1/g1RedirtyCardsQueue.hpp"
#include "gc/g1/g1OopClosures.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/g1/g1_globals.hpp"
#include "gc/shared/ageTable.hpp"
#include "gc/shared/copyFailedInfo.hpp"
@ -104,7 +104,7 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
size_t* _obj_alloc_stat;
// Per-thread evacuation failure data structures.
EVAC_FAILURE_INJECTOR_ONLY(size_t _evac_failure_inject_counter;)
ALLOCATION_FAILURE_INJECTOR_ONLY(size_t _allocation_failure_inject_counter;)
PreservedMarks* _preserved_marks;
EvacuationFailedInfo _evacuation_failed_info;
@ -120,7 +120,7 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
// Enqueue the card of p into the (evacuation failed) region.
template <class T> void enqueue_card_into_evac_fail_region(T* p, oop obj);
bool inject_allocation_failure(uint region_idx) EVAC_FAILURE_INJECTOR_RETURN_( return false; );
bool inject_allocation_failure(uint region_idx) ALLOCATION_FAILURE_INJECTOR_RETURN_( return false; );
public:
G1ParScanThreadState(G1CollectedHeap* g1h,

View File

@ -34,7 +34,6 @@
#include "gc/g1/g1CollectorState.hpp"
#include "gc/g1/g1ConcurrentMark.hpp"
#include "gc/g1/g1GCPhaseTimes.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1EvacFailureRegions.inline.hpp"
#include "gc/g1/g1EvacInfo.hpp"
#include "gc/g1/g1HRPrinter.hpp"
@ -46,6 +45,7 @@
#include "gc/g1/g1RootProcessor.hpp"
#include "gc/g1/g1Trace.hpp"
#include "gc/g1/g1YoungCollector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/g1/g1YoungGCPostEvacuateTasks.hpp"
#include "gc/g1/g1YoungGCPreEvacuateTasks.hpp"
#include "gc/g1/g1_globals.hpp"
@ -243,8 +243,8 @@ WorkerThreads* G1YoungCollector::workers() const {
return _g1h->workers();
}
G1YoungGCEvacFailureInjector* G1YoungCollector::evac_failure_injector() const {
return _g1h->evac_failure_injector();
G1YoungGCAllocationFailureInjector* G1YoungCollector::allocation_failure_injector() const {
return _g1h->allocation_failure_injector();
}
@ -534,7 +534,7 @@ void G1YoungCollector::pre_evacuate_collection_set(G1EvacInfo* evacuation_info)
DerivedPointerTable::clear();
#endif
evac_failure_injector()->arm_if_needed();
allocation_failure_injector()->arm_if_needed();
}
class G1ParEvacuateFollowersClosure : public VoidClosure {

View File

@ -26,7 +26,7 @@
#define SHARE_GC_G1_G1YOUNGCOLLECTOR_HPP
#include "gc/g1/g1EvacFailureRegions.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/shared/gcCause.hpp"
#include "gc/shared/taskqueue.hpp"
@ -49,7 +49,7 @@ class G1Policy;
class G1RedirtyCardsQueueSet;
class G1RemSet;
class G1SurvivorRegions;
class G1YoungGCEvacFailureInjector;
class G1YoungGCAllocationFailureInjector;
class STWGCTimer;
class WorkerThreads;
@ -78,7 +78,7 @@ class G1YoungCollector {
G1SurvivorRegions* survivor_regions() const;
ReferenceProcessor* ref_processor_stw() const;
WorkerThreads* workers() const;
G1YoungGCEvacFailureInjector* evac_failure_injector() const;
G1YoungGCAllocationFailureInjector* allocation_failure_injector() const;
GCCause::Cause _gc_cause;

View File

@ -0,0 +1,114 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.inline.hpp"
#include "gc/g1/g1_globals.hpp"
#if ALLOCATION_FAILURE_INJECTOR
class SelectAllocationFailureRegionClosure : public HeapRegionClosure {
CHeapBitMap& _allocation_failure_regions;
size_t _allocation_failure_regions_num;
public:
SelectAllocationFailureRegionClosure(CHeapBitMap& allocation_failure_regions, size_t cset_length) :
_allocation_failure_regions(allocation_failure_regions),
_allocation_failure_regions_num(cset_length * G1GCAllocationFailureALotCSetPercent / 100) { }
bool do_heap_region(HeapRegion* r) override {
assert(r->in_collection_set(), "must be");
if (_allocation_failure_regions_num > 0) {
_allocation_failure_regions.set_bit(r->hrm_index());
--_allocation_failure_regions_num;
}
return _allocation_failure_regions_num == 0;
}
};
G1YoungGCAllocationFailureInjector::G1YoungGCAllocationFailureInjector()
: _inject_allocation_failure_for_current_gc(),
_last_collection_with_allocation_failure(),
_allocation_failure_regions(mtGC) {}
void G1YoungGCAllocationFailureInjector::select_allocation_failure_regions() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
_allocation_failure_regions.reinitialize(g1h->max_reserved_regions());
SelectAllocationFailureRegionClosure closure(_allocation_failure_regions, g1h->collection_set()->cur_length());
g1h->collection_set_iterate_all(&closure);
}
bool G1YoungGCAllocationFailureInjector::arm_if_needed_for_gc_type(bool for_young_only_phase,
bool during_concurrent_start,
bool mark_or_rebuild_in_progress) {
bool res = false;
if (mark_or_rebuild_in_progress) {
res |= G1GCAllocationFailureALotDuringConcMark;
}
if (during_concurrent_start) {
res |= G1GCAllocationFailureALotDuringConcurrentStart;
}
if (for_young_only_phase) {
res |= G1GCAllocationFailureALotDuringYoungGC;
} else {
// GCs are mixed
res |= G1GCAllocationFailureALotDuringMixedGC;
}
return res;
}
void G1YoungGCAllocationFailureInjector::arm_if_needed() {
if (G1GCAllocationFailureALot) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// Check if we have gone over the interval.
const size_t gc_num = g1h->total_collections();
const size_t elapsed_gcs = gc_num - _last_collection_with_allocation_failure;
_inject_allocation_failure_for_current_gc = (elapsed_gcs >= G1GCAllocationFailureALotInterval);
// Now check if evacuation failure injection should be enabled for the current GC.
G1CollectorState* collector_state = g1h->collector_state();
const bool in_young_only_phase = collector_state->in_young_only_phase();
const bool in_concurrent_start_gc = collector_state->in_concurrent_start_gc();
const bool mark_or_rebuild_in_progress = collector_state->mark_or_rebuild_in_progress();
_inject_allocation_failure_for_current_gc &=
arm_if_needed_for_gc_type(in_young_only_phase,
in_concurrent_start_gc,
mark_or_rebuild_in_progress);
if (_inject_allocation_failure_for_current_gc) {
select_allocation_failure_regions();
}
}
}
void G1YoungGCAllocationFailureInjector::reset() {
_last_collection_with_allocation_failure = G1CollectedHeap::heap()->total_collections();
_inject_allocation_failure_for_current_gc = false;
}
#endif // #if ALLOCATION_FAILURE_INJECTOR

View File

@ -0,0 +1,87 @@
/*
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_HPP
#define SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_HPP
#include "gc/g1/g1_globals.hpp"
#include "memory/allStatic.hpp"
#include "utilities/globalDefinitions.hpp"
#if ALLOCATION_FAILURE_INJECTOR
#define ALLOCATION_FAILURE_INJECTOR_RETURN
#define ALLOCATION_FAILURE_INJECTOR_RETURN_(code)
#define ALLOCATION_FAILURE_INJECTOR_ONLY(code) code
#else
#define ALLOCATION_FAILURE_INJECTOR_RETURN { return; }
#define ALLOCATION_FAILURE_INJECTOR_RETURN_(code) { code }
#define ALLOCATION_FAILURE_INJECTOR_ONLY(code)
#endif // ALLOCATION_FAILURE_INJECTOR
// Support for injecting allocation failures based on the G1GCAllocationFailureALot*
// flags. Analogous to PromotionFailureALot for the other collectors.
//
// Every G1GCAllocationFailureALotInterval collections without evacuation failure
// in between we "arm" the injector to induce allocation failures after
// G1GCAllocationFailureALotCount successful evacuations.
//
// Available only when ALLOCATION_FAILURE_INJECTOR is defined.
class G1YoungGCAllocationFailureInjector {
#if ALLOCATION_FAILURE_INJECTOR
// Should we inject evacuation failures in the current GC.
bool _inject_allocation_failure_for_current_gc;
// Records the number of the last collection when allocation failure happened.
// Used to determine whether allocation failure injection should be in effect
// for the current GC.
size_t _last_collection_with_allocation_failure;
// Records the regions that will fail evacuation.
CHeapBitMap _allocation_failure_regions;
#endif
bool arm_if_needed_for_gc_type(bool for_young_only_phase,
bool during_concurrent_start,
bool mark_or_rebuild_in_progress) ALLOCATION_FAILURE_INJECTOR_RETURN_( return false; );
// Selects the regions that will fail allocation by G1GCAllocationFailureALotCSetPercent.
void select_allocation_failure_regions() ALLOCATION_FAILURE_INJECTOR_RETURN;
public:
G1YoungGCAllocationFailureInjector() ALLOCATION_FAILURE_INJECTOR_RETURN;
// Arm the allocation failure injector if needed for the current
// GC (based upon the type of GC and which command line flags are set);
void arm_if_needed() ALLOCATION_FAILURE_INJECTOR_RETURN;
// Return true if it's time to cause an allocation failure; the caller
// provides the (preferably thread-local) counter to minimize performance impact.
bool allocation_should_fail(size_t& counter, uint region_idx) ALLOCATION_FAILURE_INJECTOR_RETURN_( return false; );
// Reset the allocation failure injection counters. Should be called at
// the end of an evacuation pause in which an allocation failure occurred.
void reset() ALLOCATION_FAILURE_INJECTOR_RETURN;
};
#endif /* SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_HPP */

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2021, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -22,30 +22,30 @@
*
*/
#ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP
#define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP
#ifndef SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_INLINE_HPP
#define SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_INLINE_HPP
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1YoungGCAllocationFailureInjector.hpp"
#include "gc/g1/g1_globals.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#if EVAC_FAILURE_INJECTOR
#if ALLOCATION_FAILURE_INJECTOR
inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail(size_t& counter, uint region_idx) {
if (!_inject_evacuation_failure_for_current_gc) {
inline bool G1YoungGCAllocationFailureInjector::allocation_should_fail(size_t& counter, uint region_idx) {
if (!_inject_allocation_failure_for_current_gc) {
return false;
}
if (!_evac_failure_regions.at(region_idx)) {
if (!_allocation_failure_regions.at(region_idx)) {
return false;
}
if (++counter < G1EvacuationFailureALotCount) {
if (++counter < G1GCAllocationFailureALotCount) {
return false;
}
counter = 0;
return true;
}
#endif // #if EVAC_FAILURE_INJECTOR
#endif // #if ALLOCATION_FAILURE_INJECTOR
#endif /* SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP */
#endif /* SHARE_GC_G1_G1YOUNGGCALLOCATIONFAILUREINJECTOR_INLINE_HPP */

View File

@ -1,114 +0,0 @@
/*
* Copyright (c) 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.inline.hpp"
#include "gc/g1/g1_globals.hpp"
#if EVAC_FAILURE_INJECTOR
class SelectEvacFailureRegionClosure : public HeapRegionClosure {
CHeapBitMap& _evac_failure_regions;
size_t _evac_failure_regions_num;
public:
SelectEvacFailureRegionClosure(CHeapBitMap& evac_failure_regions, size_t cset_length) :
_evac_failure_regions(evac_failure_regions),
_evac_failure_regions_num(cset_length * G1EvacuationFailureALotCSetPercent / 100) { }
bool do_heap_region(HeapRegion* r) override {
assert(r->in_collection_set(), "must be");
if (_evac_failure_regions_num > 0) {
_evac_failure_regions.set_bit(r->hrm_index());
--_evac_failure_regions_num;
}
return _evac_failure_regions_num == 0;
}
};
G1YoungGCEvacFailureInjector::G1YoungGCEvacFailureInjector()
: _inject_evacuation_failure_for_current_gc(),
_last_collection_with_evacuation_failure(),
_evac_failure_regions(mtGC) {}
void G1YoungGCEvacFailureInjector::select_evac_failure_regions() {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
_evac_failure_regions.reinitialize(g1h->max_reserved_regions());
SelectEvacFailureRegionClosure closure(_evac_failure_regions, g1h->collection_set()->cur_length());
g1h->collection_set_iterate_all(&closure);
}
bool G1YoungGCEvacFailureInjector::arm_if_needed_for_gc_type(bool for_young_only_phase,
bool during_concurrent_start,
bool mark_or_rebuild_in_progress) {
bool res = false;
if (mark_or_rebuild_in_progress) {
res |= G1EvacuationFailureALotDuringConcMark;
}
if (during_concurrent_start) {
res |= G1EvacuationFailureALotDuringConcurrentStart;
}
if (for_young_only_phase) {
res |= G1EvacuationFailureALotDuringYoungGC;
} else {
// GCs are mixed
res |= G1EvacuationFailureALotDuringMixedGC;
}
return res;
}
void G1YoungGCEvacFailureInjector::arm_if_needed() {
if (G1EvacuationFailureALot) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
// Check if we have gone over the interval.
const size_t gc_num = g1h->total_collections();
const size_t elapsed_gcs = gc_num - _last_collection_with_evacuation_failure;
_inject_evacuation_failure_for_current_gc = (elapsed_gcs >= G1EvacuationFailureALotInterval);
// Now check if evacuation failure injection should be enabled for the current GC.
G1CollectorState* collector_state = g1h->collector_state();
const bool in_young_only_phase = collector_state->in_young_only_phase();
const bool in_concurrent_start_gc = collector_state->in_concurrent_start_gc();
const bool mark_or_rebuild_in_progress = collector_state->mark_or_rebuild_in_progress();
_inject_evacuation_failure_for_current_gc &=
arm_if_needed_for_gc_type(in_young_only_phase,
in_concurrent_start_gc,
mark_or_rebuild_in_progress);
if (_inject_evacuation_failure_for_current_gc) {
select_evac_failure_regions();
}
}
}
void G1YoungGCEvacFailureInjector::reset() {
_last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections();
_inject_evacuation_failure_for_current_gc = false;
}
#endif // #if EVAC_FAILURE_INJECTOR

View File

@ -1,87 +0,0 @@
/*
* Copyright (c) 2021, 2022, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP
#define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP
#include "gc/g1/g1_globals.hpp"
#include "memory/allStatic.hpp"
#include "utilities/globalDefinitions.hpp"
#if EVAC_FAILURE_INJECTOR
#define EVAC_FAILURE_INJECTOR_RETURN
#define EVAC_FAILURE_INJECTOR_RETURN_(code)
#define EVAC_FAILURE_INJECTOR_ONLY(code) code
#else
#define EVAC_FAILURE_INJECTOR_RETURN { return; }
#define EVAC_FAILURE_INJECTOR_RETURN_(code) { code }
#define EVAC_FAILURE_INJECTOR_ONLY(code)
#endif // EVAC_FAILURE_INJECTOR
// Support for injecting evacuation failures based on the G1EvacuationFailureALot*
// flags. Analogous to PromotionFailureALot for the other collectors.
//
// Every G1EvacuationFailureALotInterval collections without evacuation failure
// in between we "arm" the injector to induce evacuation failures after
// G1EvacuationFailureALotCount successful evacuations.
//
// Available only when EVAC_FAILURE_INJECTOR is defined.
class G1YoungGCEvacFailureInjector {
#if EVAC_FAILURE_INJECTOR
// Should we inject evacuation failures in the current GC.
bool _inject_evacuation_failure_for_current_gc;
// Records the number of the last collection when evacuation failure happened.
// Used to determine whether evacuation failure injection should be in effect
// for the current GC.
size_t _last_collection_with_evacuation_failure;
// Records the regions that will fail evacuation.
CHeapBitMap _evac_failure_regions;
#endif
bool arm_if_needed_for_gc_type(bool for_young_only_phase,
bool during_concurrent_start,
bool mark_or_rebuild_in_progress) EVAC_FAILURE_INJECTOR_RETURN_( return false; );
// Selects the regions that will fail evacuation by G1EvacuationFailureALotCSetPercent.
void select_evac_failure_regions() EVAC_FAILURE_INJECTOR_RETURN;
public:
G1YoungGCEvacFailureInjector() EVAC_FAILURE_INJECTOR_RETURN;
// Arm the evacuation failure injector if needed for the current
// GC (based upon the type of GC and which command line flags are set);
void arm_if_needed() EVAC_FAILURE_INJECTOR_RETURN;
// Return true if it's time to cause an evacuation failure; the caller
// provides the (preferably thread-local) counter to minimize performance impact.
bool evacuation_should_fail(size_t& counter, uint region_idx) EVAC_FAILURE_INJECTOR_RETURN_( return false; );
// Reset the evacuation failure injection counters. Should be called at
// the end of an evacuation pause in which an evacuation failure occurred.
void reset() EVAC_FAILURE_INJECTOR_RETURN;
};
#endif /* SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_HPP */

View File

@ -67,16 +67,26 @@ public:
class G1PostEvacuateCollectionSetCleanupTask1::RecalculateUsedTask : public G1AbstractSubTask {
bool _evacuation_failed;
bool _allocation_failed;
public:
RecalculateUsedTask(bool evacuation_failed) : G1AbstractSubTask(G1GCPhaseTimes::RecalculateUsed), _evacuation_failed(evacuation_failed) { }
RecalculateUsedTask(bool evacuation_failed, bool allocation_failed) :
G1AbstractSubTask(G1GCPhaseTimes::RecalculateUsed),
_evacuation_failed(evacuation_failed),
_allocation_failed(allocation_failed) { }
double worker_cost() const override {
// If there is no evacuation failure, the work to perform is minimal.
return _evacuation_failed ? 1.0 : AlmostNoWork;
}
void do_work(uint worker_id) override { G1CollectedHeap::heap()->update_used_after_gc(_evacuation_failed); }
void do_work(uint worker_id) override {
G1CollectedHeap::heap()->update_used_after_gc(_evacuation_failed);
if (_allocation_failed) {
// Reset the G1GCAllocationFailureALot counters and flags
G1CollectedHeap::heap()->allocation_failure_injector()->reset();
}
}
};
class G1PostEvacuateCollectionSetCleanupTask1::SampleCollectionSetCandidatesTask : public G1AbstractSubTask {
@ -309,9 +319,10 @@ G1PostEvacuateCollectionSetCleanupTask1::G1PostEvacuateCollectionSetCleanupTask1
G1BatchedTask("Post Evacuate Cleanup 1", G1CollectedHeap::heap()->phase_times())
{
bool evac_failed = evac_failure_regions->has_regions_evac_failed();
bool alloc_failed = evac_failure_regions->has_regions_alloc_failed();
add_serial_task(new MergePssTask(per_thread_states));
add_serial_task(new RecalculateUsedTask(evac_failed));
add_serial_task(new RecalculateUsedTask(evac_failed, alloc_failed));
if (SampleCollectionSetCandidatesTask::should_execute()) {
add_serial_task(new SampleCollectionSetCandidatesTask());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2001, 2022, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2001, 2023, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -27,18 +27,18 @@
#include "runtime/globals_shared.hpp"
// Enable evacuation failure injector by default in non-product builds.
// Enable allocation failure injector by default in non-product builds.
#ifdef EVAC_FAILURE_INJECTOR
#error "EVAC_FAILURE_INJECTOR already defined"
#ifdef ALLOCATION_FAILURE_INJECTOR
#error "ALLOCATION_FAILURE_INJECTOR already defined"
#endif
#ifndef PRODUCT
#define EVAC_FAILURE_INJECTOR 1
#define ALLOCATION_FAILURE_INJECTOR 1
#else
#define EVAC_FAILURE_INJECTOR 0
#define ALLOCATION_FAILURE_INJECTOR 0
#endif
#if EVAC_FAILURE_INJECTOR
#if ALLOCATION_FAILURE_INJECTOR
#define GC_G1_EVACUATION_FAILURE_FLAGS(develop, \
develop_pd, \
product, \
@ -47,38 +47,38 @@
range, \
constraint) \
\
product(bool, G1EvacuationFailureALot, false, \
"Force use of evacuation failure handling during certain " \
"evacuation pauses") \
product(bool, G1GCAllocationFailureALot, false, \
"Force execution of evacuation failure handling by inducing " \
"allocation failures during certain young collection pauses") \
\
product(uintx, G1EvacuationFailureALotCount, 1000, \
"Number of successful evacuations between evacuation failures " \
"occurring at object copying per thread") \
product(uintx, G1GCAllocationFailureALotCount, 1000, \
"Number of successful evacuations between induced allocation " \
"failures occurring at object copying per thread") \
\
product(uintx, G1EvacuationFailureALotInterval, 5, \
product(uintx, G1GCAllocationFailureALotInterval, 5, \
"Total collections between forced triggering of evacuation " \
"failures") \
\
product(bool, G1EvacuationFailureALotDuringConcMark, true, \
"Force use of evacuation failure handling during evacuation " \
"pauses when marking is in progress") \
product(bool, G1GCAllocationFailureALotDuringConcMark, true, \
"Trigger evacuation failure handling in collection pauses where " \
"marking is in progress") \
\
product(bool, G1EvacuationFailureALotDuringConcurrentStart, true, \
"Force use of evacuation failure handling during concurrent " \
"start evacuation pauses") \
product(bool, G1GCAllocationFailureALotDuringConcurrentStart, true, \
"Trigger evacuation failure handling during concurrent start " \
"collection pauses") \
\
product(bool, G1EvacuationFailureALotDuringYoungGC, true, \
"Force use of evacuation failure handling during young " \
"evacuation pauses") \
product(bool, G1GCAllocationFailureALotDuringYoungGC, true, \
"Trigger evacuation failure handling during young collection " \
"pauses") \
\
product(bool, G1EvacuationFailureALotDuringMixedGC, true, \
product(bool, G1GCAllocationFailureALotDuringMixedGC, true, \
"Force use of evacuation failure handling during mixed " \
"evacuation pauses") \
"collection pauses") \
\
product(uint, G1EvacuationFailureALotCSetPercent, 100, \
product(uint, G1GCAllocationFailureALotCSetPercent, 100, \
"The percentage of regions in the collection set starting " \
"from the beginning where the forced evacuation failure " \
"injection will be applied.") \
"from the beginning where the allocation failures are " \
"injected.") \
range(1, 100)
#else
#define GC_G1_EVACUATION_FAILURE_FLAGS(develop, \

View File

@ -24,7 +24,7 @@
package gc.g1;
/*
* @test TestEvacuationFailure
* @test TestAllocationFailure
* @summary Ensure the output for a minor GC with G1 that has allocation failure contains the correct strings.
* @requires vm.gc.G1
* @requires vm.debug
@ -34,24 +34,24 @@ package gc.g1;
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* gc.g1.TestEvacuationFailure
* gc.g1.TestAllocationFailure
*/
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
public class TestEvacuationFailure {
public class TestAllocationFailure {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC",
"-Xmx32M",
"-Xmn16M",
"-XX:+G1EvacuationFailureALot",
"-XX:G1EvacuationFailureALotCount=100",
"-XX:G1EvacuationFailureALotInterval=1",
"-XX:+G1GCAllocationFailureALot",
"-XX:G1GCAllocationFailureALotCount=100",
"-XX:G1GCAllocationFailureALotInterval=1",
"-XX:+UnlockDiagnosticVMOptions",
"-Xlog:gc",
GCTestWithEvacuationFailure.class.getName());
GCTestWithAllocationFailure.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
System.out.println(output.getStdout());
@ -59,17 +59,17 @@ public class TestEvacuationFailure {
output.shouldHaveExitValue(0);
}
static class GCTestWithEvacuationFailure {
static class GCTestWithAllocationFailure {
private static byte[] garbage;
private static byte[] largeObject;
private static Object[] holder = new Object[200]; // Must be larger than G1EvacuationFailureALotCount
private static Object[] holder = new Object[200]; // Must be larger than G1GCAllocationFailureALotCount
public static void main(String [] args) {
largeObject = new byte[16 * 1024 * 1024];
System.out.println("Creating garbage");
// Create 16 MB of garbage. This should result in at least one GC,
// (Heap size is 32M, we use 17MB for the large object above)
// which is larger than G1EvacuationFailureALotInterval.
// which is larger than G1GCAllocationFailureALotInterval.
for (int i = 0; i < 16 * 1024; i++) {
holder[i % holder.length] = new byte[1024];
}

View File

@ -275,12 +275,12 @@ public class TestGCLogMessages {
ProcessBuilder pb = ProcessTools.createLimitedTestJavaProcessBuilder("-XX:+UseG1GC",
"-Xmx32M",
"-Xmn16M",
"-XX:+G1EvacuationFailureALot",
"-XX:G1EvacuationFailureALotCount=100",
"-XX:G1EvacuationFailureALotInterval=1",
"-XX:+G1GCAllocationFailureALot",
"-XX:G1GCAllocationFailureALotCount=100",
"-XX:G1GCAllocationFailureALotInterval=1",
"-XX:+UnlockDiagnosticVMOptions",
"-Xlog:gc+phases=debug",
GCTestWithEvacuationFailure.class.getName());
GCTestWithAllocationFailure.class.getName());
OutputAnalyzer output = new OutputAnalyzer(pb.start());
checkMessagesAtLevel(output, exhFailureMessages, Level.DEBUG);
@ -292,7 +292,7 @@ public class TestGCLogMessages {
"-Xms32M",
"-XX:+UnlockDiagnosticVMOptions",
"-Xlog:gc+phases=trace",
GCTestWithEvacuationFailure.class.getName());
GCTestWithAllocationFailure.class.getName());
output = new OutputAnalyzer(pb.start());
checkMessagesAtLevel(output, exhFailureMessages, Level.TRACE);
@ -346,17 +346,17 @@ public class TestGCLogMessages {
}
}
static class GCTestWithEvacuationFailure {
static class GCTestWithAllocationFailure {
private static byte[] garbage;
private static byte[] largeObject;
private static Object[] holder = new Object[200]; // Must be larger than G1EvacuationFailureALotCount
private static Object[] holder = new Object[200]; // Must be larger than G1GCAllocationFailureALotCount
public static void main(String [] args) {
largeObject = new byte[16*1024*1024];
System.out.println("Creating garbage");
// Create 16 MB of garbage. This should result in at least one GC,
// (Heap size is 32M, we use 17MB for the large object above)
// which is larger than G1EvacuationFailureALotInterval.
// which is larger than G1GCAllocationFailureALotInterval.
for (int i = 0; i < 16 * 1024; i++) {
holder[i % holder.length] = new byte[1024];
}

View File

@ -122,9 +122,9 @@ public class TestVerifyGCType {
private static void testYoungEvacFail() throws Exception {
OutputAnalyzer output;
output = testWithVerificationType(new String[] {"young-evac-fail"},
new String[] {"-XX:+G1EvacuationFailureALot",
"-XX:G1EvacuationFailureALotCount=100",
"-XX:G1EvacuationFailureALotInterval=1",
new String[] {"-XX:+G1GCAllocationFailureALot",
"-XX:G1GCAllocationFailureALotCount=100",
"-XX:G1GCAllocationFailureALotInterval=1",
"-XX:+UnlockDiagnosticVMOptions"});
output.shouldHaveExitValue(0);

View File

@ -47,8 +47,8 @@ import jdk.test.whitebox.WhiteBox;
* @build jdk.test.whitebox.WhiteBox
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
* -Xmx32m -Xms32m -XX:+UnlockExperimentalVMOptions -XX:+G1EvacuationFailureALot
* -XX:G1EvacuationFailureALotCount=100 -XX:G1EvacuationFailureALotInterval=1
* -Xmx32m -Xms32m -XX:+UnlockExperimentalVMOptions -XX:+G1GCAllocationFailureALot
* -XX:G1GCAllocationFailureALotCount=100 -XX:G1GCAllocationFailureALotInterval=1
* -Xlog:gc=debug -XX:+UseG1GC jdk.jfr.event.gc.detailed.TestEvacuationFailedEvent
*/