test/hotspot/jtreg/gc/logging/TestPrintReferences.java
changeset 50605 7f63c74f0974
parent 50395 41258f041b24
child 50606 8f1d5d706bdd
equal deleted inserted replaced
50604:929621cf06b4 50605:7f63c74f0974
    39 import jdk.test.lib.process.ProcessTools;
    39 import jdk.test.lib.process.ProcessTools;
    40 import java.util.regex.Pattern;
    40 import java.util.regex.Pattern;
    41 import java.util.regex.Matcher;
    41 import java.util.regex.Matcher;
    42 
    42 
    43 public class TestPrintReferences {
    43 public class TestPrintReferences {
    44   static String output;
    44     static String output;
    45   static final String doubleRegex = "[0-9]+[.,][0-9]+";
    45     static final String doubleRegex = "[0-9]+[.,][0-9]+";
    46   static final String referenceProcessing = "Reference Processing";
    46     static final String referenceProcessing = "Reference Processing";
    47   static final String softReference = "SoftReference";
    47     static final String softReference = "SoftReference";
    48   static final String weakReference = "WeakReference";
    48     static final String weakReference = "WeakReference";
    49   static final String finalReference = "FinalReference";
    49     static final String finalReference = "FinalReference";
    50   static final String phantomReference = "PhantomReference";
    50     static final String phantomReference = "PhantomReference";
    51   static final String phase1 = "Phase1";
    51 
    52   static final String phase2 = "Phase2";
    52     static final String phaseReconsiderSoftReferences = "Reconsider SoftReferences";
    53   static final String phase3 = "Phase3";
    53     static final String phaseNotifySoftWeakReferences = "Notify Soft/WeakReferences";
    54   static final String gcLogTimeRegex = ".* GC\\([0-9]+\\) ";
    54     static final String phaseNotifyKeepAliveFinalizer = "Notify and keep alive finalizable";
    55 
    55     static final String phaseNotifyPhantomReferences  = "Notify PhantomReferences";
    56   public static void main(String[] args) throws Exception {
    56 
    57     test(true);
    57     static final String phase1 = "Phase1";
    58     test(false);
    58     static final String phase2 = "Phase2";
    59   }
    59     static final String phase3 = "Phase3";
    60 
    60     static final String gcLogTimeRegex = ".* GC\\([0-9]+\\) ";
    61   static String indent(int count) {
    61 
    62     return " {" + count + "}";
    62     public static void main(String[] args) throws Exception {
    63   }
    63         testPhases(true);
    64 
    64         testPhases(false);
    65   public static void test(boolean parallelRefProcEnabled) throws Exception {
    65         testRefs();
    66     ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+phases+ref=debug",
    66     }
    67                                                                       "-XX:+UseG1GC",
    67 
    68                                                                       "-Xmx32M",
    68     static String indent(int count) {
    69                                                                       // Explicit thread setting is required to avoid using only 1 thread
    69         return " {" + count + "}";
    70                                                                       "-XX:" + (parallelRefProcEnabled ? "+" : "-") + "ParallelRefProcEnabled",
    70     }
    71                                                                       "-XX:ParallelGCThreads=2",
    71 
    72                                                                       GCTest.class.getName());
    72     public static void testRefs() throws Exception {
    73     OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());
    73         ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+ref+phases=debug",
    74 
    74                                                                           "-XX:+UseG1GC",
    75     checkLogFormat(output, parallelRefProcEnabled);
    75                                                                           "-Xmx32M",
    76     checkLogValue(output);
    76                                                                           GCTest.class.getName());
    77 
    77         OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());
    78     output.shouldHaveExitValue(0);
    78 
    79   }
    79         checkRefsLogFormat(output);
    80 
    80 
    81   // Find the first Reference Processing log and check its format.
    81         output.shouldHaveExitValue(0);
    82   public static void checkLogFormat(OutputAnalyzer output, boolean parallelRefProcEnabled) {
    82     }
    83     String countRegex = "[0-9]+";
    83 
    84     String timeRegex = doubleRegex + "ms";
    84     private static String refRegex(String reftype) {
    85     String totalRegex = gcLogTimeRegex + indent(4) + referenceProcessing + ": " + timeRegex + "\n";
    85         String countRegex = "[0-9]+";
    86     String balanceRegex = parallelRefProcEnabled ? gcLogTimeRegex + indent(8) + "Balance queues: " + timeRegex + "\n" : "";
    86         return gcLogTimeRegex + indent(6) + reftype + ":\n" +
    87     String softRefRegex = gcLogTimeRegex + indent(6) + softReference + ": " + timeRegex + "\n";
    87                gcLogTimeRegex + indent(8) + "Discovered: " + countRegex + "\n" +
    88     String weakRefRegex = gcLogTimeRegex + indent(6) + weakReference + ": " + timeRegex + "\n";
    88                gcLogTimeRegex + indent(8) + "Cleared: " + countRegex + "\n";
    89     String finalRefRegex = gcLogTimeRegex + indent(6) + finalReference + ": " + timeRegex + "\n";
    89     }
    90     String phantomRefRegex = gcLogTimeRegex + indent(6) + phantomReference + ": " + timeRegex + "\n";
    90 
    91     String refDetailRegex = gcLogTimeRegex + indent(8) + phase2 + ": " + timeRegex + "\n" +
    91     private static void checkRefsLogFormat(OutputAnalyzer output) {
    92                             gcLogTimeRegex + indent(8) + phase3 + ": " + timeRegex + "\n" +
    92         output.shouldMatch(refRegex("SoftReference") +
    93                             gcLogTimeRegex + indent(8) + "Discovered: " + countRegex + "\n" +
    93                            refRegex("WeakReference") +
    94                             gcLogTimeRegex + indent(8) + "Cleared: " + countRegex + "\n";
    94                            refRegex("FinalReference") +
    95     String softRefDetailRegex = gcLogTimeRegex + indent(8) + phase1 + ": " + timeRegex + "\n" + refDetailRegex;
    95                            refRegex("PhantomReference"));
    96 
    96     }
    97     output.shouldMatch(/* Total Reference processing time */
    97 
    98                        totalRegex +
    98     public static void testPhases(boolean parallelRefProcEnabled) throws Exception {
    99                        /* SoftReference processing */
    99         ProcessBuilder pb_enabled = ProcessTools.createJavaProcessBuilder("-Xlog:gc+phases+ref=debug",
   100                        softRefRegex + balanceRegex + softRefDetailRegex +
   100                                                                           "-XX:+UseG1GC",
   101                        /* WeakReference processing */
   101                                                                           "-Xmx32M",
   102                        weakRefRegex + balanceRegex + refDetailRegex +
   102                                                                           "-XX:" + (parallelRefProcEnabled ? "+" : "-") + "ParallelRefProcEnabled",
   103                        /* FinalReference processing */
   103                                                                           "-XX:-UseDynamicNumberOfGCThreads",
   104                        finalRefRegex + balanceRegex + refDetailRegex +
   104                                                                           "-XX:ParallelGCThreads=2",
   105                        /* PhantomReference processing */
   105                                                                           GCTest.class.getName());
   106                        phantomRefRegex + balanceRegex + refDetailRegex
   106         OutputAnalyzer output = new OutputAnalyzer(pb_enabled.start());
   107                        );
   107 
   108   }
   108         checkLogFormat(output, parallelRefProcEnabled);
   109 
   109         checkLogValue(output);
   110   // After getting time value, update 'output' for next use.
   110 
   111   public static BigDecimal getTimeValue(String name, int indentCount) {
   111         output.shouldHaveExitValue(0);
   112     // Pattern of 'name', 'value' and some extra strings.
   112     }
   113     String patternString = gcLogTimeRegex + indent(indentCount) + name + ": " + "(" + doubleRegex + ")";
   113 
   114     Matcher m = Pattern.compile(patternString).matcher(output);
   114     private static String phaseRegex(String phaseName) {
   115      if (!m.find()) {
   115         final String timeRegex = doubleRegex + "ms";
   116       throw new RuntimeException("Could not find time log for " + patternString);
   116         return indent(6) + phaseName + ": " + timeRegex + "\n";
   117      }
   117     }
   118 
   118 
   119     String match = m.group();
   119     private static String subphaseRegex(String subphaseName, boolean parallelRefProcEnabled) {
   120     String value = m.group(1);
   120         final String timeRegex = "\\s+" + doubleRegex;
   121 
   121         if (parallelRefProcEnabled) {
   122     double result = Double.parseDouble(value);
   122             final String timeInParRegex = timeRegex +",\\s";
   123 
   123             return gcLogTimeRegex + indent(8) + subphaseName +
   124     int index = output.indexOf(match);
   124                    " \\(ms\\):\\s+Min: " + timeInParRegex + "Avg: " + timeInParRegex + "Max: " + timeInParRegex + "Diff: " + timeInParRegex + "Sum: " + timeInParRegex +
   125     if (index != -1) {
   125                    "Workers: [0-9]+" + "\n";
   126       output = output.substring(index, output.length());
   126         } else {
   127     }
   127             return gcLogTimeRegex + indent(8) + subphaseName + ":" + timeRegex + "ms\n";
   128 
   128         }
   129     // Convert to BigDecimal to control the precision of floating point arithmetic.
   129     }
   130     return BigDecimal.valueOf(result);
   130 
   131   }
   131     // Find the first Reference Processing log and check its format.
   132 
   132     private static void checkLogFormat(OutputAnalyzer output, boolean parallelRefProcEnabled) {
   133   // Reference log is printing 1 decimal place of elapsed time.
   133         String countRegex = "[0-9]+";
   134   // So sum of each sub-phases could be slightly larger than the enclosing phase in some cases.
   134         String timeRegex = doubleRegex + "ms";
   135   // e.g. If there are 3 sub-phases:
   135 
   136   //      Actual value:  SoftReference(5.55) = phase1(1.85) + phase2(1.85) + phase3(1.85)
   136         /* Total Reference processing time */
   137   //      Log value:     SoftReference(5.6) = phase1(1.9) + phase2(1.9) + phase3(1.9)
   137         String totalRegex = gcLogTimeRegex + indent(4) + referenceProcessing + ": " + timeRegex + "\n";
   138   //      When checked:  5.6 < 5.7 (sum of phase1~3)
   138 
   139   // Because of this we need method to verify that our measurements and calculations are valid.
   139         String balanceRegex = parallelRefProcEnabled ? gcLogTimeRegex + indent(8) + "Balance queues: " + timeRegex + "\n" : "";
   140   public static boolean greaterThanOrApproximatelyEqual(BigDecimal phaseTime, BigDecimal sumOfSubPhasesTime, BigDecimal tolerance) {
   140 
   141     if (phaseTime.compareTo(sumOfSubPhasesTime) >= 0) {
   141         final boolean p = parallelRefProcEnabled;
   142       // phaseTime is greater than or equal.
   142 
   143       return true;
   143         String phase1Regex = gcLogTimeRegex + phaseRegex(phaseReconsiderSoftReferences) + balanceRegex + subphaseRegex("SoftRef", p);
   144     }
   144         String phase2Regex = gcLogTimeRegex + phaseRegex(phaseNotifySoftWeakReferences) +
   145 
   145                              balanceRegex +
   146     BigDecimal diff = sumOfSubPhasesTime.subtract(phaseTime);
   146                              subphaseRegex("SoftRef", p) +
   147     if (diff.compareTo(tolerance) <= 0) {
   147                              subphaseRegex("WeakRef", p) +
   148       // Difference is within tolerance, so approximately equal.
   148                              subphaseRegex("FinalRef", p) +
   149       return true;
   149                              subphaseRegex("Total", p);
   150     }
   150         String phase3Regex = gcLogTimeRegex + phaseRegex(phaseNotifyKeepAliveFinalizer) + balanceRegex + subphaseRegex("FinalRef", p);
   151 
   151         String phase4Regex = gcLogTimeRegex + phaseRegex(phaseNotifyPhantomReferences) + balanceRegex + subphaseRegex("PhantomRef", p);
   152     // sumOfSubPhasesTime is greater than phaseTime and not within tolerance.
   152 
   153     return false;
   153         output.shouldMatch(totalRegex +
   154   }
   154                            phase1Regex +
   155 
   155                            phase2Regex +
   156   public static BigDecimal checkPhaseTime(String refType) {
   156                            phase3Regex +
   157     BigDecimal phaseTime = getTimeValue(refType, 2);
   157                            phase4Regex);
   158     BigDecimal sumOfSubPhasesTime = BigDecimal.valueOf(0.0);
   158     }
   159 
   159 
   160     if (softReference.equals(refType)) {
   160     // After getting time value, update 'output' for next use.
   161       sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase1, 4));
   161     private static BigDecimal getTimeValue(String name, int indentCount) {
   162     }
   162         // Pattern of 'name', 'value' and some extra strings.
   163     sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase2, 4));
   163         String patternString = gcLogTimeRegex + indent(indentCount) + name + ": " + "(" + doubleRegex + ")";
   164     sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phase3, 4));
   164         Matcher m = Pattern.compile(patternString).matcher(output);
   165 
   165         if (!m.find()) {
   166     // If there are 3 sub-phases, we should allow 0.1 tolerance.
   166             throw new RuntimeException("Could not find time log for " + patternString);
   167     final BigDecimal toleranceFor3SubPhases = BigDecimal.valueOf(0.1);
   167         }
   168     if (!greaterThanOrApproximatelyEqual(phaseTime, sumOfSubPhasesTime, toleranceFor3SubPhases)) {
   168 
   169       throw new RuntimeException(refType +" time(" + phaseTime +
   169         String match = m.group();
   170                                  "ms) is less than the sum(" + sumOfSubPhasesTime + "ms) of each phases");
   170         String value = m.group(1);
   171     }
   171 
   172 
   172         double result = Double.parseDouble(value);
   173     return phaseTime;
   173 
   174   }
   174         int index = output.indexOf(match);
   175 
   175         if (index != -1) {
   176   // Find the first concurrent Reference Processing log and compare phase time vs. sum of sub-phases.
   176             output = output.substring(index, output.length());
   177   public static void checkLogValue(OutputAnalyzer out) {
   177         }
   178     output = out.getStdout();
   178 
   179 
   179         // Convert to BigDecimal to control the precision of floating point arithmetic.
   180     String patternString = gcLogTimeRegex + indent(0) +
   180         return BigDecimal.valueOf(result);
   181                            referenceProcessing + ": " + "[0-9]+[.,][0-9]+";
   181    }
   182     Matcher m = Pattern.compile(patternString).matcher(output);
   182 
   183     if (m.find()) {
   183     // Reference log is printing 1 decimal place of elapsed time.
   184         int start = m.start();
   184     // So sum of each sub-phases could be slightly larger than the enclosing phase in some cases.
   185         int end = output.length();
   185     // Because of this we need method to verify that our measurements and calculations are valid.
   186         // If there's another concurrent Reference Processing log, ignore it.
   186     private static boolean greaterThanOrApproximatelyEqual(BigDecimal phaseTime, BigDecimal sumOfSubPhasesTime, BigDecimal tolerance) {
       
   187         if (phaseTime.compareTo(sumOfSubPhasesTime) >= 0) {
       
   188             // phaseTime is greater than or equal.
       
   189             return true;
       
   190         }
       
   191 
       
   192         BigDecimal diff = sumOfSubPhasesTime.subtract(phaseTime);
       
   193         if (diff.compareTo(tolerance) <= 0) {
       
   194             // Difference is within tolerance, so approximately equal.
       
   195             return true;
       
   196         }
       
   197 
       
   198         // sumOfSubPhasesTime is greater than phaseTime and not within tolerance.
       
   199         return false;
       
   200     }
       
   201 
       
   202     // Find the first concurrent Reference Processing log and compare phase time vs. sum of sub-phases.
       
   203     public static void checkLogValue(OutputAnalyzer out) {
       
   204         output = out.getStdout();
       
   205 
       
   206         String patternString = gcLogTimeRegex + indent(0) +
       
   207                                referenceProcessing + ": " + "[0-9]+[.,][0-9]+";
       
   208         Matcher m = Pattern.compile(patternString).matcher(output);
   187         if (m.find()) {
   209         if (m.find()) {
   188             end = m.start();
   210             int start = m.start();
   189         }
   211             int end = output.length();
   190         if (start != -1) {
   212             // If there's another concurrent Reference Processing log, ignore it.
   191             output = output.substring(start, end);
   213             if (m.find()) {
   192             checkTrimmedLogValue();
   214                 end = m.start();
   193         }
   215             }
   194      }
   216             if (start != -1) {
   195   }
   217                 output = output.substring(start, end);
   196 
   218                 checkTrimmedLogValue();
   197   public static void checkTrimmedLogValue() {
   219             }
   198     BigDecimal refProcTime = getTimeValue(referenceProcessing, 0);
   220         }
   199 
   221     }
   200     BigDecimal sumOfSubPhasesTime = checkPhaseTime(softReference);
   222 
   201     sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(weakReference));
   223     private static void checkTrimmedLogValue() {
   202     sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(finalReference));
   224         BigDecimal refProcTime = getTimeValue(referenceProcessing, 0);
   203     sumOfSubPhasesTime = sumOfSubPhasesTime.add(checkPhaseTime(phantomReference));
   225 
   204 
   226         BigDecimal sumOfSubPhasesTime = getTimeValue(phaseReconsiderSoftReferences, 2);
   205     // If there are 4 sub-phases, we should allow 0.2 tolerance.
   227         sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifySoftWeakReferences, 2));
   206     final BigDecimal toleranceFor4SubPhases = BigDecimal.valueOf(0.2);
   228         sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifyKeepAliveFinalizer, 2));
   207     if (!greaterThanOrApproximatelyEqual(refProcTime, sumOfSubPhasesTime, toleranceFor4SubPhases)) {
   229         sumOfSubPhasesTime = sumOfSubPhasesTime.add(getTimeValue(phaseNotifyPhantomReferences, 2));
   208       throw new RuntimeException("Reference Processing time(" + refProcTime + "ms) is less than the sum("
   230 
   209                                  + sumOfSubPhasesTime + "ms) of each phases");
   231         // If there are 4 phases, we should allow 0.2 tolerance.
   210     }
   232         final BigDecimal toleranceFor4SubPhases = BigDecimal.valueOf(0.2);
   211   }
   233         if (!greaterThanOrApproximatelyEqual(refProcTime, sumOfSubPhasesTime, toleranceFor4SubPhases)) {
   212 
   234             throw new RuntimeException("Reference Processing time(" + refProcTime + "ms) is less than the sum("
   213   static class GCTest {
   235                                        + sumOfSubPhasesTime + "ms) of each phases");
   214     static final int SIZE = 512 * 1024;
   236         }
   215     static Object[] dummy = new Object[SIZE];
   237     }
   216 
   238 
   217     public static void main(String [] args) {
   239     static class GCTest {
   218       for (int i = 0; i < SIZE; i++) {
   240         static final int SIZE = 512 * 1024;
   219         dummy[i] = new SoftReference<>(new Object());
   241         static Object[] dummy = new Object[SIZE];
   220       }
   242 
   221     }
   243         public static void main(String [] args) {
   222   }
   244              for (int i = 0; i < SIZE; i++) {
       
   245                   dummy[i] = new SoftReference<>(new Object());
       
   246              }
       
   247         }
       
   248     }
   223 }
   249 }