--- old/src/share/vm/gc/g1/g1CollectedHeap.cpp 2016-08-30 15:41:20.528454200 +0200 +++ new/src/share/vm/gc/g1/g1CollectedHeap.cpp 2016-08-30 15:41:20.400450250 +0200 @@ -4513,6 +4513,7 @@ #if defined(COMPILER2) || INCLUDE_JVMCI DerivedPointerTable::update_pointers(); #endif + g1_policy()->print_age_table(); } void G1CollectedHeap::record_obj_copy_mem_stats() { --- old/src/share/vm/gc/g1/g1DefaultPolicy.cpp 2016-08-30 15:41:21.393480889 +0200 +++ new/src/share/vm/gc/g1/g1DefaultPolicy.cpp 2016-08-30 15:41:21.253476569 +0200 @@ -885,6 +885,15 @@ return _young_gen_sizer.adaptive_young_list_length(); } +size_t G1DefaultPolicy::desired_survivor_size() const { + size_t const survivor_capacity = HeapRegion::GrainWords * _max_survivor_regions; + return (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100); +} + +void G1DefaultPolicy::print_age_table() { + _survivors_age_table.print_age_table(_tenuring_threshold); +} + void G1DefaultPolicy::update_max_gc_locker_expansion() { uint expansion_region_num = 0; if (GCLockerEdenExpansionPercent > 0) { @@ -908,8 +917,11 @@ // smaller than 1.0) we'll get 1. _max_survivor_regions = (uint) ceil(max_survivor_regions_d); - _tenuring_threshold = _survivors_age_table.compute_tenuring_threshold( - HeapRegion::GrainWords * _max_survivor_regions, _policy_counters); + _tenuring_threshold = _survivors_age_table.compute_tenuring_threshold(desired_survivor_size()); + if (UsePerfData) { + _policy_counters->tenuring_threshold()->set_value(_tenuring_threshold); + _policy_counters->desired_survivor_size()->set_value(desired_survivor_size() * oopSize); + } } bool G1DefaultPolicy::force_initial_mark_if_outside_cycle(GCCause::Cause gc_cause) { --- old/src/share/vm/gc/g1/g1DefaultPolicy.hpp 2016-08-30 15:41:22.204505912 +0200 +++ new/src/share/vm/gc/g1/g1DefaultPolicy.hpp 2016-08-30 15:41:22.082502148 +0200 @@ -360,6 +360,8 @@ AgeTable _survivors_age_table; +protected: + size_t desired_survivor_size() const; public: uint tenuring_threshold() const { return _tenuring_threshold; } @@ -374,11 +376,13 @@ void note_stop_adding_survivor_regions() { _survivor_surv_rate_group->stop_adding_regions(); } - + void record_age_table(AgeTable* age_table) { _survivors_age_table.merge(age_table); } + void print_age_table(); + void update_max_gc_locker_expansion(); void update_survivors_policy(); --- old/src/share/vm/gc/g1/g1Policy.hpp 2016-08-30 15:41:22.984529979 +0200 +++ new/src/share/vm/gc/g1/g1Policy.hpp 2016-08-30 15:41:22.845525690 +0200 @@ -181,6 +181,9 @@ virtual void note_stop_adding_survivor_regions() = 0; virtual void record_age_table(AgeTable* age_table) = 0; + virtual void print_age_table() = 0; +protected: + virtual size_t desired_survivor_size() const = 0; }; #endif // SHARE_VM_GC_G1_G1POLICY_HPP --- old/src/share/vm/gc/serial/defNewGeneration.cpp 2016-08-30 15:41:23.806555341 +0200 +++ new/src/share/vm/gc/serial/defNewGeneration.cpp 2016-08-30 15:41:23.665550991 +0200 @@ -564,9 +564,18 @@ void DefNewGeneration::adjust_desired_tenuring_threshold() { // Set the desired survivor size to half the real survivor space + size_t const survivor_capacity = to()->capacity() / HeapWordSize; + size_t const desired_survivor_size = (size_t)((((double)survivor_capacity) * TargetSurvivorRatio) / 100); + + _tenuring_threshold = age_table()->compute_tenuring_threshold(desired_survivor_size); + GCPolicyCounters* gc_counters = GenCollectedHeap::heap()->gen_policy()->counters(); - _tenuring_threshold = - age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize, gc_counters); + if (UsePerfData) { + gc_counters->tenuring_threshold()->set_value(_tenuring_threshold); + gc_counters->desired_survivor_size()->set_value(desired_survivor_size * oopSize); + } + + age_table()->print_age_table(_tenuring_threshold); } void DefNewGeneration::collect(bool full, --- old/src/share/vm/gc/shared/ageTable.cpp 2016-08-30 15:41:24.653581475 +0200 +++ new/src/share/vm/gc/shared/ageTable.cpp 2016-08-30 15:41:24.515577217 +0200 @@ -75,8 +75,7 @@ } } -uint AgeTable::compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters) { - size_t desired_survivor_size = (size_t)((((double) survivor_capacity)*TargetSurvivorRatio)/100); +uint AgeTable::compute_tenuring_threshold(size_t desired_survivor_size) { uint result; if (AlwaysTenure || NeverTenure) { @@ -99,9 +98,16 @@ log_debug(gc, age)("Desired survivor size " SIZE_FORMAT " bytes, new threshold " UINTX_FORMAT " (max threshold " UINTX_FORMAT ")", - desired_survivor_size*oopSize, (uintx) result, MaxTenuringThreshold); + desired_survivor_size * oopSize, (uintx) result, MaxTenuringThreshold); + return result; +} + +void AgeTable::print_age_table(uint tenuring_threshold) { if (log_is_enabled(Trace, gc, age) || UsePerfData || AgeTableTracer::is_tenuring_distribution_event_enabled()) { + log_trace(gc, age)("Age table with threshold %u (max threshold " UINTX_FORMAT ")", + tenuring_threshold, MaxTenuringThreshold); + size_t total = 0; uint age = 1; while (age < table_size) { @@ -109,20 +115,13 @@ total += wordSize; if (wordSize > 0) { log_trace(gc, age)("- age %3u: " SIZE_FORMAT_W(10) " bytes, " SIZE_FORMAT_W(10) " total", - age, wordSize*oopSize, total*oopSize); + age, wordSize * oopSize, total * oopSize); } - AgeTableTracer::send_tenuring_distribution_event(age, wordSize*oopSize); + AgeTableTracer::send_tenuring_distribution_event(age, wordSize * oopSize); if (UsePerfData) { - _perf_sizes[age]->set_value(wordSize*oopSize); + _perf_sizes[age]->set_value(wordSize * oopSize); } age++; } - if (UsePerfData) { - gc_counters->tenuring_threshold()->set_value(result); - gc_counters->desired_survivor_size()->set_value( - desired_survivor_size*oopSize); - } - } - - return result; -} + } +} \ No newline at end of file --- old/src/share/vm/gc/shared/ageTable.hpp 2016-08-30 15:41:25.472606745 +0200 +++ new/src/share/vm/gc/shared/ageTable.hpp 2016-08-30 15:41:25.344602796 +0200 @@ -67,10 +67,12 @@ // for parallel young generation gc. void merge(AgeTable* subTable); - // calculate new tenuring threshold based on age information - uint compute_tenuring_threshold(size_t survivor_capacity, GCPolicyCounters* gc_counters); + // Calculate new tenuring threshold based on age information. + uint compute_tenuring_threshold(size_t desired_survivor_size); + void print_age_table(uint tenuring_threshold); private: + PerfVariable* _perf_sizes[table_size]; }; --- /dev/null 2016-08-30 09:55:17.854570508 +0200 +++ new/test/gc/g1/TestAgeOutput.java 2016-08-30 15:41:26.088625752 +0200 @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. + * 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. + */ + +/* + * @test TestAgeOutput + * @bug 8164936 + * @summary Check that G1 prints an age table even for the first garbage collection + * @key gc + * @requires vm.gc.G1 + * @modules java.base/jdk.internal.misc + * @library /test/lib + * @build sun.hotspot.WhiteBox + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * @run driver TestAgeOutput + */ + +import sun.hotspot.WhiteBox; + +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import jdk.test.lib.Platform; +import jdk.test.lib.process.OutputAnalyzer; +import jdk.test.lib.process.ProcessTools; + +import static jdk.test.lib.Asserts.*; + +public class TestAgeOutput { + + public static void checkPattern(String pattern, String what) throws Exception { + Pattern r = Pattern.compile(pattern); + Matcher m = r.matcher(what); + + if (!m.find()) { + throw new RuntimeException("Could not find pattern " + pattern + " in output"); + } + } + + public static void runTest() throws Exception { + final String[] arguments = { + "-Xbootclasspath/a:.", + "-XX:+UnlockExperimentalVMOptions", + "-XX:+UnlockDiagnosticVMOptions", + "-XX:+WhiteBoxAPI", + "-XX:+UseG1GC", + "-Xmx10M", + "-Xlog:gc+age=trace", + GCTest.class.getName() + }; + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(arguments); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + + output.shouldHaveExitValue(0); + + System.out.println(output.getStdout()); + + String stdout = output.getStdout(); + + checkPattern(".*GC\\(0\\) .*Desired survivor size.*", stdout); + checkPattern(".*GC\\(0\\) .*Age table with threshold.*", stdout); + checkPattern(".*GC\\(0\\) .*- age 1:.*", stdout); + } + + public static void main(String[] args) throws Exception { + runTest(); + } + + static class GCTest { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + + public static Object holder; + + public static void main(String [] args) { + holder = new byte[100]; + WB.youngGC(); + System.out.println(holder); + } + } +} +