8175312: SA: clhsdb: Provide an improved heap summary for 'universe' for G1GC

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
This commit is contained in:
Jini George 2018-03-20 11:24:32 +05:30
parent 3cbe6dfd8f
commit 9d036d6dd2
10 changed files with 296 additions and 22 deletions

View File

@ -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)

View File

@ -52,6 +52,8 @@ import sun.jvm.hotspot.classfile.ClassLoaderDataGraph;
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 @@ public class CommandProcessor {
}
}
},
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) {

View File

@ -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.debugger.Address;
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.AddressField;
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 @@ public class G1CollectedHeap extends CollectedHeap {
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) {

View File

@ -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 class HeapRegion extends CompactibleSpace {
public static long getPointerSize() {
return pointerSize;
}
public void printOn(PrintStream tty) {
tty.print("Region: " + bottom() + "," + top() + "," + end());
tty.println(":" + type.typeAnnotation());
}
}

View File

@ -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 @@ public class HeapRegionType extends VMObject {
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 @@ public class HeapRegionType extends VMObject {
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 @@ public class HeapRegionType extends VMObject {
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 @@ public class HeapRegionType extends VMObject {
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 class HeapRegionType extends VMObject {
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";
}
}

View File

@ -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);
}
}

View File

@ -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 @@ public class HeapSummary extends Tool {
}
}
} 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 @@ public class HeapSummary extends Tool {
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;

View File

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

View File

@ -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);
}
}

View File

@ -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 @@ public class TestUniverse {
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");