113 |
114 |
114 _recent_avg_pause_time_ratio(0.0), |
115 _recent_avg_pause_time_ratio(0.0), |
115 _rs_lengths_prediction(0), |
116 _rs_lengths_prediction(0), |
116 _max_survivor_regions(0), |
117 _max_survivor_regions(0), |
117 |
118 |
118 _eden_cset_region_length(0), |
|
119 _survivor_cset_region_length(0), |
|
120 _old_cset_region_length(0), |
|
121 |
|
122 _collection_set(NULL), |
|
123 _collection_set_bytes_used_before(0), |
|
124 |
|
125 // Incremental CSet attributes |
|
126 _inc_cset_build_state(Inactive), |
|
127 _inc_cset_head(NULL), |
|
128 _inc_cset_tail(NULL), |
|
129 _inc_cset_bytes_used_before(0), |
|
130 _inc_cset_recorded_rs_lengths(0), |
|
131 _inc_cset_recorded_rs_lengths_diffs(0), |
|
132 _inc_cset_predicted_elapsed_time_ms(0.0), |
|
133 _inc_cset_predicted_elapsed_time_ms_diffs(0.0), |
|
134 |
|
135 // add here any more surv rate groups |
119 // add here any more surv rate groups |
136 _recorded_survivor_regions(0), |
120 _recorded_survivor_regions(0), |
137 _recorded_survivor_head(NULL), |
121 _recorded_survivor_head(NULL), |
138 _recorded_survivor_tail(NULL), |
122 _recorded_survivor_tail(NULL), |
139 _survivors_age_table(true), |
123 _survivors_age_table(true), |
1816 _prev_collection_pause_end_ms += elapsed_time_ms; |
1794 _prev_collection_pause_end_ms += elapsed_time_ms; |
1817 |
1795 |
1818 record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); |
1796 record_pause(Cleanup, _mark_cleanup_start_sec, end_sec); |
1819 } |
1797 } |
1820 |
1798 |
1821 // Add the heap region at the head of the non-incremental collection set |
|
1822 void G1CollectorPolicy::add_old_region_to_cset(HeapRegion* hr) { |
|
1823 assert(_inc_cset_build_state == Active, "Precondition"); |
|
1824 assert(hr->is_old(), "the region should be old"); |
|
1825 |
|
1826 assert(!hr->in_collection_set(), "should not already be in the CSet"); |
|
1827 _g1->register_old_region_with_cset(hr); |
|
1828 hr->set_next_in_collection_set(_collection_set); |
|
1829 _collection_set = hr; |
|
1830 _collection_set_bytes_used_before += hr->used(); |
|
1831 size_t rs_length = hr->rem_set()->occupied(); |
|
1832 _recorded_rs_lengths += rs_length; |
|
1833 _old_cset_region_length += 1; |
|
1834 } |
|
1835 |
|
1836 // Initialize the per-collection-set information |
|
1837 void G1CollectorPolicy::start_incremental_cset_building() { |
|
1838 assert(_inc_cset_build_state == Inactive, "Precondition"); |
|
1839 |
|
1840 _inc_cset_head = NULL; |
|
1841 _inc_cset_tail = NULL; |
|
1842 _inc_cset_bytes_used_before = 0; |
|
1843 |
|
1844 _inc_cset_recorded_rs_lengths = 0; |
|
1845 _inc_cset_recorded_rs_lengths_diffs = 0; |
|
1846 _inc_cset_predicted_elapsed_time_ms = 0.0; |
|
1847 _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; |
|
1848 _inc_cset_build_state = Active; |
|
1849 } |
|
1850 |
|
1851 void G1CollectorPolicy::finalize_incremental_cset_building() { |
|
1852 assert(_inc_cset_build_state == Active, "Precondition"); |
|
1853 assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); |
|
1854 |
|
1855 // The two "main" fields, _inc_cset_recorded_rs_lengths and |
|
1856 // _inc_cset_predicted_elapsed_time_ms, are updated by the thread |
|
1857 // that adds a new region to the CSet. Further updates by the |
|
1858 // concurrent refinement thread that samples the young RSet lengths |
|
1859 // are accumulated in the *_diffs fields. Here we add the diffs to |
|
1860 // the "main" fields. |
|
1861 |
|
1862 if (_inc_cset_recorded_rs_lengths_diffs >= 0) { |
|
1863 _inc_cset_recorded_rs_lengths += _inc_cset_recorded_rs_lengths_diffs; |
|
1864 } else { |
|
1865 // This is defensive. The diff should in theory be always positive |
|
1866 // as RSets can only grow between GCs. However, given that we |
|
1867 // sample their size concurrently with other threads updating them |
|
1868 // it's possible that we might get the wrong size back, which |
|
1869 // could make the calculations somewhat inaccurate. |
|
1870 size_t diffs = (size_t) (-_inc_cset_recorded_rs_lengths_diffs); |
|
1871 if (_inc_cset_recorded_rs_lengths >= diffs) { |
|
1872 _inc_cset_recorded_rs_lengths -= diffs; |
|
1873 } else { |
|
1874 _inc_cset_recorded_rs_lengths = 0; |
|
1875 } |
|
1876 } |
|
1877 _inc_cset_predicted_elapsed_time_ms += |
|
1878 _inc_cset_predicted_elapsed_time_ms_diffs; |
|
1879 |
|
1880 _inc_cset_recorded_rs_lengths_diffs = 0; |
|
1881 _inc_cset_predicted_elapsed_time_ms_diffs = 0.0; |
|
1882 } |
|
1883 |
|
1884 void G1CollectorPolicy::add_to_incremental_cset_info(HeapRegion* hr, size_t rs_length) { |
|
1885 // This routine is used when: |
|
1886 // * adding survivor regions to the incremental cset at the end of an |
|
1887 // evacuation pause, |
|
1888 // * adding the current allocation region to the incremental cset |
|
1889 // when it is retired, and |
|
1890 // * updating existing policy information for a region in the |
|
1891 // incremental cset via young list RSet sampling. |
|
1892 // Therefore this routine may be called at a safepoint by the |
|
1893 // VM thread, or in-between safepoints by mutator threads (when |
|
1894 // retiring the current allocation region) or a concurrent |
|
1895 // refine thread (RSet sampling). |
|
1896 |
|
1897 double region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); |
|
1898 size_t used_bytes = hr->used(); |
|
1899 _inc_cset_recorded_rs_lengths += rs_length; |
|
1900 _inc_cset_predicted_elapsed_time_ms += region_elapsed_time_ms; |
|
1901 _inc_cset_bytes_used_before += used_bytes; |
|
1902 |
|
1903 // Cache the values we have added to the aggregated information |
|
1904 // in the heap region in case we have to remove this region from |
|
1905 // the incremental collection set, or it is updated by the |
|
1906 // rset sampling code |
|
1907 hr->set_recorded_rs_length(rs_length); |
|
1908 hr->set_predicted_elapsed_time_ms(region_elapsed_time_ms); |
|
1909 } |
|
1910 |
|
1911 void G1CollectorPolicy::update_incremental_cset_info(HeapRegion* hr, |
|
1912 size_t new_rs_length) { |
|
1913 // Update the CSet information that is dependent on the new RS length |
|
1914 assert(hr->is_young(), "Precondition"); |
|
1915 assert(!SafepointSynchronize::is_at_safepoint(), |
|
1916 "should not be at a safepoint"); |
|
1917 |
|
1918 // We could have updated _inc_cset_recorded_rs_lengths and |
|
1919 // _inc_cset_predicted_elapsed_time_ms directly but we'd need to do |
|
1920 // that atomically, as this code is executed by a concurrent |
|
1921 // refinement thread, potentially concurrently with a mutator thread |
|
1922 // allocating a new region and also updating the same fields. To |
|
1923 // avoid the atomic operations we accumulate these updates on two |
|
1924 // separate fields (*_diffs) and we'll just add them to the "main" |
|
1925 // fields at the start of a GC. |
|
1926 |
|
1927 ssize_t old_rs_length = (ssize_t) hr->recorded_rs_length(); |
|
1928 ssize_t rs_lengths_diff = (ssize_t) new_rs_length - old_rs_length; |
|
1929 _inc_cset_recorded_rs_lengths_diffs += rs_lengths_diff; |
|
1930 |
|
1931 double old_elapsed_time_ms = hr->predicted_elapsed_time_ms(); |
|
1932 double new_region_elapsed_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); |
|
1933 double elapsed_ms_diff = new_region_elapsed_time_ms - old_elapsed_time_ms; |
|
1934 _inc_cset_predicted_elapsed_time_ms_diffs += elapsed_ms_diff; |
|
1935 |
|
1936 hr->set_recorded_rs_length(new_rs_length); |
|
1937 hr->set_predicted_elapsed_time_ms(new_region_elapsed_time_ms); |
|
1938 } |
|
1939 |
|
1940 void G1CollectorPolicy::add_region_to_incremental_cset_common(HeapRegion* hr) { |
|
1941 assert(hr->is_young(), "invariant"); |
|
1942 assert(hr->young_index_in_cset() > -1, "should have already been set"); |
|
1943 assert(_inc_cset_build_state == Active, "Precondition"); |
|
1944 |
|
1945 // We need to clear and set the cached recorded/cached collection set |
|
1946 // information in the heap region here (before the region gets added |
|
1947 // to the collection set). An individual heap region's cached values |
|
1948 // are calculated, aggregated with the policy collection set info, |
|
1949 // and cached in the heap region here (initially) and (subsequently) |
|
1950 // by the Young List sampling code. |
|
1951 |
|
1952 size_t rs_length = hr->rem_set()->occupied(); |
|
1953 add_to_incremental_cset_info(hr, rs_length); |
|
1954 |
|
1955 assert(!hr->in_collection_set(), "invariant"); |
|
1956 _g1->register_young_region_with_cset(hr); |
|
1957 assert(hr->next_in_collection_set() == NULL, "invariant"); |
|
1958 } |
|
1959 |
|
1960 // Add the region at the RHS of the incremental cset |
|
1961 void G1CollectorPolicy::add_region_to_incremental_cset_rhs(HeapRegion* hr) { |
|
1962 // We should only ever be appending survivors at the end of a pause |
|
1963 assert(hr->is_survivor(), "Logic"); |
|
1964 |
|
1965 // Do the 'common' stuff |
|
1966 add_region_to_incremental_cset_common(hr); |
|
1967 |
|
1968 // Now add the region at the right hand side |
|
1969 if (_inc_cset_tail == NULL) { |
|
1970 assert(_inc_cset_head == NULL, "invariant"); |
|
1971 _inc_cset_head = hr; |
|
1972 } else { |
|
1973 _inc_cset_tail->set_next_in_collection_set(hr); |
|
1974 } |
|
1975 _inc_cset_tail = hr; |
|
1976 } |
|
1977 |
|
1978 // Add the region to the LHS of the incremental cset |
|
1979 void G1CollectorPolicy::add_region_to_incremental_cset_lhs(HeapRegion* hr) { |
|
1980 // Survivors should be added to the RHS at the end of a pause |
|
1981 assert(hr->is_eden(), "Logic"); |
|
1982 |
|
1983 // Do the 'common' stuff |
|
1984 add_region_to_incremental_cset_common(hr); |
|
1985 |
|
1986 // Add the region at the left hand side |
|
1987 hr->set_next_in_collection_set(_inc_cset_head); |
|
1988 if (_inc_cset_head == NULL) { |
|
1989 assert(_inc_cset_tail == NULL, "Invariant"); |
|
1990 _inc_cset_tail = hr; |
|
1991 } |
|
1992 _inc_cset_head = hr; |
|
1993 } |
|
1994 |
|
1995 #ifndef PRODUCT |
|
1996 void G1CollectorPolicy::print_collection_set(HeapRegion* list_head, outputStream* st) { |
|
1997 assert(list_head == inc_cset_head() || list_head == collection_set(), "must be"); |
|
1998 |
|
1999 st->print_cr("\nCollection_set:"); |
|
2000 HeapRegion* csr = list_head; |
|
2001 while (csr != NULL) { |
|
2002 HeapRegion* next = csr->next_in_collection_set(); |
|
2003 assert(csr->in_collection_set(), "bad CS"); |
|
2004 st->print_cr(" " HR_FORMAT ", P: " PTR_FORMAT "N: " PTR_FORMAT ", age: %4d", |
|
2005 HR_FORMAT_PARAMS(csr), |
|
2006 p2i(csr->prev_top_at_mark_start()), p2i(csr->next_top_at_mark_start()), |
|
2007 csr->age_in_surv_rate_group_cond()); |
|
2008 csr = next; |
|
2009 } |
|
2010 } |
|
2011 #endif // !PRODUCT |
|
2012 |
|
2013 double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { |
1799 double G1CollectorPolicy::reclaimable_bytes_perc(size_t reclaimable_bytes) const { |
2014 // Returns the given amount of reclaimable bytes (that represents |
1800 // Returns the given amount of reclaimable bytes (that represents |
2015 // the amount of reclaimable space still to be collected) as a |
1801 // the amount of reclaimable space still to be collected) as a |
2016 // percentage of the current heap capacity. |
1802 // percentage of the current heap capacity. |
2017 size_t capacity_bytes = _g1->capacity(); |
1803 size_t capacity_bytes = _g1->capacity(); |
2137 result += 1; |
1923 result += 1; |
2138 } |
1924 } |
2139 return (uint) result; |
1925 return (uint) result; |
2140 } |
1926 } |
2141 |
1927 |
2142 |
1928 void G1CollectorPolicy::finalize_collection_set(double target_pause_time_ms) { |
2143 double G1CollectorPolicy::finalize_young_cset_part(double target_pause_time_ms) { |
1929 double time_remaining_ms = _collection_set->finalize_young_part(target_pause_time_ms); |
2144 double young_start_time_sec = os::elapsedTime(); |
1930 _collection_set->finalize_old_part(time_remaining_ms); |
2145 |
1931 } |
2146 YoungList* young_list = _g1->young_list(); |
1932 |
2147 finalize_incremental_cset_building(); |
|
2148 |
|
2149 guarantee(target_pause_time_ms > 0.0, |
|
2150 "target_pause_time_ms = %1.6lf should be positive", target_pause_time_ms); |
|
2151 guarantee(_collection_set == NULL, "Precondition"); |
|
2152 |
|
2153 double base_time_ms = predict_base_elapsed_time_ms(_pending_cards); |
|
2154 double time_remaining_ms = MAX2(target_pause_time_ms - base_time_ms, 0.0); |
|
2155 |
|
2156 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", |
|
2157 _pending_cards, base_time_ms, time_remaining_ms, target_pause_time_ms); |
|
2158 |
|
2159 collector_state()->set_last_gc_was_young(collector_state()->gcs_are_young()); |
|
2160 |
|
2161 // The young list is laid with the survivor regions from the previous |
|
2162 // pause are appended to the RHS of the young list, i.e. |
|
2163 // [Newly Young Regions ++ Survivors from last pause]. |
|
2164 |
|
2165 uint survivor_region_length = young_list->survivor_length(); |
|
2166 uint eden_region_length = young_list->eden_length(); |
|
2167 init_cset_region_lengths(eden_region_length, survivor_region_length); |
|
2168 |
|
2169 HeapRegion* hr = young_list->first_survivor_region(); |
|
2170 while (hr != NULL) { |
|
2171 assert(hr->is_survivor(), "badly formed young list"); |
|
2172 // There is a convention that all the young regions in the CSet |
|
2173 // are tagged as "eden", so we do this for the survivors here. We |
|
2174 // use the special set_eden_pre_gc() as it doesn't check that the |
|
2175 // region is free (which is not the case here). |
|
2176 hr->set_eden_pre_gc(); |
|
2177 hr = hr->get_next_young_region(); |
|
2178 } |
|
2179 |
|
2180 // Clear the fields that point to the survivor list - they are all young now. |
|
2181 young_list->clear_survivors(); |
|
2182 |
|
2183 _collection_set = _inc_cset_head; |
|
2184 _collection_set_bytes_used_before = _inc_cset_bytes_used_before; |
|
2185 time_remaining_ms = MAX2(time_remaining_ms - _inc_cset_predicted_elapsed_time_ms, 0.0); |
|
2186 |
|
2187 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", |
|
2188 eden_region_length, survivor_region_length, _inc_cset_predicted_elapsed_time_ms, target_pause_time_ms); |
|
2189 |
|
2190 // The number of recorded young regions is the incremental |
|
2191 // collection set's current size |
|
2192 set_recorded_rs_lengths(_inc_cset_recorded_rs_lengths); |
|
2193 |
|
2194 double young_end_time_sec = os::elapsedTime(); |
|
2195 phase_times()->record_young_cset_choice_time_ms((young_end_time_sec - young_start_time_sec) * 1000.0); |
|
2196 |
|
2197 return time_remaining_ms; |
|
2198 } |
|
2199 |
|
2200 void G1CollectorPolicy::finalize_old_cset_part(double time_remaining_ms) { |
|
2201 double non_young_start_time_sec = os::elapsedTime(); |
|
2202 double predicted_old_time_ms = 0.0; |
|
2203 |
|
2204 |
|
2205 if (!collector_state()->gcs_are_young()) { |
|
2206 cset_chooser()->verify(); |
|
2207 const uint min_old_cset_length = calc_min_old_cset_length(); |
|
2208 const uint max_old_cset_length = calc_max_old_cset_length(); |
|
2209 |
|
2210 uint expensive_region_num = 0; |
|
2211 bool check_time_remaining = adaptive_young_list_length(); |
|
2212 |
|
2213 HeapRegion* hr = cset_chooser()->peek(); |
|
2214 while (hr != NULL) { |
|
2215 if (old_cset_region_length() >= max_old_cset_length) { |
|
2216 // Added maximum number of old regions to the CSet. |
|
2217 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached max). old %u regions, max %u regions", |
|
2218 old_cset_region_length(), max_old_cset_length); |
|
2219 break; |
|
2220 } |
|
2221 |
|
2222 |
|
2223 // Stop adding regions if the remaining reclaimable space is |
|
2224 // not above G1HeapWastePercent. |
|
2225 size_t reclaimable_bytes = cset_chooser()->remaining_reclaimable_bytes(); |
|
2226 double reclaimable_perc = reclaimable_bytes_perc(reclaimable_bytes); |
|
2227 double threshold = (double) G1HeapWastePercent; |
|
2228 if (reclaimable_perc <= threshold) { |
|
2229 // We've added enough old regions that the amount of uncollected |
|
2230 // reclaimable space is at or below the waste threshold. Stop |
|
2231 // adding old regions to the CSet. |
|
2232 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (reclaimable percentage not over threshold). " |
|
2233 "old %u regions, max %u regions, reclaimable: " SIZE_FORMAT "B (%1.2f%%) threshold: " UINTX_FORMAT "%%", |
|
2234 old_cset_region_length(), max_old_cset_length, reclaimable_bytes, reclaimable_perc, G1HeapWastePercent); |
|
2235 break; |
|
2236 } |
|
2237 |
|
2238 double predicted_time_ms = predict_region_elapsed_time_ms(hr, collector_state()->gcs_are_young()); |
|
2239 if (check_time_remaining) { |
|
2240 if (predicted_time_ms > time_remaining_ms) { |
|
2241 // Too expensive for the current CSet. |
|
2242 |
|
2243 if (old_cset_region_length() >= min_old_cset_length) { |
|
2244 // We have added the minimum number of old regions to the CSet, |
|
2245 // we are done with this CSet. |
|
2246 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (predicted time is too high). " |
|
2247 "predicted time: %1.2fms, remaining time: %1.2fms old %u regions, min %u regions", |
|
2248 predicted_time_ms, time_remaining_ms, old_cset_region_length(), min_old_cset_length); |
|
2249 break; |
|
2250 } |
|
2251 |
|
2252 // We'll add it anyway given that we haven't reached the |
|
2253 // minimum number of old regions. |
|
2254 expensive_region_num += 1; |
|
2255 } |
|
2256 } else { |
|
2257 if (old_cset_region_length() >= min_old_cset_length) { |
|
2258 // In the non-auto-tuning case, we'll finish adding regions |
|
2259 // to the CSet if we reach the minimum. |
|
2260 |
|
2261 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (old CSet region num reached min). old %u regions, min %u regions", |
|
2262 old_cset_region_length(), min_old_cset_length); |
|
2263 break; |
|
2264 } |
|
2265 } |
|
2266 |
|
2267 // We will add this region to the CSet. |
|
2268 time_remaining_ms = MAX2(time_remaining_ms - predicted_time_ms, 0.0); |
|
2269 predicted_old_time_ms += predicted_time_ms; |
|
2270 cset_chooser()->pop(); // already have region via peek() |
|
2271 _g1->old_set_remove(hr); |
|
2272 add_old_region_to_cset(hr); |
|
2273 |
|
2274 hr = cset_chooser()->peek(); |
|
2275 } |
|
2276 if (hr == NULL) { |
|
2277 log_debug(gc, ergo, cset)("Finish adding old regions to CSet (candidate old regions not available)"); |
|
2278 } |
|
2279 |
|
2280 if (expensive_region_num > 0) { |
|
2281 // We print the information once here at the end, predicated on |
|
2282 // whether we added any apparently expensive regions or not, to |
|
2283 // avoid generating output per region. |
|
2284 log_debug(gc, ergo, cset)("Added expensive regions to CSet (old CSet region num not reached min)." |
|
2285 "old: %u regions, expensive: %u regions, min: %u regions, remaining time: %1.2fms", |
|
2286 old_cset_region_length(), expensive_region_num, min_old_cset_length, time_remaining_ms); |
|
2287 } |
|
2288 |
|
2289 cset_chooser()->verify(); |
|
2290 } |
|
2291 |
|
2292 stop_incremental_cset_building(); |
|
2293 |
|
2294 log_debug(gc, ergo, cset)("Finish choosing CSet. old: %u regions, predicted old region time: %1.2fms, time remaining: %1.2f", |
|
2295 old_cset_region_length(), predicted_old_time_ms, time_remaining_ms); |
|
2296 |
|
2297 double non_young_end_time_sec = os::elapsedTime(); |
|
2298 phase_times()->record_non_young_cset_choice_time_ms((non_young_end_time_sec - non_young_start_time_sec) * 1000.0); |
|
2299 } |
|