8175312: SA: clhsdb: Provide an improved heap summary for 'universe' for G1GC
authorjgeorge
Tue, 20 Mar 2018 11:24:32 +0530
changeset 49463 ccb003941743
parent 49462 00992d4e8a23
child 49464 7ea4724a959c
8175312: SA: clhsdb: Provide an improved heap summary for 'universe' for G1GC Summary: Provide an improved heap summary for G1GC with parameters like 'capacity', 'used', 'free', etc with the 'universe' command, and introduce a new command 'g1regiondetails' to display the individual region details. Reviewed-by: sjohanss, minqi
src/hotspot/share/gc/g1/vmStructs_g1.hpp
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/PrintRegionClosure.java
src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java
test/hotspot/jtreg/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java
test/hotspot/jtreg/serviceability/sa/LingeredAppWithLargeStringArray.java
test/hotspot/jtreg/serviceability/sa/TestUniverse.java
--- a/src/hotspot/share/gc/g1/vmStructs_g1.hpp	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/hotspot/share/gc/g1/vmStructs_g1.hpp	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -73,8 +73,13 @@
 #define VM_INT_CONSTANTS_G1(declare_constant, declare_constant_with_value)    \
   declare_constant(HeapRegionType::FreeTag)                                   \
   declare_constant(HeapRegionType::YoungMask)                                 \
+  declare_constant(HeapRegionType::EdenTag)                                   \
+  declare_constant(HeapRegionType::SurvTag)                                   \
   declare_constant(HeapRegionType::HumongousMask)                             \
   declare_constant(HeapRegionType::PinnedMask)                                \
+  declare_constant(HeapRegionType::ArchiveMask)                               \
+  declare_constant(HeapRegionType::StartsHumongousTag)                        \
+  declare_constant(HeapRegionType::ContinuesHumongousTag)                     \
   declare_constant(HeapRegionType::OldMask)
 
 
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/CommandProcessor.java	Tue Mar 20 11:24:32 2018 +0530
@@ -52,6 +52,8 @@
 import sun.jvm.hotspot.memory.SymbolTable;
 import sun.jvm.hotspot.memory.SystemDictionary;
 import sun.jvm.hotspot.memory.Universe;
+import sun.jvm.hotspot.gc.shared.CollectedHeap;
+import sun.jvm.hotspot.gc.g1.G1CollectedHeap;
 import sun.jvm.hotspot.oops.DefaultHeapVisitor;
 import sun.jvm.hotspot.oops.HeapVisitor;
 import sun.jvm.hotspot.oops.InstanceKlass;
@@ -1656,6 +1658,21 @@
                 }
             }
         },
+        new Command("g1regiondetails", false) {
+            public void doit(Tokens t) {
+                if (t.countTokens() != 0) {
+                    usage();
+                } else {
+                    CollectedHeap heap = VM.getVM().getUniverse().heap();
+                    if (!(heap instanceof G1CollectedHeap)) {
+                        out.println("This command is valid only for G1GC.");
+                        return;
+                    }
+                    out.println("Region Details:");
+                    ((G1CollectedHeap)heap).printRegionDetails(out);
+                }
+            }
+        },
         new Command("universe", false) {
             public void doit(Tokens t) {
                 if (t.countTokens() != 0) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/G1CollectedHeap.java	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -33,6 +33,7 @@
 import sun.jvm.hotspot.gc.shared.CollectedHeap;
 import sun.jvm.hotspot.gc.shared.CollectedHeapName;
 import sun.jvm.hotspot.gc.shared.SpaceClosure;
+import sun.jvm.hotspot.gc.shared.PrintRegionClosure;
 import sun.jvm.hotspot.memory.MemRegion;
 import sun.jvm.hotspot.runtime.VM;
 import sun.jvm.hotspot.runtime.VMObjectFactory;
@@ -40,6 +41,7 @@
 import sun.jvm.hotspot.types.CIntegerField;
 import sun.jvm.hotspot.types.Type;
 import sun.jvm.hotspot.types.TypeDataBase;
+import sun.jvm.hotspot.tools.HeapSummary;
 
 // Mirror class for G1CollectedHeap.
 
@@ -133,6 +135,14 @@
         tty.print("garbage-first heap");
         tty.print(" [" + mr.start() + ", " + mr.end() + "]");
         tty.println(" region size " + (HeapRegion.grainBytes() / 1024) + "K");
+
+        HeapSummary sum = new HeapSummary();
+        sum.printG1HeapSummary(this);
+    }
+
+    public void printRegionDetails(PrintStream tty) {
+        PrintRegionClosure prc = new PrintRegionClosure(tty);
+        heapRegionIterate(prc);
     }
 
     public G1CollectedHeap(Address addr) {
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegion.java	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2011, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2011, 2018, 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
@@ -24,6 +24,7 @@
 
 package sun.jvm.hotspot.gc.g1;
 
+import java.io.PrintStream;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Observable;
@@ -124,4 +125,9 @@
     public static long getPointerSize() {
         return pointerSize;
     }
+
+    public void printOn(PrintStream tty) {
+        tty.print("Region: " + bottom() + "," + top() + "," + end());
+        tty.println(":" + type.typeAnnotation());
+    }
 }
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/g1/HeapRegionType.java	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, 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
@@ -40,8 +40,13 @@
 
     private static int freeTag;
     private static int youngMask;
+    private static int edenTag;
+    private static int survTag;
     private static int humongousMask;
+    private static int startsHumongousTag;
+    private static int continuesHumongousTag;
     private static int pinnedMask;
+    private static int archiveMask;
     private static int oldMask;
     private static CIntegerField tagField;
     private int tag;
@@ -61,6 +66,11 @@
 
         freeTag = db.lookupIntConstant("HeapRegionType::FreeTag");
         youngMask = db.lookupIntConstant("HeapRegionType::YoungMask");
+        edenTag = db.lookupIntConstant("HeapRegionType::EdenTag");
+        survTag = db.lookupIntConstant("HeapRegionType::SurvTag");
+        startsHumongousTag = db.lookupIntConstant("HeapRegionType::StartsHumongousTag");
+        continuesHumongousTag = db.lookupIntConstant("HeapRegionType::ContinuesHumongousTag");
+        archiveMask = db.lookupIntConstant("HeapRegionType::ArchiveMask");
         humongousMask = db.lookupIntConstant("HeapRegionType::HumongousMask");
         pinnedMask = db.lookupIntConstant("HeapRegionType::PinnedMask");
         oldMask = db.lookupIntConstant("HeapRegionType::OldMask");
@@ -70,6 +80,14 @@
         return tagField.getValue(addr) == freeTag;
     }
 
+    public boolean isEden() {
+        return tagField.getValue(addr) == edenTag;
+    }
+
+    public boolean isSurvivor() {
+        return tagField.getValue(addr) == survTag;
+    }
+
     public boolean isYoung() {
         return (tagField.getValue(addr) & youngMask) != 0;
     }
@@ -78,6 +96,18 @@
         return (tagField.getValue(addr) & humongousMask) != 0;
     }
 
+    public boolean isStartsHumongous() {
+        return tagField.getValue(addr) == startsHumongousTag;
+    }
+
+    public boolean isContinuesHumongous() {
+        return tagField.getValue(addr) == continuesHumongousTag;
+    }
+
+    public boolean isArchive() {
+        return (tagField.getValue(addr) & archiveMask) != 0;
+    }
+
     public boolean isPinned() {
         return (tagField.getValue(addr) & pinnedMask) != 0;
     }
@@ -89,4 +119,32 @@
     public HeapRegionType(Address addr) {
         super(addr);
     }
+
+    public String typeAnnotation() {
+        if (isFree()) {
+            return "Free";
+        }
+        if (isEden()) {
+            return "Eden";
+        }
+        if (isSurvivor()) {
+            return "Survivor";
+        }
+        if (isStartsHumongous()) {
+            return "StartsHumongous";
+        }
+        if (isContinuesHumongous()) {
+            return "ContinuesHumongous";
+        }
+        if (isArchive()) {
+            return "Archive";
+        }
+        if (isPinned()) {
+            return "Pinned";
+        }
+        if (isOld()) {
+            return "Old";
+        }
+        return "Unknown Region Type";
+    }
 }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/gc/shared/PrintRegionClosure.java	Tue Mar 20 11:24:32 2018 +0530
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018, 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.
+ *
+ */
+
+package sun.jvm.hotspot.gc.shared;
+
+import java.io.PrintStream;
+import sun.jvm.hotspot.gc.g1.HeapRegion;
+
+public class PrintRegionClosure implements SpaceClosure {
+  private PrintStream tty;
+
+  public PrintRegionClosure(PrintStream tty) {
+    this.tty = tty;
+  }
+
+  public void doSpace(Space hr) {
+    ((HeapRegion)hr).printOn(tty);
+  }
+}
--- a/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/tools/HeapSummary.java	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2018, 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
@@ -111,22 +111,7 @@
             }
          }
       } else if (heap instanceof G1CollectedHeap) {
-          G1CollectedHeap g1h = (G1CollectedHeap) heap;
-          G1MonitoringSupport g1mm = g1h.g1mm();
-          long edenRegionNum = g1mm.edenRegionNum();
-          long survivorRegionNum = g1mm.survivorRegionNum();
-          HeapRegionSetBase oldSet = g1h.oldSet();
-          HeapRegionSetBase humongousSet = g1h.humongousSet();
-          long oldRegionNum = oldSet.length() + humongousSet.length();
-          printG1Space("G1 Heap:", g1h.n_regions(),
-                       g1h.used(), g1h.capacity());
-          System.out.println("G1 Young Generation:");
-          printG1Space("Eden Space:", edenRegionNum,
-                       g1mm.edenUsed(), g1mm.edenCommitted());
-          printG1Space("Survivor Space:", survivorRegionNum,
-                       g1mm.survivorUsed(), g1mm.survivorCommitted());
-          printG1Space("G1 Old Generation:", oldRegionNum,
-                       g1mm.oldUsed(), g1mm.oldCommitted());
+          printG1HeapSummary((G1CollectedHeap)heap);
       } else if (heap instanceof ParallelScavengeHeap) {
          ParallelScavengeHeap psh = (ParallelScavengeHeap) heap;
          PSYoungGen youngGen = psh.youngGen();
@@ -217,6 +202,24 @@
       System.out.println(alignment +  (double)space.used() * 100.0 / space.capacity() + "% used");
    }
 
+   public void printG1HeapSummary(G1CollectedHeap g1h) {
+      G1MonitoringSupport g1mm = g1h.g1mm();
+      long edenRegionNum = g1mm.edenRegionNum();
+      long survivorRegionNum = g1mm.survivorRegionNum();
+      HeapRegionSetBase oldSet = g1h.oldSet();
+      HeapRegionSetBase humongousSet = g1h.humongousSet();
+      long oldRegionNum = oldSet.length() + humongousSet.length();
+      printG1Space("G1 Heap:", g1h.n_regions(),
+                   g1h.used(), g1h.capacity());
+      System.out.println("G1 Young Generation:");
+      printG1Space("Eden Space:", edenRegionNum,
+                   g1mm.edenUsed(), g1mm.edenCommitted());
+      printG1Space("Survivor Space:", survivorRegionNum,
+                   g1mm.survivorUsed(), g1mm.survivorCommitted());
+      printG1Space("G1 Old Generation:", oldRegionNum,
+                   g1mm.oldUsed(), g1mm.oldCommitted());
+   }
+
    private void printG1Space(String spaceName, long regionNum,
                              long used, long capacity) {
       long free = capacity - used;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/ClhsdbRegionDetailsScanOopsForG1.java	Tue Mar 20 11:24:32 2018 +0530
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import jdk.test.lib.apps.LingeredApp;
+
+/*
+ * @test
+ * @bug 8175312
+ * @summary Test clhsdb 'g1regiondetails' and 'scanoops' commands for G1GC
+ * @library /test/lib
+ * @requires (vm.bits == "64" & os.maxMemory > 8g)
+ * @run main/othervm/timeout=2400 ClhsdbRegionDetailsScanOopsForG1
+ */
+
+public class ClhsdbRegionDetailsScanOopsForG1 {
+
+    public static void main(String[] args) throws Exception {
+        System.out.println("Starting ClhsdbRegionDetailsScanOopsForG1 test");
+
+        LingeredAppWithLargeStringArray theApp = null;
+        try {
+            ClhsdbLauncher test = new ClhsdbLauncher();
+            List<String> vmArgs = new ArrayList<String>();
+            vmArgs.add("-XX:+UseG1GC");
+            vmArgs.add("-Xmx8g");
+            vmArgs.add("-XX:G1HeapRegionSize=2m");
+
+            theApp = new LingeredAppWithLargeStringArray();
+            LingeredApp.startApp(vmArgs, theApp);
+            System.out.println("Started LingeredAppWithLargeStringArray with pid " + theApp.getPid());
+
+            List<String> cmds = List.of("g1regiondetails");
+            Map<String, List<String>> expStrMap = new HashMap<>();
+            Map<String, List<String>> unExpStrMap = new HashMap<>();
+
+            // Test that the various types of regions are listed with the
+            // 'g1regiondetails' command
+            expStrMap.put("g1regiondetails", List.of(
+                "Region",
+                "Eden",
+                "Survivor",
+                "StartsHumongous",
+                "ContinuesHumongous",
+                "Free"));
+            unExpStrMap.put("g1regiondetails", List.of("Unknown Region Type"));
+            String regionDetailsOutput = test.run(theApp.getPid(), cmds,
+                                                  expStrMap, unExpStrMap);
+            if (regionDetailsOutput == null) {
+                // Output could be null due to attach permission issues
+                // and if we are skipping this.
+                LingeredApp.stopApp(theApp);
+                return;
+            }
+
+            // Test the output of 'scanoops' -- get the start and end addresses
+            // from the StartsHumongous region. Ensure that it contains an
+            // array of Strings.
+            String[] snippets = regionDetailsOutput.split(":StartsHumongous");
+            snippets = snippets[0].split("Region: ");
+            String[] words = snippets[snippets.length - 1].split(",");
+            // words[0] and words[1] represent the start and end addresses
+            String cmd = "scanoops " + words[0] + " " + words[1];
+            expStrMap = new HashMap<>();
+            expStrMap.put(cmd, List.of("[Ljava/lang/String"));
+            test.run(theApp.getPid(), List.of(cmd), expStrMap, null);
+        } catch (Exception ex) {
+            throw new RuntimeException("Test ERROR " + ex, ex);
+        } finally {
+            LingeredApp.stopApp(theApp);
+        }
+        System.out.println("Test PASSED");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/hotspot/jtreg/serviceability/sa/LingeredAppWithLargeStringArray.java	Tue Mar 20 11:24:32 2018 +0530
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2018, 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.
+ */
+
+import jdk.test.lib.apps.LingeredApp;
+
+public class LingeredAppWithLargeStringArray extends LingeredApp {
+    public static void main(String args[]) {
+        String[] hugeArray = new String[Integer.MAX_VALUE/8];
+        String[] smallArray = {"Just", "for", "testing"};
+        for (int i = 0; i < hugeArray.length/16; i++) {
+            hugeArray[i] = new String(smallArray[i%3]);
+        }
+        LingeredApp.main(args);
+    }
+ }
--- a/test/hotspot/jtreg/serviceability/sa/TestUniverse.java	Mon Mar 19 14:20:28 2018 -0500
+++ b/test/hotspot/jtreg/serviceability/sa/TestUniverse.java	Tue Mar 20 11:24:32 2018 +0530
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2017, 2018, 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
@@ -87,6 +87,9 @@
         output.shouldContain("Heap Parameters");
         if (gc.contains("G1GC")) {
             output.shouldContain("garbage-first heap");
+            output.shouldContain("region size");
+            output.shouldContain("G1 Young Generation:");
+            output.shouldContain("regions  =");
         }
         if (gc.contains("UseConcMarkSweepGC")) {
             output.shouldContain("Gen 1: concurrent mark-sweep generation");