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
--- 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");