8274191: Improve g1 evacuation failure injector performance

Reviewed-by: kbarrett, ayang
This commit is contained in:
Thomas Schatzl 2021-09-24 12:06:17 +00:00
parent d91e227abb
commit db23ecdfae
6 changed files with 25 additions and 21 deletions

View File

@ -85,6 +85,7 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
_num_optional_regions(optional_cset_length), _num_optional_regions(optional_cset_length),
_numa(g1h->numa()), _numa(g1h->numa()),
_obj_alloc_stat(NULL), _obj_alloc_stat(NULL),
NOT_PRODUCT(_evac_failure_inject_counter(0) COMMA)
_preserved_marks(preserved_marks), _preserved_marks(preserved_marks),
_evacuation_failed_info(), _evacuation_failed_info(),
_evac_failure_regions(evac_failure_regions) _evac_failure_regions(evac_failure_regions)
@ -414,6 +415,12 @@ HeapWord* G1ParScanThreadState::allocate_copy_slow(G1HeapRegionAttr* dest_attr,
return obj_ptr; return obj_ptr;
} }
#ifndef PRODUCT
bool G1ParScanThreadState::inject_evacuation_failure() {
return _g1h->evac_failure_injector()->evacuation_should_fail(_evac_failure_inject_counter);
}
#endif
NOINLINE NOINLINE
void G1ParScanThreadState::undo_allocation(G1HeapRegionAttr dest_attr, void G1ParScanThreadState::undo_allocation(G1HeapRegionAttr dest_attr,
HeapWord* obj_ptr, HeapWord* obj_ptr,
@ -458,7 +465,7 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio
assert(_g1h->is_in_reserved(obj_ptr), "Allocated memory should be in the heap"); assert(_g1h->is_in_reserved(obj_ptr), "Allocated memory should be in the heap");
// Should this evacuation fail? // Should this evacuation fail?
if (_g1h->evac_failure_injector()->evacuation_should_fail()) { if (inject_evacuation_failure()) {
// Doing this after all the allocation attempts also tests the // Doing this after all the allocation attempts also tests the
// undo_allocation() method too. // undo_allocation() method too.
undo_allocation(dest_attr, obj_ptr, word_sz, node_index); undo_allocation(dest_attr, obj_ptr, word_sz, node_index);
@ -515,7 +522,6 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio
G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young()); G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young());
obj->oop_iterate_backwards(&_scanner, klass); obj->oop_iterate_backwards(&_scanner, klass);
return obj; return obj;
} else { } else {
_plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index); _plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index);
return forward_ptr; return forward_ptr;

View File

@ -98,10 +98,15 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
size_t* _obj_alloc_stat; size_t* _obj_alloc_stat;
// Per-thread evacuation failure data structures. // Per-thread evacuation failure data structures.
#ifndef PRODUCT
size_t _evac_failure_inject_counter;
#endif
PreservedMarks* _preserved_marks; PreservedMarks* _preserved_marks;
EvacuationFailedInfo _evacuation_failed_info; EvacuationFailedInfo _evacuation_failed_info;
G1EvacFailureRegions* _evac_failure_regions; G1EvacFailureRegions* _evac_failure_regions;
bool inject_evacuation_failure() PRODUCT_RETURN_( return false; );
public: public:
G1ParScanThreadState(G1CollectedHeap* g1h, G1ParScanThreadState(G1CollectedHeap* g1h,
G1RedirtyCardsQueueSet* rdcqs, G1RedirtyCardsQueueSet* rdcqs,

View File

@ -72,11 +72,8 @@ void G1YoungGCEvacFailureInjector::arm_if_needed() {
} }
void G1YoungGCEvacFailureInjector::reset() { void G1YoungGCEvacFailureInjector::reset() {
if (G1EvacuationFailureALot) { _last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections();
_last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections(); _inject_evacuation_failure_for_current_gc = false;
_evacuation_failure_object_count = 0;
_inject_evacuation_failure_for_current_gc = false;
}
} }
#endif // #ifndef PRODUCT #endif // #ifndef PRODUCT

View File

@ -45,9 +45,6 @@ class G1YoungGCEvacFailureInjector {
// Used to determine whether evacuation failure injection should be in effect // Used to determine whether evacuation failure injection should be in effect
// for the current GC. // for the current GC.
size_t _last_collection_with_evacuation_failure; size_t _last_collection_with_evacuation_failure;
// The number of evacuations between induced failures.
volatile size_t _evacuation_failure_object_count;
#endif #endif
bool arm_if_needed_for_gc_type(bool for_young_gc, bool arm_if_needed_for_gc_type(bool for_young_gc,
@ -59,8 +56,9 @@ public:
// GC (based upon the type of GC and which command line flags are set); // GC (based upon the type of GC and which command line flags are set);
void arm_if_needed() PRODUCT_RETURN; void arm_if_needed() PRODUCT_RETURN;
// Return true if it's time to cause an evacuation failure. // Return true if it's time to cause an evacuation failure; the caller
bool evacuation_should_fail() PRODUCT_RETURN_( return false; ); // provides the (preferably thread-local) counter to minimize performance impact.
bool evacuation_should_fail(size_t& counter) PRODUCT_RETURN_( return false; );
// Reset the evacuation failure injection counters. Should be called at // Reset the evacuation failure injection counters. Should be called at
// the end of an evacuation pause in which an evacuation failure occurred. // the end of an evacuation pause in which an evacuation failure occurred.

View File

@ -25,23 +25,21 @@
#ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP #ifndef SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP
#define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP #define SHARE_GC_G1_G1YOUNGGCEVACUATIONFAILUREINJECTOR_INLINE_HPP
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#include "gc/g1/g1_globals.hpp" #include "gc/g1/g1_globals.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"
#ifndef PRODUCT #ifndef PRODUCT
inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail() { inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail(size_t& counter) {
if (!G1EvacuationFailureALot || !_inject_evacuation_failure_for_current_gc) { if (!_inject_evacuation_failure_for_current_gc) {
return false; return false;
} }
// Injecting evacuation failures is in effect for current GC if (++counter < G1EvacuationFailureALotCount) {
// Access to _evacuation_failure_alot_count is not atomic;
// the value does not have to be exact.
if (++_evacuation_failure_object_count < G1EvacuationFailureALotCount) {
return false; return false;
} }
_evacuation_failure_object_count = 0; counter = 0;
return true; return true;
} }

View File

@ -275,7 +275,7 @@
\ \
develop(uintx, G1EvacuationFailureALotCount, 1000, \ develop(uintx, G1EvacuationFailureALotCount, 1000, \
"Number of successful evacuations between evacuation failures " \ "Number of successful evacuations between evacuation failures " \
"occurring at object copying") \ "occurring at object copying per thread") \
\ \
develop(uintx, G1EvacuationFailureALotInterval, 5, \ develop(uintx, G1EvacuationFailureALotInterval, 5, \
"Total collections between forced triggering of evacuation " \ "Total collections between forced triggering of evacuation " \