--- /dev/null 2013-05-27 09:16:24.088852603 +0200 +++ new/test/gc/arguments/TestUseCompressedOopsErgoTools.java 2013-06-04 17:03:34.111740914 +0200 @@ -0,0 +1,178 @@ +/* +* Copyright (c) 2013, 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.regex.Matcher; +import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.Arrays; + +import com.oracle.java.testlibrary.*; +import sun.hotspot.WhiteBox; + +class CompressedOopsErgoPrinter { + public static void main(String[] args) throws Exception { + WhiteBox wb = WhiteBox.getWhiteBox(); + wb.printCompressedOopsHeapInfo(); + } +} + +final class HeapForCompressedOopsValues { + public long maxHeapForCompressedOops; +} + +class TestUseCompressedOopsErgoTools { + + public static boolean is64bitVM() { + String val = System.getProperty("sun.arch.data.model"); + if (val == null) { + throw new RuntimeException("Could not read sun.arch.data.model"); + } + if (val.equals("64")) { + return true; + } else if (val.equals("32")) { + return false; + } + throw new RuntimeException("Unexpected value " + val + " of sun.arch.data.model"); + } + + private static String[] join(String[] part1, String part2) { + ArrayList result = new ArrayList(); + result.addAll(Arrays.asList(part1)); + result.add(part2); + return result.toArray(new String[0]); + } + + public static void checkCompressedOopsErgo(String[] gcflags) throws Exception { + HeapForCompressedOopsValues v = new HeapForCompressedOopsValues(); + + getMaxHeapForCompressedOops(gcflags, v); + + checkUseCompressedOops(gcflags, v.maxHeapForCompressedOops, true); + checkUseCompressedOops(gcflags, v.maxHeapForCompressedOops - 1, true); + checkUseCompressedOops(gcflags, v.maxHeapForCompressedOops + 1, false); + + // the use of HeapBaseMinAddress should not change the outcome + checkUseCompressedOops(join(gcflags, "-XX:HeapBaseMinAddress=32G"), v.maxHeapForCompressedOops, true); + checkUseCompressedOops(join(gcflags, "-XX:HeapBaseMinAddress=32G"), v.maxHeapForCompressedOops - 1, true); + checkUseCompressedOops(join(gcflags, "-XX:HeapBaseMinAddress=32G"), v.maxHeapForCompressedOops + 1, false); + + // use a different object alignment + getMaxHeapForCompressedOops(join(gcflags, "-XX:ObjectAlignmentInBytes=16"), v); + + checkUseCompressedOops(join(gcflags, "-XX:ObjectAlignmentInBytes=16"), v.maxHeapForCompressedOops, true); + checkUseCompressedOops(join(gcflags, "-XX:ObjectAlignmentInBytes=16"), v.maxHeapForCompressedOops - 1, true); + checkUseCompressedOops(join(gcflags, "-XX:ObjectAlignmentInBytes=16"), v.maxHeapForCompressedOops + 1, false); + + // use a different ClassMetaspaceSize + getMaxHeapForCompressedOops(join(gcflags, "-XX:ClassMetaspaceSize=1G"), v); + + checkUseCompressedOops(join(gcflags, "-XX:ClassMetaspaceSize=1G"), v.maxHeapForCompressedOops, true); + checkUseCompressedOops(join(gcflags, "-XX:ClassMetaspaceSize=1G"), v.maxHeapForCompressedOops - 1, true); + checkUseCompressedOops(join(gcflags, "-XX:ClassMetaspaceSize=1G"), v.maxHeapForCompressedOops + 1, false); + } + + private static void checkUseCompressedOops(String[] args, long heapsize, boolean expectUseCompressedOops) throws Exception { + ArrayList finalargs = new ArrayList(); + finalargs.addAll(Arrays.asList(args)); + finalargs.add("-Xmx" + heapsize); + finalargs.add("-XX:+PrintFlagsFinal"); + finalargs.add("-version"); + + String output = expectValid(finalargs.toArray(new String[0])); + + boolean actualUseCompressedOops = getFlagBoolValue(" UseCompressedOops", output); + + if (expectUseCompressedOops != actualUseCompressedOops) { + throw new RuntimeException("Expected use of compressed oops: " + expectUseCompressedOops + " but was: " + actualUseCompressedOops); + } + } + + private static long valueAfter(String source, String match) { + int start = source.indexOf(match) + match.length(); + String tail = source.substring(start).split(" ")[0]; + return Long.parseLong(tail); + } + + private static void getMaxHeapForCompressedOops(String[] args, HeapForCompressedOopsValues val) throws Exception { + ArrayList finalargs = new ArrayList(); + + String[] testVMopts = new String[] { + "-XX:+UnlockDiagnosticVMOptions", "-XX:+WhiteBoxAPI", + "-Xbootclasspath/a:.", + "-cp", System.getProperty("java.class.path"), + }; + + finalargs.addAll(Arrays.asList(args)); + finalargs.addAll(Arrays.asList(testVMopts)); + finalargs.add(CompressedOopsErgoPrinter.class.getName()); + + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(finalargs.toArray(new String[0])); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(0); + + // the output we watch for has the following format: + // + // "Max heap for compressed oops X Max heap alignment Y ClassMetaspaceSize Z Page size A" + // + // where X, Y, Z and A are sizes in bytes. + + Matcher m = Pattern.compile("Max heap for compressed oops \\d+ ClassMetaspaceSize \\d+"). + matcher(output.getStdout()); + if (!m.find()) { + throw new RuntimeException("Could not find heap size string."); + } + String match = m.group(); + + // parse actual values + val.maxHeapForCompressedOops = valueAfter(match, "Max heap for compressed oops "); + } + + private static boolean getFlagBoolValue(String flag, String where) { + Matcher m = Pattern.compile(flag + "\\s+:?= (true|false)").matcher(where); + if (!m.find()) { + throw new RuntimeException("Could not find value for flag " + flag + " in output string"); + } + String match = m.group(); + return match.substring(match.lastIndexOf(" ") + 1, match.length()).equals("true"); + } + + private static void shouldContainOrNot(OutputAnalyzer output, boolean contains, String message) throws Exception { + if (contains) { + output.shouldContain(message); + } else { + output.shouldNotContain(message); + } + } + + private static String expect(String[] flags, boolean hasWarning, boolean hasError, int errorcode) throws Exception { + ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(flags); + OutputAnalyzer output = new OutputAnalyzer(pb.start()); + output.shouldHaveExitValue(errorcode); + return output.getStdout(); + } + + private static String expectValid(String[] flags) throws Exception { + return expect(flags, false, false, 0); + } +} +