2016-03-07 17:23:59 +01:00
/*
2019-02-08 12:55:20 +01:00
* Copyright ( c ) 2016 , 2019 , Oracle and / or its affiliates . All rights reserved .
2016-03-07 17:23:59 +01:00
* 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"
2018-12-07 13:54:45 +01:00
# include "gc/g1/g1CollectedHeap.inline.hpp"
2016-03-07 17:23:59 +01:00
# include "gc/g1/g1CollectionSet.hpp"
2019-02-08 12:55:20 +01:00
# include "gc/g1/g1CollectionSetCandidates.hpp"
2016-03-07 17:23:59 +01:00
# include "gc/g1/g1CollectorState.hpp"
2018-12-07 13:54:45 +01:00
# include "gc/g1/g1ParScanThreadState.hpp"
2016-03-18 15:20:43 +01:00
# include "gc/g1/g1Policy.hpp"
2016-03-07 17:23:59 +01:00
# include "gc/g1/heapRegion.inline.hpp"
# include "gc/g1/heapRegionRemSet.hpp"
# include "gc/g1/heapRegionSet.hpp"
2016-07-06 11:22:55 +02:00
# include "logging/logStream.hpp"
2016-03-07 17:23:59 +01:00
# include "utilities/debug.hpp"
2018-12-07 13:54:45 +01:00
# include "utilities/globalDefinitions.hpp"
2016-09-12 09:34:51 +02:00
# include "utilities/quickSort.hpp"
2016-03-07 17:23:59 +01:00
G1CollectorState * G1CollectionSet : : collector_state ( ) {
2018-04-18 11:36:48 +02:00
return _g1h - > collector_state ( ) ;
2016-03-07 17:23:59 +01:00
}
G1GCPhaseTimes * G1CollectionSet : : phase_times ( ) {
return _policy - > phase_times ( ) ;
}
double G1CollectionSet : : predict_region_elapsed_time_ms ( HeapRegion * hr ) {
2018-03-29 14:07:59 +02:00
return _policy - > predict_region_elapsed_time_ms ( hr , collector_state ( ) - > in_young_only_phase ( ) ) ;
2016-03-07 17:23:59 +01:00
}
2016-03-18 15:20:43 +01:00
G1CollectionSet : : G1CollectionSet ( G1CollectedHeap * g1h , G1Policy * policy ) :
2018-04-18 11:36:48 +02:00
_g1h ( g1h ) ,
2016-03-18 15:20:43 +01:00
_policy ( policy ) ,
2019-02-08 12:55:20 +01:00
_candidates ( NULL ) ,
2016-03-07 17:23:59 +01:00
_eden_region_length ( 0 ) ,
_survivor_region_length ( 0 ) ,
_old_region_length ( 0 ) ,
2016-07-06 11:22:55 +02:00
_collection_set_regions ( NULL ) ,
_collection_set_cur_length ( 0 ) ,
_collection_set_max_length ( 0 ) ,
2018-12-07 13:54:45 +01:00
_optional_regions ( NULL ) ,
_optional_region_length ( 0 ) ,
_optional_region_max_length ( 0 ) ,
2018-08-08 15:31:06 +02:00
_bytes_used_before ( 0 ) ,
_recorded_rs_lengths ( 0 ) ,
2016-03-07 17:23:59 +01:00
_inc_build_state ( Inactive ) ,
_inc_bytes_used_before ( 0 ) ,
_inc_recorded_rs_lengths ( 0 ) ,
_inc_recorded_rs_lengths_diffs ( 0 ) ,
_inc_predicted_elapsed_time_ms ( 0.0 ) ,
2016-07-06 11:22:55 +02:00
_inc_predicted_elapsed_time_ms_diffs ( 0.0 ) {
}
2016-03-07 17:23:59 +01:00
G1CollectionSet : : ~ G1CollectionSet ( ) {
2016-07-06 11:22:55 +02:00
if ( _collection_set_regions ! = NULL ) {
FREE_C_HEAP_ARRAY ( uint , _collection_set_regions ) ;
}
2018-12-07 13:54:45 +01:00
free_optional_regions ( ) ;
2019-02-08 12:55:20 +01:00
clear_candidates ( ) ;
2016-03-07 17:23:59 +01:00
}
void G1CollectionSet : : init_region_lengths ( uint eden_cset_region_length ,
uint survivor_cset_region_length ) {
2018-03-03 23:56:08 -05:00
assert_at_safepoint_on_vm_thread ( ) ;
2016-07-06 11:22:55 +02:00
2016-03-07 17:23:59 +01:00
_eden_region_length = eden_cset_region_length ;
_survivor_region_length = survivor_cset_region_length ;
2016-04-27 11:25:16 +02:00
2016-07-06 11:22:55 +02:00
assert ( ( size_t ) young_region_length ( ) = = _collection_set_cur_length ,
" Young region length %u should match collection set length " SIZE_FORMAT , young_region_length ( ) , _collection_set_cur_length ) ;
2016-04-27 11:25:16 +02:00
2016-03-07 17:23:59 +01:00
_old_region_length = 0 ;
2018-12-07 13:54:45 +01:00
_optional_region_length = 0 ;
2016-03-07 17:23:59 +01:00
}
2016-07-06 11:22:55 +02:00
void G1CollectionSet : : initialize ( uint max_region_length ) {
guarantee ( _collection_set_regions = = NULL , " Must only initialize once. " ) ;
_collection_set_max_length = max_region_length ;
_collection_set_regions = NEW_C_HEAP_ARRAY ( uint , max_region_length , mtGC ) ;
}
2018-12-07 13:54:45 +01:00
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 ) ;
}
void G1CollectionSet : : free_optional_regions ( ) {
_optional_region_length = 0 ;
_optional_region_max_length = 0 ;
if ( _optional_regions ! = NULL ) {
FREE_C_HEAP_ARRAY ( HeapRegion * , _optional_regions ) ;
_optional_regions = NULL ;
}
}
2019-02-08 12:55:20 +01:00
void G1CollectionSet : : clear_candidates ( ) {
delete _candidates ;
_candidates = NULL ;
}
2016-03-07 17:23:59 +01:00
void G1CollectionSet : : set_recorded_rs_lengths ( size_t rs_lengths ) {
_recorded_rs_lengths = rs_lengths ;
}
// Add the heap region at the head of the non-incremental collection set
void G1CollectionSet : : add_old_region ( HeapRegion * hr ) {
2018-03-03 23:56:08 -05:00
assert_at_safepoint_on_vm_thread ( ) ;
2016-07-06 11:22:55 +02:00
2018-12-07 13:54:45 +01:00
assert ( _inc_build_state = = Active | | hr - > index_in_opt_cset ( ) ! = G1OptionalCSet : : InvalidCSetIndex ,
" Precondition, actively building cset or adding optional later on " ) ;
2016-03-07 17:23:59 +01:00
assert ( hr - > is_old ( ) , " the region should be old " ) ;
assert ( ! hr - > in_collection_set ( ) , " should not already be in the CSet " ) ;
2018-04-18 11:36:48 +02:00
_g1h - > register_old_region_with_cset ( hr ) ;
2016-07-06 11:22:55 +02:00
_collection_set_regions [ _collection_set_cur_length + + ] = hr - > hrm_index ( ) ;
assert ( _collection_set_cur_length < = _collection_set_max_length , " Collection set now larger than maximum size. " ) ;
2016-03-07 17:23:59 +01:00
_bytes_used_before + = hr - > used ( ) ;
size_t rs_length = hr - > rem_set ( ) - > occupied ( ) ;
_recorded_rs_lengths + = rs_length ;
_old_region_length + = 1 ;
2018-12-07 13:54:45 +01:00
log_trace ( gc , cset ) ( " Added old region %d to collection set " , hr - > hrm_index ( ) ) ;
}
void G1CollectionSet : : add_optional_region ( HeapRegion * hr ) {
assert ( ! optional_is_full ( ) , " Precondition, must have room left for this region " ) ;
assert ( hr - > is_old ( ) , " the region should be old " ) ;
assert ( ! hr - > in_collection_set ( ) , " should not already be in the CSet " ) ;
_g1h - > register_optional_region_with_cset ( hr ) ;
_optional_regions [ _optional_region_length ] = hr ;
uint index = _optional_region_length + + ;
hr - > set_index_in_opt_cset ( index ) ;
log_trace ( gc , cset ) ( " Added region %d to optional collection set (%u) " , hr - > hrm_index ( ) , _optional_region_length ) ;
2016-03-07 17:23:59 +01:00
}
// Initialize the per-collection-set information
void G1CollectionSet : : start_incremental_building ( ) {
2016-07-06 11:22:55 +02:00
assert ( _collection_set_cur_length = = 0 , " Collection set must be empty before starting a new collection set. " ) ;
2016-03-07 17:23:59 +01:00
assert ( _inc_build_state = = Inactive , " Precondition " ) ;
_inc_bytes_used_before = 0 ;
_inc_recorded_rs_lengths = 0 ;
_inc_recorded_rs_lengths_diffs = 0 ;
_inc_predicted_elapsed_time_ms = 0.0 ;
_inc_predicted_elapsed_time_ms_diffs = 0.0 ;
_inc_build_state = Active ;
}
void G1CollectionSet : : finalize_incremental_building ( ) {
assert ( _inc_build_state = = Active , " Precondition " ) ;
assert ( SafepointSynchronize : : is_at_safepoint ( ) , " should be at a safepoint " ) ;
// The two "main" fields, _inc_recorded_rs_lengths and
// _inc_predicted_elapsed_time_ms, are updated by the thread
// that adds a new region to the CSet. Further updates by the
// concurrent refinement thread that samples the young RSet lengths
// are accumulated in the *_diffs fields. Here we add the diffs to
// the "main" fields.
if ( _inc_recorded_rs_lengths_diffs > = 0 ) {
_inc_recorded_rs_lengths + = _inc_recorded_rs_lengths_diffs ;
} else {
// This is defensive. The diff should in theory be always positive
// as RSets can only grow between GCs. However, given that we
// sample their size concurrently with other threads updating them
// it's possible that we might get the wrong size back, which
// could make the calculations somewhat inaccurate.
size_t diffs = ( size_t ) ( - _inc_recorded_rs_lengths_diffs ) ;
if ( _inc_recorded_rs_lengths > = diffs ) {
_inc_recorded_rs_lengths - = diffs ;
} else {
_inc_recorded_rs_lengths = 0 ;
}
}
_inc_predicted_elapsed_time_ms + = _inc_predicted_elapsed_time_ms_diffs ;
_inc_recorded_rs_lengths_diffs = 0 ;
_inc_predicted_elapsed_time_ms_diffs = 0.0 ;
}
2016-07-06 11:22:55 +02:00
void G1CollectionSet : : clear ( ) {
2018-03-03 23:56:08 -05:00
assert_at_safepoint_on_vm_thread ( ) ;
2016-07-06 11:22:55 +02:00
_collection_set_cur_length = 0 ;
2018-12-07 13:54:45 +01:00
_optional_region_length = 0 ;
2016-07-06 11:22:55 +02:00
}
void G1CollectionSet : : iterate ( HeapRegionClosure * cl ) const {
iterate_from ( cl , 0 , 1 ) ;
}
void G1CollectionSet : : iterate_from ( HeapRegionClosure * cl , uint worker_id , uint total_workers ) const {
size_t len = _collection_set_cur_length ;
OrderAccess : : loadload ( ) ;
if ( len = = 0 ) {
return ;
}
size_t start_pos = ( worker_id * len ) / total_workers ;
size_t cur_pos = start_pos ;
do {
2018-04-18 11:36:48 +02:00
HeapRegion * r = _g1h - > region_at ( _collection_set_regions [ cur_pos ] ) ;
2018-02-09 13:09:55 +01:00
bool result = cl - > do_heap_region ( r ) ;
2016-07-06 11:22:55 +02:00
if ( result ) {
2018-02-09 13:09:55 +01:00
cl - > set_incomplete ( ) ;
2016-07-06 11:22:55 +02:00
return ;
}
cur_pos + + ;
if ( cur_pos = = len ) {
cur_pos = 0 ;
}
} while ( cur_pos ! = start_pos ) ;
}
2016-03-07 17:23:59 +01:00
void G1CollectionSet : : update_young_region_prediction ( HeapRegion * hr ,
size_t new_rs_length ) {
// Update the CSet information that is dependent on the new RS length
assert ( hr - > is_young ( ) , " Precondition " ) ;
assert ( ! SafepointSynchronize : : is_at_safepoint ( ) , " should not be at a safepoint " ) ;
// We could have updated _inc_recorded_rs_lengths and
// _inc_predicted_elapsed_time_ms directly but we'd need to do
// that atomically, as this code is executed by a concurrent
// refinement thread, potentially concurrently with a mutator thread
// allocating a new region and also updating the same fields. To
// avoid the atomic operations we accumulate these updates on two
// separate fields (*_diffs) and we'll just add them to the "main"
// fields at the start of a GC.
ssize_t old_rs_length = ( ssize_t ) hr - > recorded_rs_length ( ) ;
ssize_t rs_lengths_diff = ( ssize_t ) new_rs_length - old_rs_length ;
_inc_recorded_rs_lengths_diffs + = rs_lengths_diff ;
double old_elapsed_time_ms = hr - > predicted_elapsed_time_ms ( ) ;
double new_region_elapsed_time_ms = predict_region_elapsed_time_ms ( hr ) ;
double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms ;
_inc_predicted_elapsed_time_ms_diffs + = elapsed_ms_diff ;
hr - > set_recorded_rs_length ( new_rs_length ) ;
hr - > set_predicted_elapsed_time_ms ( new_region_elapsed_time_ms ) ;
}
void G1CollectionSet : : add_young_region_common ( HeapRegion * hr ) {
assert ( hr - > is_young ( ) , " invariant " ) ;
assert ( _inc_build_state = = Active , " Precondition " ) ;
2016-07-06 11:22:55 +02:00
size_t collection_set_length = _collection_set_cur_length ;
assert ( collection_set_length < = INT_MAX , " Collection set is too large with %d entries " , ( int ) collection_set_length ) ;
hr - > set_young_index_in_cset ( ( int ) collection_set_length ) ;
_collection_set_regions [ collection_set_length ] = hr - > hrm_index ( ) ;
// Concurrent readers must observe the store of the value in the array before an
// update to the length field.
OrderAccess : : storestore ( ) ;
_collection_set_cur_length + + ;
assert ( _collection_set_cur_length < = _collection_set_max_length , " Collection set larger than maximum allowed. " ) ;
2016-04-27 11:25:16 +02:00
2016-03-07 17:23:59 +01:00
// This routine is used when:
// * adding survivor regions to the incremental cset at the end of an
// evacuation pause or
// * adding the current allocation region to the incremental cset
// when it is retired.
// Therefore this routine may be called at a safepoint by the
// VM thread, or in-between safepoints by mutator threads (when
// retiring the current allocation region)
// We need to clear and set the cached recorded/cached collection set
// information in the heap region here (before the region gets added
// to the collection set). An individual heap region's cached values
// are calculated, aggregated with the policy collection set info,
// and cached in the heap region here (initially) and (subsequently)
// by the Young List sampling code.
2018-03-29 14:07:59 +02:00
// Ignore calls to this due to retirement during full gc.
2018-04-18 11:36:48 +02:00
if ( ! _g1h - > collector_state ( ) - > in_full_gc ( ) ) {
2018-03-29 14:07:59 +02:00
size_t rs_length = hr - > rem_set ( ) - > occupied ( ) ;
double region_elapsed_time_ms = predict_region_elapsed_time_ms ( hr ) ;
// Cache the values we have added to the aggregated information
// in the heap region in case we have to remove this region from
// the incremental collection set, or it is updated by the
// rset sampling code
hr - > set_recorded_rs_length ( rs_length ) ;
hr - > set_predicted_elapsed_time_ms ( region_elapsed_time_ms ) ;
_inc_recorded_rs_lengths + = rs_length ;
_inc_predicted_elapsed_time_ms + = region_elapsed_time_ms ;
_inc_bytes_used_before + = hr - > used ( ) ;
}
2016-03-07 17:23:59 +01:00
assert ( ! hr - > in_collection_set ( ) , " invariant " ) ;
2018-04-18 11:36:48 +02:00
_g1h - > register_young_region_with_cset ( hr ) ;
2016-03-07 17:23:59 +01:00
}
void G1CollectionSet : : add_survivor_regions ( HeapRegion * hr ) {
2016-07-06 11:22:55 +02:00
assert ( hr - > is_survivor ( ) , " Must only add survivor regions, but is %s " , hr - > get_type_str ( ) ) ;
add_young_region_common ( hr ) ;
}
2016-03-07 17:23:59 +01:00
2016-07-06 11:22:55 +02:00
void G1CollectionSet : : add_eden_region ( HeapRegion * hr ) {
assert ( hr - > is_eden ( ) , " Must only add eden regions, but is %s " , hr - > get_type_str ( ) ) ;
2016-03-07 17:23:59 +01:00
add_young_region_common ( hr ) ;
2016-07-06 11:22:55 +02:00
}
2016-03-07 17:23:59 +01:00
2016-07-06 11:22:55 +02:00
# ifndef PRODUCT
class G1VerifyYoungAgesClosure : public HeapRegionClosure {
public :
bool _valid ;
public :
G1VerifyYoungAgesClosure ( ) : HeapRegionClosure ( ) , _valid ( true ) { }
2018-02-09 13:09:55 +01:00
virtual bool do_heap_region ( HeapRegion * r ) {
2016-07-06 11:22:55 +02:00
guarantee ( r - > is_young ( ) , " Region must be young but is %s " , r - > get_type_str ( ) ) ;
SurvRateGroup * group = r - > surv_rate_group ( ) ;
if ( group = = NULL ) {
log_error ( gc , verify ) ( " ## encountered NULL surv_rate_group in young region " ) ;
_valid = false ;
}
if ( r - > age_in_surv_rate_group ( ) < 0 ) {
log_error ( gc , verify ) ( " ## encountered negative age in young region " ) ;
_valid = false ;
}
return false ;
2016-03-07 17:23:59 +01:00
}
2016-07-06 11:22:55 +02:00
bool valid ( ) const { return _valid ; }
} ;
2016-03-07 17:23:59 +01:00
2016-07-06 11:22:55 +02:00
bool G1CollectionSet : : verify_young_ages ( ) {
2018-03-03 23:56:08 -05:00
assert_at_safepoint_on_vm_thread ( ) ;
2016-07-06 11:22:55 +02:00
G1VerifyYoungAgesClosure cl ;
iterate ( & cl ) ;
2016-03-07 17:23:59 +01:00
2016-07-06 11:22:55 +02:00
if ( ! cl . valid ( ) ) {
LogStreamHandle ( Error , gc , verify ) log ;
print ( & log ) ;
2016-03-07 17:23:59 +01:00
}
2016-07-06 11:22:55 +02:00
return cl . valid ( ) ;
2016-03-07 17:23:59 +01:00
}
2018-08-21 13:17:29 -07:00
class G1PrintCollectionSetDetailClosure : public HeapRegionClosure {
2016-07-06 11:22:55 +02:00
outputStream * _st ;
public :
2018-08-21 13:17:29 -07:00
G1PrintCollectionSetDetailClosure ( outputStream * st ) : HeapRegionClosure ( ) , _st ( st ) { }
2016-07-06 11:22:55 +02:00
2018-02-09 13:09:55 +01:00
virtual bool do_heap_region ( HeapRegion * r ) {
2016-07-06 11:22:55 +02:00
assert ( r - > in_collection_set ( ) , " Region %u should be in collection set " , r - > hrm_index ( ) ) ;
_st - > print_cr ( " " HR_FORMAT " , P: " PTR_FORMAT " N: " PTR_FORMAT " , age: %4d " ,
HR_FORMAT_PARAMS ( r ) ,
p2i ( r - > prev_top_at_mark_start ( ) ) ,
p2i ( r - > next_top_at_mark_start ( ) ) ,
r - > age_in_surv_rate_group_cond ( ) ) ;
return false ;
}
} ;
2016-03-07 17:23:59 +01:00
2016-07-06 11:22:55 +02:00
void G1CollectionSet : : print ( outputStream * st ) {
2016-03-07 17:23:59 +01:00
st - > print_cr ( " \n Collection_set: " ) ;
2016-07-06 11:22:55 +02:00
2018-08-21 13:17:29 -07:00
G1PrintCollectionSetDetailClosure cl ( st ) ;
2016-07-06 11:22:55 +02:00
iterate ( & cl ) ;
2016-03-07 17:23:59 +01:00
}
# endif // !PRODUCT
2016-05-03 12:33:10 +02:00
double G1CollectionSet : : finalize_young_part ( double target_pause_time_ms , G1SurvivorRegions * survivors ) {
2016-03-07 17:23:59 +01:00
double young_start_time_sec = os : : elapsedTime ( ) ;
finalize_incremental_building ( ) ;
guarantee ( target_pause_time_ms > 0.0 ,
" target_pause_time_ms = %1.6lf should be positive " , target_pause_time_ms ) ;
size_t pending_cards = _policy - > pending_cards ( ) ;
double base_time_ms = _policy - > predict_base_elapsed_time_ms ( pending_cards ) ;
double time_remaining_ms = MAX2 ( target_pause_time_ms - base_time_ms , 0.0 ) ;
log_trace ( gc , ergo , cset ) ( " Start choosing CSet. pending cards: " SIZE_FORMAT " predicted base time: %1.2fms remaining time: %1.2fms target pause time: %1.2fms " ,
pending_cards , base_time_ms , time_remaining_ms , target_pause_time_ms ) ;
// The young list is laid with the survivor regions from the previous
// pause are appended to the RHS of the young list, i.e.
// [Newly Young Regions ++ Survivors from last pause].
2016-05-03 12:33:10 +02:00
uint survivor_region_length = survivors - > length ( ) ;
2018-04-18 11:36:48 +02:00
uint eden_region_length = _g1h - > eden_regions_count ( ) ;
2016-03-07 17:23:59 +01:00
init_region_lengths ( eden_region_length , survivor_region_length ) ;
2016-04-27 11:25:16 +02:00
verify_young_cset_indices ( ) ;
2016-03-07 17:23:59 +01:00
// Clear the fields that point to the survivor list - they are all young now.
2016-05-03 12:33:10 +02:00
survivors - > convert_to_eden ( ) ;
2016-03-07 17:23:59 +01:00
_bytes_used_before = _inc_bytes_used_before ;
time_remaining_ms = MAX2 ( time_remaining_ms - _inc_predicted_elapsed_time_ms , 0.0 ) ;
log_trace ( gc , ergo , cset ) ( " Add young regions to CSet. eden: %u regions, survivors: %u regions, predicted young region time: %1.2fms, target pause time: %1.2fms " ,
eden_region_length , survivor_region_length , _inc_predicted_elapsed_time_ms , target_pause_time_ms ) ;
// The number of recorded young regions is the incremental
// collection set's current size
set_recorded_rs_lengths ( _inc_recorded_rs_lengths ) ;
double young_end_time_sec = os : : elapsedTime ( ) ;
phase_times ( ) - > record_young_cset_choice_time_ms ( ( young_end_time_sec - young_start_time_sec ) * 1000.0 ) ;
return time_remaining_ms ;
}
2018-12-07 13:54:45 +01:00
void G1CollectionSet : : add_as_old ( HeapRegion * hr ) {
2019-02-08 12:55:20 +01:00
candidates ( ) - > pop_front ( ) ; // already have region via peek()
2018-12-07 13:54:45 +01:00
_g1h - > old_set_remove ( hr ) ;
add_old_region ( hr ) ;
}
void G1CollectionSet : : add_as_optional ( HeapRegion * hr ) {
assert ( _optional_regions ! = NULL , " Must not be called before array is allocated " ) ;
2019-02-08 12:55:20 +01:00
candidates ( ) - > pop_front ( ) ; // already have region via peek()
2018-12-07 13:54:45 +01:00
_g1h - > old_set_remove ( hr ) ;
add_optional_region ( hr ) ;
}
bool G1CollectionSet : : optional_is_full ( ) {
assert ( _optional_region_length < = _optional_region_max_length , " Invariant " ) ;
return _optional_region_length = = _optional_region_max_length ;
}
void G1CollectionSet : : clear_optional_region ( const HeapRegion * hr ) {
assert ( _optional_regions ! = NULL , " Must not be called before array is allocated " ) ;
uint index = hr - > index_in_opt_cset ( ) ;
_optional_regions [ index ] = NULL ;
}
2016-09-12 09:34:51 +02:00
static int compare_region_idx ( const uint a , const uint b ) {
if ( a > b ) {
return 1 ;
} else if ( a = = b ) {
return 0 ;
} else {
return - 1 ;
}
}
2016-03-07 17:23:59 +01:00
void G1CollectionSet : : finalize_old_part ( double time_remaining_ms ) {
double non_young_start_time_sec = os : : elapsedTime ( ) ;
double predicted_old_time_ms = 0.0 ;
2018-12-07 13:54:45 +01:00
double predicted_optional_time_ms = 0.0 ;
double optional_threshold_ms = time_remaining_ms * _policy - > optional_prediction_fraction ( ) ;
uint expensive_region_num = 0 ;
2016-03-07 17:23:59 +01:00
2018-03-29 14:07:59 +02:00
if ( collector_state ( ) - > in_mixed_phase ( ) ) {
2019-02-08 12:55:20 +01:00
candidates ( ) - > verify ( ) ;
2016-03-07 17:23:59 +01:00
const uint min_old_cset_length = _policy - > calc_min_old_cset_length ( ) ;
2018-12-07 13:54:45 +01:00
const uint max_old_cset_length = MAX2 ( min_old_cset_length , _policy - > calc_max_old_cset_length ( ) ) ;
2016-03-07 17:23:59 +01:00
bool check_time_remaining = _policy - > adaptive_young_list_length ( ) ;
2018-12-07 13:54:45 +01:00
initialize_optional ( max_old_cset_length - min_old_cset_length ) ;
log_debug ( gc , ergo , cset ) ( " Start adding old regions for mixed gc. min %u regions, max %u regions, "
" time remaining %1.2fms, optional threshold %1.2fms " ,
min_old_cset_length , max_old_cset_length , time_remaining_ms , optional_threshold_ms ) ;
2019-02-08 12:55:20 +01:00
HeapRegion * hr = candidates ( ) - > peek_front ( ) ;
2016-03-07 17:23:59 +01:00
while ( hr ! = NULL ) {
2018-12-07 13:54:45 +01:00
if ( old_region_length ( ) + optional_region_length ( ) > = max_old_cset_length ) {
2016-03-07 17:23:59 +01:00
// Added maximum number of old regions to the CSet.
2018-12-07 13:54:45 +01:00
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (old CSet region num reached max). "
" old %u regions, optional %u regions " ,
old_region_length ( ) , optional_region_length ( ) ) ;
2016-03-07 17:23:59 +01:00
break ;
}
// Stop adding regions if the remaining reclaimable space is
// not above G1HeapWastePercent.
2019-02-08 12:55:20 +01:00
size_t reclaimable_bytes = candidates ( ) - > remaining_reclaimable_bytes ( ) ;
2017-10-23 11:46:54 +02:00
double reclaimable_percent = _policy - > reclaimable_bytes_percent ( reclaimable_bytes ) ;
2016-03-07 17:23:59 +01:00
double threshold = ( double ) G1HeapWastePercent ;
2017-10-23 11:46:54 +02:00
if ( reclaimable_percent < = threshold ) {
2016-03-07 17:23:59 +01:00
// We've added enough old regions that the amount of uncollected
// reclaimable space is at or below the waste threshold. Stop
// adding old regions to the CSet.
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (reclaimable percentage not over threshold). "
2018-12-07 13:54:45 +01:00
" reclaimable: " SIZE_FORMAT " %s (%1.2f%%) threshold: " UINTX_FORMAT " %% " ,
byte_size_in_proper_unit ( reclaimable_bytes ) , proper_unit_for_byte_size ( reclaimable_bytes ) ,
reclaimable_percent , G1HeapWastePercent ) ;
2016-03-07 17:23:59 +01:00
break ;
}
double predicted_time_ms = predict_region_elapsed_time_ms ( hr ) ;
2018-12-07 13:54:45 +01:00
time_remaining_ms = MAX2 ( time_remaining_ms - predicted_time_ms , 0.0 ) ;
// Add regions to old set until we reach minimum amount
if ( old_region_length ( ) < min_old_cset_length ) {
predicted_old_time_ms + = predicted_time_ms ;
add_as_old ( hr ) ;
// Record the number of regions added when no time remaining
if ( time_remaining_ms = = 0.0 ) {
expensive_region_num + + ;
2016-03-07 17:23:59 +01:00
}
} else {
2018-12-07 13:54:45 +01:00
// In the non-auto-tuning case, we'll finish adding regions
// to the CSet if we reach the minimum.
if ( ! check_time_remaining ) {
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (old CSet region num reached min). " ) ;
break ;
}
// Keep adding regions to old set until we reach optional threshold
if ( time_remaining_ms > optional_threshold_ms ) {
predicted_old_time_ms + = predicted_time_ms ;
add_as_old ( hr ) ;
} else if ( time_remaining_ms > 0 ) {
// Keep adding optional regions until time is up
if ( ! optional_is_full ( ) ) {
predicted_optional_time_ms + = predicted_time_ms ;
add_as_optional ( hr ) ;
} else {
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (optional set full). " ) ;
break ;
}
} else {
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (predicted time is too high). " ) ;
2016-03-07 17:23:59 +01:00
break ;
}
}
2019-02-08 12:55:20 +01:00
hr = candidates ( ) - > peek_front ( ) ;
2016-03-07 17:23:59 +01:00
}
if ( hr = = NULL ) {
log_debug ( gc , ergo , cset ) ( " Finish adding old regions to CSet (candidate old regions not available) " ) ;
}
2019-02-08 12:55:20 +01:00
candidates ( ) - > verify ( ) ;
2016-03-07 17:23:59 +01:00
}
stop_incremental_building ( ) ;
2018-12-07 13:54:45 +01:00
log_debug ( gc , ergo , cset ) ( " Finish choosing CSet regions old: %u, optional: %u, "
" predicted old time: %1.2fms, predicted optional time: %1.2fms, time remaining: %1.2f " ,
old_region_length ( ) , optional_region_length ( ) ,
predicted_old_time_ms , predicted_optional_time_ms , time_remaining_ms ) ;
if ( expensive_region_num > 0 ) {
log_debug ( gc , ergo , cset ) ( " CSet contains %u old regions that were added although the predicted time was too high. " ,
expensive_region_num ) ;
}
2016-03-07 17:23:59 +01:00
double non_young_end_time_sec = os : : elapsedTime ( ) ;
phase_times ( ) - > record_non_young_cset_choice_time_ms ( ( non_young_end_time_sec - non_young_start_time_sec ) * 1000.0 ) ;
2016-09-12 09:34:51 +02:00
2017-08-07 20:58:49 -04:00
QuickSort : : sort ( _collection_set_regions , _collection_set_cur_length , compare_region_idx , true ) ;
2016-03-07 17:23:59 +01:00
}
2016-04-27 11:25:16 +02:00
2018-12-07 13:54:45 +01:00
HeapRegion * G1OptionalCSet : : region_at ( uint index ) {
return _cset - > optional_region_at ( index ) ;
}
void G1OptionalCSet : : prepare_evacuation ( double time_limit ) {
assert ( _current_index = = _current_limit , " Before prepare no regions should be ready for evac " ) ;
uint prepared_regions = 0 ;
double prediction_ms = 0 ;
_prepare_failed = true ;
for ( uint i = _current_index ; i < _cset - > optional_region_length ( ) ; i + + ) {
HeapRegion * hr = region_at ( i ) ;
prediction_ms + = _cset - > predict_region_elapsed_time_ms ( hr ) ;
if ( prediction_ms > time_limit ) {
log_debug ( gc , cset ) ( " Prepared %u regions for optional evacuation. Predicted time: %.3fms " , prepared_regions , prediction_ms ) ;
return ;
}
// This region will be included in the next optional evacuation.
prepare_to_evacuate_optional_region ( hr ) ;
prepared_regions + + ;
_current_limit + + ;
_prepare_failed = false ;
}
log_debug ( gc , cset ) ( " Prepared all %u regions for optional evacuation. Predicted time: %.3fms " ,
prepared_regions , prediction_ms ) ;
}
bool G1OptionalCSet : : prepare_failed ( ) {
return _prepare_failed ;
}
void G1OptionalCSet : : complete_evacuation ( ) {
_evacuation_failed = false ;
for ( uint i = _current_index ; i < _current_limit ; i + + ) {
HeapRegion * hr = region_at ( i ) ;
_cset - > clear_optional_region ( hr ) ;
if ( hr - > evacuation_failed ( ) ) {
_evacuation_failed = true ;
}
}
_current_index = _current_limit ;
}
bool G1OptionalCSet : : evacuation_failed ( ) {
return _evacuation_failed ;
}
G1OptionalCSet : : ~ G1OptionalCSet ( ) {
G1CollectedHeap * g1h = G1CollectedHeap : : heap ( ) ;
while ( ! is_empty ( ) ) {
2019-02-08 12:55:20 +01:00
// We want to return regions not evacuated to the collection set candidates
// in reverse order to maintain the old order.
2018-12-07 13:54:45 +01:00
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 ) ;
2019-02-08 12:55:20 +01:00
_cset - > candidates ( ) - > push_front ( hr ) ;
2018-12-07 13:54:45 +01:00
}
_cset - > free_optional_regions ( ) ;
}
uint G1OptionalCSet : : size ( ) {
return _cset - > optional_region_length ( ) - _current_index ;
}
bool G1OptionalCSet : : is_empty ( ) {
return size ( ) = = 0 ;
}
void G1OptionalCSet : : prepare_to_evacuate_optional_region ( HeapRegion * hr ) {
log_trace ( gc , cset ) ( " Adding region %u for optional evacuation " , hr - > hrm_index ( ) ) ;
G1CollectedHeap : : heap ( ) - > clear_in_cset ( hr ) ;
_cset - > add_old_region ( hr ) ;
}
2016-04-27 11:25:16 +02:00
# ifdef ASSERT
2016-07-06 11:22:55 +02:00
class G1VerifyYoungCSetIndicesClosure : public HeapRegionClosure {
private :
size_t _young_length ;
int * _heap_region_indices ;
public :
G1VerifyYoungCSetIndicesClosure ( size_t young_length ) : HeapRegionClosure ( ) , _young_length ( young_length ) {
_heap_region_indices = NEW_C_HEAP_ARRAY ( int , young_length , mtGC ) ;
for ( size_t i = 0 ; i < young_length ; i + + ) {
_heap_region_indices [ i ] = - 1 ;
}
2016-04-27 11:25:16 +02:00
}
2016-07-06 11:22:55 +02:00
~ G1VerifyYoungCSetIndicesClosure ( ) {
FREE_C_HEAP_ARRAY ( int , _heap_region_indices ) ;
}
2018-02-09 13:09:55 +01:00
virtual bool do_heap_region ( HeapRegion * r ) {
2016-07-06 11:22:55 +02:00
const int idx = r - > young_index_in_cset ( ) ;
assert ( idx > - 1 , " Young index must be set for all regions in the incremental collection set but is not for region %u. " , r - > hrm_index ( ) ) ;
assert ( ( size_t ) idx < _young_length , " Young cset index too large for region %u " , r - > hrm_index ( ) ) ;
2016-04-27 11:25:16 +02:00
2016-07-06 11:22:55 +02:00
assert ( _heap_region_indices [ idx ] = = - 1 ,
" Index %d used by multiple regions, first use by region %u, second by region %u " ,
idx , _heap_region_indices [ idx ] , r - > hrm_index ( ) ) ;
2016-04-27 11:25:16 +02:00
2016-07-06 11:22:55 +02:00
_heap_region_indices [ idx ] = r - > hrm_index ( ) ;
2016-04-27 11:25:16 +02:00
2016-07-06 11:22:55 +02:00
return false ;
2016-04-27 11:25:16 +02:00
}
2016-07-06 11:22:55 +02:00
} ;
void G1CollectionSet : : verify_young_cset_indices ( ) const {
2018-03-03 23:56:08 -05:00
assert_at_safepoint_on_vm_thread ( ) ;
2016-07-06 11:22:55 +02:00
G1VerifyYoungCSetIndicesClosure cl ( _collection_set_cur_length ) ;
iterate ( & cl ) ;
2016-04-27 11:25:16 +02:00
}
# endif