--- old/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-11-27 20:26:33.867821138 +0100 +++ new/src/hotspot/share/gc/g1/g1CollectedHeap.cpp 2018-11-27 20:26:33.351818579 +0100 @@ -3738,6 +3738,7 @@ size_t scanned = 0; size_t claimed = 0; size_t skipped = 0; + size_t used_memory = 0; Ticks start = Ticks::now(); Tickspan copy_time; @@ -3754,6 +3755,9 @@ scanned += scan_rs_cl.cards_scanned(); claimed += scan_rs_cl.cards_claimed(); skipped += scan_rs_cl.cards_skipped(); + + // Chunk lists for this region is no longer needed. + used_memory += pss->oops_into_optional_region(hr)->used_memory(); } Tickspan scan_time = (Ticks::now() - start) - copy_time; @@ -3761,9 +3765,10 @@ p->record_or_add_time_secs(G1GCPhaseTimes::OptScanRS, worker_id, scan_time.seconds()); p->record_or_add_time_secs(G1GCPhaseTimes::OptObjCopy, worker_id, copy_time.seconds()); - p->record_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, scanned, G1GCPhaseTimes::OptCSetScannedCards); - p->record_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, claimed, G1GCPhaseTimes::OptCSetClaimedCards); - p->record_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, skipped, G1GCPhaseTimes::OptCSetSkippedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, scanned, G1GCPhaseTimes::OptCSetScannedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, claimed, G1GCPhaseTimes::OptCSetClaimedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, skipped, G1GCPhaseTimes::OptCSetSkippedCards); + p->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_id, used_memory, G1GCPhaseTimes::OptCSetUsedMemory); } void evacuate_live_objects(G1ParScanThreadState* pss, uint worker_id) { @@ -3812,7 +3817,7 @@ } void G1CollectedHeap::evacuate_optional_collection_set(G1ParScanThreadStateSet* per_thread_states) { - G1OptionalCSet optional_cset(&_collection_set); + G1OptionalCSet optional_cset(&_collection_set, per_thread_states); if (optional_cset.is_empty()) { return; } --- old/src/hotspot/share/gc/g1/g1CollectionSet.cpp 2018-11-27 20:26:34.823825879 +0100 +++ new/src/hotspot/share/gc/g1/g1CollectionSet.cpp 2018-11-27 20:26:34.427823915 +0100 @@ -26,6 +26,7 @@ #include "gc/g1/g1CollectedHeap.inline.hpp" #include "gc/g1/g1CollectionSet.hpp" #include "gc/g1/g1CollectorState.hpp" +#include "gc/g1/g1ParScanThreadState.hpp" #include "gc/g1/g1Policy.hpp" #include "gc/g1/heapRegion.inline.hpp" #include "gc/g1/heapRegionRemSet.hpp" @@ -104,6 +105,8 @@ void G1CollectionSet::initialize_optional(uint max_length) { assert(_optional_regions == NULL, "Already initialized"); + assert(_optional_region_length == 0, "Already initialized"); + assert(_optional_region_max_length == 0, "Already initialized"); _optional_region_max_length = max_length; _optional_regions = NEW_C_HEAP_ARRAY(HeapRegion*, _optional_region_max_length, mtGC); } @@ -449,6 +452,7 @@ } bool G1CollectionSet::optional_is_full() { + assert(_optional_region_length <= _optional_region_max_length, "Invariant"); return _optional_region_length == _optional_region_max_length; } @@ -630,6 +634,7 @@ // chooser in reverse order to maintain the old order. HeapRegion* hr = _cset->remove_last_optional_region(); assert(hr != NULL, "Should be valid region left"); + _pset->record_unused_optional_region(hr); g1h->old_set_add(hr); g1h->clear_in_cset(hr); hr->set_index_in_opt_cset(InvalidCSetIndex); --- old/src/hotspot/share/gc/g1/g1CollectionSet.hpp 2018-11-27 20:26:35.727830361 +0100 +++ new/src/hotspot/share/gc/g1/g1CollectionSet.hpp 2018-11-27 20:26:35.331828398 +0100 @@ -32,6 +32,7 @@ class G1CollectedHeap; class G1CollectorState; class G1GCPhaseTimes; +class G1ParScanThreadStateSet; class G1Policy; class G1SurvivorRegions; class HeapRegion; @@ -234,6 +235,7 @@ class G1OptionalCSet : public StackObj { private: G1CollectionSet* _cset; + G1ParScanThreadStateSet* _pset; uint _current_index; uint _current_limit; bool _prepare_failed; @@ -244,8 +246,9 @@ public: static const uint InvalidCSetIndex = UINT_MAX; - G1OptionalCSet(G1CollectionSet* cset) : + G1OptionalCSet(G1CollectionSet* cset, G1ParScanThreadStateSet* pset) : _cset(cset), + _pset(pset), _current_index(0), _current_limit(0), _prepare_failed(false), --- old/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2018-11-27 20:26:36.659834983 +0100 +++ new/src/hotspot/share/gc/g1/g1GCPhaseTimes.cpp 2018-11-27 20:26:36.279833099 +0100 @@ -251,6 +251,10 @@ _gc_par_phases[phase]->set_thread_work_item(worker_i, count, index); } +void G1GCPhaseTimes::record_or_add_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index) { + _gc_par_phases[phase]->set_or_add_thread_work_item(worker_i, count, index); +} + // return the average time for a phase in milliseconds double G1GCPhaseTimes::average_time_ms(GCParPhases phase) { return _gc_par_phases[phase]->average() * 1000.0; --- old/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp 2018-11-27 20:26:37.567839485 +0100 +++ new/src/hotspot/share/gc/g1/g1GCPhaseTimes.hpp 2018-11-27 20:26:37.175837542 +0100 @@ -219,6 +219,8 @@ void record_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index = 0); + void record_or_add_thread_work_item(GCParPhases phase, uint worker_i, size_t count, uint index = 0); + // return the average time for a phase in milliseconds double average_time_ms(GCParPhases phase); --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.cpp 2018-11-27 20:26:38.487844048 +0100 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.cpp 2018-11-27 20:26:38.091842084 +0100 @@ -25,13 +25,11 @@ #include "precompiled.hpp" #include "gc/g1/g1OopStarChunkedList.inline.hpp" -size_t G1OopStarChunkedList::free_chunk_lists() { - size_t freed_memory = 0; - freed_memory += delete_list(_roots); - freed_memory += delete_list(_croots); - freed_memory += delete_list(_oops); - freed_memory += delete_list(_coops); - return freed_memory; +G1OopStarChunkedList::~G1OopStarChunkedList() { + delete_list(_roots); + delete_list(_croots); + delete_list(_oops); + delete_list(_coops); } void G1OopStarChunkedList::oops_do(OopClosure* obj_cl, OopClosure* root_cl) { --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.hpp 2018-11-27 20:26:39.495849046 +0100 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.hpp 2018-11-27 20:26:39.083847003 +0100 @@ -31,12 +31,14 @@ class OopClosure; class G1OopStarChunkedList : public CHeapObj { + size_t _used_memory; + ChunkedList* _roots; ChunkedList* _croots; ChunkedList* _oops; ChunkedList* _coops; - template size_t delete_list(ChunkedList* c); + template void delete_list(ChunkedList* c); template void chunks_do(ChunkedList* head, @@ -46,9 +48,10 @@ inline void push(ChunkedList** field, T* p); public: - G1OopStarChunkedList() : _roots(NULL), _croots(NULL), _oops(NULL), _coops(NULL) {} + G1OopStarChunkedList() : _used_memory(0), _roots(NULL), _croots(NULL), _oops(NULL), _coops(NULL) {} + ~G1OopStarChunkedList(); - size_t free_chunk_lists(); + size_t used_memory() { return _used_memory; } void oops_do(OopClosure* obj_cl, OopClosure* root_cl); --- old/src/hotspot/share/gc/g1/g1OopStarChunkedList.inline.hpp 2018-11-27 20:26:40.455853806 +0100 +++ new/src/hotspot/share/gc/g1/g1OopStarChunkedList.inline.hpp 2018-11-27 20:26:40.031851704 +0100 @@ -35,10 +35,12 @@ ChunkedList* list = *field; if (list == NULL) { *field = new ChunkedList(); + _used_memory += sizeof(ChunkedList); } else if (list->is_full()) { ChunkedList* next = new ChunkedList(); next->set_next_used(list); *field = next; + _used_memory += sizeof(ChunkedList); } (*field)->push(p); @@ -61,16 +63,12 @@ } template -size_t G1OopStarChunkedList::delete_list(ChunkedList* c) { - size_t freed = 0; - size_t chunk_size = sizeof(ChunkedList); +void G1OopStarChunkedList::delete_list(ChunkedList* c) { while (c != NULL) { ChunkedList* next = c->next_used(); - freed += chunk_size; delete c; c = next; } - return freed; } template --- old/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2018-11-27 20:26:41.367858329 +0100 +++ new/src/hotspot/share/gc/g1/g1ParScanThreadState.cpp 2018-11-27 20:26:40.975856385 +0100 @@ -83,10 +83,7 @@ _closures = G1EvacuationRootClosures::create_root_closures(this, _g1h); - _oops_into_optional_regions = NEW_C_HEAP_ARRAY(G1OopStarChunkedList, _num_optional_regions, mtGC); - for (size_t i = 0; i < _num_optional_regions; i++) { - ::new (_oops_into_optional_regions + i) G1OopStarChunkedList(); - } + _oops_into_optional_regions = new G1OopStarChunkedList[_num_optional_regions]; } // Pass locally gathered statistics to global state. @@ -106,12 +103,7 @@ delete _plab_allocator; delete _closures; FREE_C_HEAP_ARRAY(size_t, _surviving_young_words_base); - size_t used_by_optional = 0; - for (size_t i = 0; i < _num_optional_regions; i++) { - used_by_optional += _oops_into_optional_regions[i].free_chunk_lists(); - } - _g1h->g1_policy()->phase_times()->record_thread_work_item(G1GCPhaseTimes::OptScanRS, _worker_id, used_by_optional, G1GCPhaseTimes::OptCSetUsedMemory); - FREE_C_HEAP_ARRAY(G1OopStarChunkedList, _oops_into_optional_regions); + delete[] _oops_into_optional_regions; } void G1ParScanThreadState::waste(size_t& wasted, size_t& undo_wasted) { @@ -367,6 +359,19 @@ _flushed = true; } +void G1ParScanThreadStateSet::record_unused_optional_region(HeapRegion* hr) { + for (uint worker_index = 0; worker_index < _n_workers; ++worker_index) { + G1ParScanThreadState* pss = _states[worker_index]; + + if (pss == NULL) { + continue; + } + + size_t used_memory = pss->oops_into_optional_region(hr)->used_memory(); + _g1h->g1_policy()->phase_times()->record_or_add_thread_work_item(G1GCPhaseTimes::OptScanRS, worker_index, used_memory, G1GCPhaseTimes::OptCSetUsedMemory); + } +} + oop G1ParScanThreadState::handle_evacuation_failure_par(oop old, markOop m) { assert(_g1h->is_in_cset(old), "Object " PTR_FORMAT " should be in the CSet", p2i(old)); --- old/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp 2018-11-27 20:26:42.271862811 +0100 +++ new/src/hotspot/share/gc/g1/g1ParScanThreadState.hpp 2018-11-27 20:26:41.879860868 +0100 @@ -239,6 +239,7 @@ ~G1ParScanThreadStateSet(); void flush(); + void record_unused_optional_region(HeapRegion* hr); G1ParScanThreadState* state_for_worker(uint worker_id); --- old/src/hotspot/share/gc/shared/workerDataArray.hpp 2018-11-27 20:26:43.211867473 +0100 +++ new/src/hotspot/share/gc/shared/workerDataArray.hpp 2018-11-27 20:26:42.795865410 +0100 @@ -49,6 +49,8 @@ void link_thread_work_items(WorkerDataArray* thread_work_items, uint index = 0); void set_thread_work_item(uint worker_i, size_t value, uint index = 0); void add_thread_work_item(uint worker_i, size_t value, uint index = 0); + void set_or_add_thread_work_item(uint worker_i, size_t value, uint index = 0); + WorkerDataArray* thread_work_items(uint index = 0) const { assert(index < MaxThreadWorkItems, "Tried to access thread work item %u max %u", index, MaxThreadWorkItems); return _thread_work_items[index]; --- old/src/hotspot/share/gc/shared/workerDataArray.inline.hpp 2018-11-27 20:26:44.195872352 +0100 +++ new/src/hotspot/share/gc/shared/workerDataArray.inline.hpp 2018-11-27 20:26:43.759870190 +0100 @@ -81,6 +81,17 @@ } template +void WorkerDataArray::set_or_add_thread_work_item(uint worker_i, size_t value, uint index) { + assert(index < MaxThreadWorkItems, "Tried to access thread work item %u (max %u)", index, MaxThreadWorkItems); + assert(_thread_work_items[index] != NULL, "No sub count"); + if (_thread_work_items[index]->get(worker_i) == _thread_work_items[index]->uninitialized()) { + _thread_work_items[index]->set(worker_i, value); + } else { + _thread_work_items[index]->add(worker_i, value); + } +} + +template void WorkerDataArray::add(uint worker_i, T value) { assert(worker_i < _length, "Worker %d is greater than max: %d", worker_i, _length); assert(_data[worker_i] != uninitialized(), "No data to add to for worker %d", worker_i);