8164936: G1 age table printout contains contents from previous GC
authortschatzl
Fri, 02 Sep 2016 09:49:10 +0200
changeset 40914 90c87069b39c
parent 40912 7f19457ea0fc
child 40915 7ca02bd6fbf6
8164936: G1 age table printout contains contents from previous GC Summary: Split tenuring threshold update and printing into two separate parts so that they can be used independently. Reviewed-by: jmasa, sangheki
hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp
hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp
hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp
hotspot/src/share/vm/gc/g1/g1Policy.hpp
hotspot/src/share/vm/gc/serial/defNewGeneration.cpp
hotspot/src/share/vm/gc/shared/ageTable.cpp
hotspot/src/share/vm/gc/shared/ageTable.hpp
hotspot/test/gc/TestAgeOutput.java
--- a/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1CollectedHeap.cpp	Fri Sep 02 09:49:10 2016 +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() {
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.cpp	Fri Sep 02 09:49:10 2016 +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) {
--- a/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1DefaultPolicy.hpp	Fri Sep 02 09:49:10 2016 +0200
@@ -360,6 +360,8 @@
 
   AgeTable _survivors_age_table;
 
+protected:
+  size_t desired_survivor_size() const;
 public:
   uint tenuring_threshold() const { return _tenuring_threshold; }
 
@@ -379,6 +381,8 @@
     _survivors_age_table.merge(age_table);
   }
 
+  void print_age_table();
+
   void update_max_gc_locker_expansion();
 
   void update_survivors_policy();
--- a/hotspot/src/share/vm/gc/g1/g1Policy.hpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/g1/g1Policy.hpp	Fri Sep 02 09:49:10 2016 +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
--- a/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/serial/defNewGeneration.cpp	Fri Sep 02 09:49:10 2016 +0200
@@ -564,9 +564,18 @@
 
 void DefNewGeneration::adjust_desired_tenuring_threshold() {
   // Set the desired survivor size to half the real survivor space
-  GCPolicyCounters* gc_counters = GenCollectedHeap::heap()->gen_policy()->counters();
-  _tenuring_threshold =
-    age_table()->compute_tenuring_threshold(to()->capacity()/HeapWordSize, gc_counters);
+  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);
+
+  if (UsePerfData) {
+    GCPolicyCounters* gc_counters = GenCollectedHeap::heap()->gen_policy()->counters();
+    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,
--- a/hotspot/src/share/vm/gc/shared/ageTable.cpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/shared/ageTable.cpp	Fri Sep 02 09:49:10 2016 +0200
@@ -27,7 +27,6 @@
 #include "gc/shared/ageTableTracer.hpp"
 #include "gc/shared/collectedHeap.hpp"
 #include "gc/shared/collectorPolicy.hpp"
-#include "gc/shared/gcPolicyCounters.hpp"
 #include "memory/resourceArea.hpp"
 #include "logging/log.hpp"
 #include "oops/oop.inline.hpp"
@@ -75,8 +74,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 +97,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 +114,14 @@
       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;
-}
--- a/hotspot/src/share/vm/gc/shared/ageTable.hpp	Fri Sep 02 01:39:47 2016 +0000
+++ b/hotspot/src/share/vm/gc/shared/ageTable.hpp	Fri Sep 02 09:49:10 2016 +0200
@@ -29,8 +29,6 @@
 #include "oops/oop.hpp"
 #include "runtime/perfData.hpp"
 
-class GCPolicyCounters;
-
 /* Copyright (c) 1992, 2016, Oracle and/or its affiliates, and Stanford University.
    See the LICENSE file for license information. */
 
@@ -67,10 +65,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	Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/TestAgeOutput.java	Fri Sep 02 09:49:10 2016 +0200
@@ -0,0 +1,103 @@
+/*
+ * 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 collectors using age table based aging print an age table even for the first garbage collection
+ * @key gc
+ * @requires vm.gc=="null"
+ * @modules java.base/jdk.internal.misc
+ * @library /test/lib
+ * @build sun.hotspot.WhiteBox
+ * @run main ClassFileInstaller sun.hotspot.WhiteBox
+ * @run main/othervm -XX:+UseSerialGC TestAgeOutput UseSerialGC
+ * @run main/othervm -XX:+UseConcMarkSweepGC TestAgeOutput UseConcMarkSweepGC
+ * @run main/othervm -XX:+UseG1GC TestAgeOutput UseG1GC
+ */
+
+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(String gcArg) throws Exception {
+        final String[] arguments = {
+            "-Xbootclasspath/a:.",
+            "-XX:+UnlockExperimentalVMOptions",
+            "-XX:+UnlockDiagnosticVMOptions",
+            "-XX:+WhiteBoxAPI",
+            "-XX:+" + gcArg,
+            "-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(args[0]);
+    }
+
+    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);
+        }
+    }
+}
+