Path: blob/master/test/hotspot/jtreg/gc/logging/TestPrintReferences.java
40942 views
/*1* Copyright (c) 2015, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223package gc.logging;2425/*26* @test TestPrintReferences27* @bug 8136991 8186402 8186465 818824528* @summary Validate the reference processing logging29* @requires vm.gc.G130* @library /test/lib31* @modules java.base/jdk.internal.misc32* java.management33* @run driver gc.logging.TestPrintReferences34*/3536import java.lang.ref.SoftReference;37import java.math.BigDecimal;38import jdk.test.lib.process.OutputAnalyzer;39import jdk.test.lib.process.ProcessTools;40import java.util.regex.Pattern;41import java.util.regex.Matcher;4243public class TestPrintReferences {44static String output;45static final String doubleRegex = "[0-9]+[.,][0-9]+";46static final String referenceProcessing = "Reference Processing";47static final String softReference = "SoftReference";48static final String weakReference = "WeakReference";49static final String finalReference = "FinalReference";50static final String phantomReference = "PhantomReference";5152static final String phaseReconsiderSoftReferences = "Reconsider SoftReferences";53static final String phaseNotifySoftWeakReferences = "Notify Soft/WeakReferences";54static final String phaseNotifyKeepAliveFinalizer = "Notify and keep alive finalizable";55static final String phaseNotifyPhantomReferences = "Notify PhantomReferences";5657static final String gcLogTimeRegex = ".* GC\\([0-9]+\\) ";5859public static void main(String[] args) throws Exception {60testPhases(true);61testPhases(false);62testRefs();63}6465static String indent(int count) {66return " {" + count + "}";67}6869public static void testRefs() throws Exception {70ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+ref+phases=debug",71"-XX:+UseG1GC",72"-Xmx32M",73GCTest.class.getName());74OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());7576checkRefsLogFormat(output);7778output.shouldHaveExitValue(0);79}8081private static String refRegex(String reftype) {82String countRegex = "[0-9]+";83return gcLogTimeRegex + indent(6) + reftype + ":\n" +84gcLogTimeRegex + indent(8) + "Discovered: " + countRegex + "\n" +85gcLogTimeRegex + indent(8) + "Cleared: " + countRegex + "\n";86}8788private static void checkRefsLogFormat(OutputAnalyzer output) {89output.shouldMatch(refRegex("SoftReference") +90refRegex("WeakReference") +91refRegex("FinalReference") +92refRegex("PhantomReference"));93}9495public static void testPhases(boolean parallelRefProcEnabled) throws Exception {96ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+phases+ref=debug",97"-XX:+UseG1GC",98"-Xmx32M",99"-XX:" + (parallelRefProcEnabled ? "+" : "-") + "ParallelRefProcEnabled",100"-XX:-UseDynamicNumberOfGCThreads",101"-XX:ParallelGCThreads=2",102GCTest.class.getName());103OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());104105checkLogFormat(output, parallelRefProcEnabled);106checkLogValue(output);107108output.shouldHaveExitValue(0);109}110111private static String phaseRegex(String phaseName) {112final String timeRegex = doubleRegex + "ms";113return indent(6) + phaseName + ": " + timeRegex + "\n";114}115116private static String subphaseRegex(String subphaseName, boolean parallelRefProcEnabled) {117final String timeRegex = "\\s+" + doubleRegex;118if (parallelRefProcEnabled) {119final String timeInParRegex = timeRegex +",\\s";120return gcLogTimeRegex + indent(8) + subphaseName +121" \\(ms\\):\\s+(Min:" + timeInParRegex + "Avg:" + timeInParRegex + "Max:" + timeInParRegex + "Diff:" + timeInParRegex + "Sum:" + timeInParRegex +122"Workers: [0-9]+|skipped)" + "\n";123} else {124return gcLogTimeRegex + indent(8) + subphaseName + ":(" + timeRegex + "ms|\\s+skipped)\n";125}126}127128// Find the first Reference Processing log and check its format.129private static void checkLogFormat(OutputAnalyzer output, boolean parallelRefProcEnabled) {130String timeRegex = doubleRegex + "ms";131132/* Total Reference processing time */133String totalRegex = gcLogTimeRegex + indent(4) + referenceProcessing + ": " + timeRegex + "\n";134135String balanceRegex = parallelRefProcEnabled ? "(" + gcLogTimeRegex + indent(8) + "Balance queues: " + timeRegex + "\n)??" : "";136137final boolean p = parallelRefProcEnabled;138139String phase1Regex = gcLogTimeRegex + phaseRegex(phaseReconsiderSoftReferences) + balanceRegex + subphaseRegex("SoftRef", p);140String phase2Regex = gcLogTimeRegex + phaseRegex(phaseNotifySoftWeakReferences) +141balanceRegex +142subphaseRegex("SoftRef", p) +143subphaseRegex("WeakRef", p) +144subphaseRegex("FinalRef", p) +145subphaseRegex("Total", p);146String phase3Regex = gcLogTimeRegex + phaseRegex(phaseNotifyKeepAliveFinalizer) + balanceRegex + subphaseRegex("FinalRef", p);147String phase4Regex = gcLogTimeRegex + phaseRegex(phaseNotifyPhantomReferences) + balanceRegex + subphaseRegex("PhantomRef", p);148149output.shouldMatch(totalRegex +150phase1Regex +151phase2Regex +152phase3Regex +153phase4Regex);154}155156// After getting time value, update 'output' for next use.157private static BigDecimal getTimeValue(String name, int indentCount) {158// Pattern of 'name', 'value' and some extra strings.159String patternString = gcLogTimeRegex + indent(indentCount) + name + ": " + "(" + doubleRegex + ")";160Matcher m = Pattern.compile(patternString).matcher(output);161if (!m.find()) {162throw new RuntimeException("Could not find time log for " + patternString);163}164165String match = m.group();166String value = m.group(1);167168double result = Double.parseDouble(value);169170int index = output.indexOf(match);171if (index != -1) {172output = output.substring(index, output.length());173}174175// Convert to BigDecimal to control the precision of floating point arithmetic.176return BigDecimal.valueOf(result);177}178179// Reference log is printing 1 decimal place of elapsed time.180// So sum of each sub-phases could be slightly larger than the enclosing phase in some cases.181// Because of this we need method to verify that our measurements and calculations are valid.182private static boolean greaterThanOrApproximatelyEqual(BigDecimal phaseTime, BigDecimal sumOfSubPhasesTime, BigDecimal tolerance) {183if (phaseTime.compareTo(sumOfSubPhasesTime) >= 0) {184// phaseTime is greater than or equal.185return true;186}187188BigDecimal diff = sumOfSubPhasesTime.subtract(phaseTime);189if (diff.compareTo(tolerance) <= 0) {190// Difference is within tolerance, so approximately equal.191return true;192}193194// sumOfSubPhasesTime is greater than phaseTime and not within tolerance.195return false;196}197198// Find the first concurrent Reference Processing log and compare phase time vs. sum of sub-phases.199public static void checkLogValue(OutputAnalyzer out) {200output = out.getStdout();201202String patternString = gcLogTimeRegex + indent(0) +203referenceProcessing + ": " + "[0-9]+[.,][0-9]+";204Matcher m = Pattern.compile(patternString).matcher(output);205if (m.find()) {206int start = m.start();207int end = output.length();208// If there's another concurrent Reference Processing log, ignore it.209if (m.find()) {210end = m.start();211}212if (start != -1) {213output = output.substring(start, end);214checkTrimmedLogValue();215}216}217}218219private static void checkTrimmedLogValue() {220BigDecimal refProcTime = getTimeValue(referenceProcessing, 0);221222BigDecimal sumOfSubPhasesTime = getTimeValue(phaseReconsiderSoftReferences, 2);223sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifySoftWeakReferences, 2));224sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifyKeepAliveFinalizer, 2));225sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifyPhantomReferences, 2));226227// If there are 4 phases, we should allow 0.2 tolerance.228final BigDecimal toleranceFor4SubPhases = BigDecimal.valueOf(0.2);229if (!greaterThanOrApproximatelyEqual(refProcTime, sumOfSubPhasesTime, toleranceFor4SubPhases)) {230throw new RuntimeException("Reference Processing time(" + refProcTime + "ms) is less than the sum("231+ sumOfSubPhasesTime + "ms) of each phases");232}233}234235static class GCTest {236static final int SIZE = 512 * 1024;237static Object[] dummy = new Object[SIZE];238239public static void main(String [] args) {240for (int i = 0; i < SIZE; i++) {241dummy[i] = new SoftReference<>(new Object());242}243}244}245}246247248