Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8274191: Improve g1 evacuation failure injector performance #5650

Changes from 2 commits
File filter

Filter by extension

Filter by extension

Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
@@ -85,6 +85,9 @@ G1ParScanThreadState::G1ParScanThreadState(G1CollectedHeap* g1h,
#ifndef PRODUCT
tschatzl marked this conversation as resolved.
Show resolved Hide resolved
@@ -414,6 +417,12 @@ HeapWord* G1ParScanThreadState::allocate_copy_slow(G1HeapRegionAttr* dest_attr,
return obj_ptr;

#ifndef PRODUCT
bool G1ParScanThreadState::inject_evacuation_failure() {
return _g1h->evac_failure_injector()->evacuation_should_fail(_evac_failure_inject_counter);

void G1ParScanThreadState::undo_allocation(G1HeapRegionAttr dest_attr,
HeapWord* obj_ptr,
@@ -458,7 +467,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");

// 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
// undo_allocation() method too.
undo_allocation(dest_attr, obj_ptr, word_sz, node_index);
@@ -515,7 +524,6 @@ oop G1ParScanThreadState::do_copy_to_survivor_space(G1HeapRegionAttr const regio
G1SkipCardEnqueueSetter x(&_scanner, dest_attr.is_young());
obj->oop_iterate_backwards(&_scanner, klass);
return obj;

} else {
_plab_allocator->undo_allocation(dest_attr, obj_ptr, word_sz, node_index);
return forward_ptr;
@@ -98,10 +98,15 @@ class G1ParScanThreadState : public CHeapObj<mtGC> {
size_t* _obj_alloc_stat;

// Per-thread evacuation failure data structures.
#ifndef PRODUCT
size_t _evac_failure_inject_counter;
PreservedMarks* _preserved_marks;
EvacuationFailedInfo _evacuation_failed_info;
G1EvacFailureRegions* _evac_failure_regions;

bool inject_evacuation_failure() PRODUCT_RETURN_( return false; );

G1ParScanThreadState(G1CollectedHeap* g1h,
G1RedirtyCardsQueueSet* rdcqs,
@@ -72,11 +72,8 @@ void G1YoungGCEvacFailureInjector::arm_if_needed() {

void G1YoungGCEvacFailureInjector::reset() {
if (G1EvacuationFailureALot) {
_last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections();
_evacuation_failure_object_count = 0;
_inject_evacuation_failure_for_current_gc = false;
_last_collection_with_evacuation_failure = G1CollectedHeap::heap()->total_collections();
_inject_evacuation_failure_for_current_gc = false;

#endif // #ifndef PRODUCT
@@ -45,9 +45,6 @@ class G1YoungGCEvacFailureInjector {
// Used to determine whether evacuation failure injection should be in effect
// for the current GC.
size_t _last_collection_with_evacuation_failure;

// The number of evacuations between induced failures.
volatile size_t _evacuation_failure_object_count;

bool arm_if_needed_for_gc_type(bool for_young_gc,
@@ -59,8 +56,9 @@ class G1YoungGCEvacFailureInjector {
// GC (based upon the type of GC and which command line flags are set);
void arm_if_needed() PRODUCT_RETURN;

// Return true if it's time to cause an evacuation failure.
bool evacuation_should_fail() PRODUCT_RETURN_( return false; );
// 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) PRODUCT_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.
@@ -25,23 +25,24 @@

#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"

#include "gc/g1/g1_globals.hpp"
#include "gc/g1/g1CollectedHeap.inline.hpp"
#include "gc/g1/g1YoungGCEvacFailureInjector.hpp"

#ifndef PRODUCT

inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail() {
if (!G1EvacuationFailureALot || !_inject_evacuation_failure_for_current_gc) {
inline bool G1YoungGCEvacFailureInjector::evacuation_should_fail(size_t& counter) {
if (!_inject_evacuation_failure_for_current_gc) {
return false;
// Injecting evacuation failures is in effect for current GC
// Access to _evacuation_failure_alot_count is not atomic;
tschatzl marked this conversation as resolved.
Show resolved Hide resolved
// the value does not have to be exact.
if (++_evacuation_failure_object_count < G1EvacuationFailureALotCount) {
if (++counter < G1EvacuationFailureALotCount) {
return false;
_evacuation_failure_object_count = 0;
counter = 0;
return true;