1 /*
   2  * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 package gc.g1;
  25 
  26 /*
  27  * @test TestGCLogMessages
  28  * @bug 8035406 8027295 8035398 8019342 8027959 8048179 8027962 8069330 8076463 8150630 8160055 8177059 8166191
  29  * @summary Ensure the output for a minor GC with G1
  30  * includes the expected necessary messages.
  31  * @requires vm.gc.G1
  32  * @library /test/lib
  33  * @modules java.base/jdk.internal.misc
  34  *          java.management
  35  * @build sun.hotspot.WhiteBox
  36  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
  37  * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  38  *                   gc.g1.TestGCLogMessages
  39  */
  40 
  41 import jdk.test.lib.process.OutputAnalyzer;
  42 import jdk.test.lib.process.ProcessTools;
  43 import sun.hotspot.code.Compiler;
  44 
  45 public class TestGCLogMessages {
  46 
  47     private enum Level {
  48         OFF(""),
  49         INFO("info"),
  50         DEBUG("debug"),
  51         TRACE("trace");
  52 
  53         private String logName;
  54 
  55         Level(String logName) {
  56             this.logName = logName;
  57         }
  58 
  59         public boolean lessThan(Level other) {
  60             return this.compareTo(other) < 0;
  61         }
  62 
  63         public String toString() {
  64             return logName;
  65         }
  66     }
  67 
  68     private class LogMessageWithLevel {
  69         String message;
  70         Level level;
  71 
  72         public LogMessageWithLevel(String message, Level level) {
  73             this.message = message;
  74             this.level = level;
  75         }
  76 
  77         public boolean isAvailable() {
  78             return true;
  79         }
  80     };
  81 
  82     private class LogMessageWithLevelC2OrJVMCIOnly extends LogMessageWithLevel {
  83         public LogMessageWithLevelC2OrJVMCIOnly(String message, Level level) {
  84             super(message, level);
  85         }
  86 
  87         public boolean isAvailable() {
  88             return Compiler.isC2OrJVMCIIncludedInVmBuild();
  89         }
  90     }
  91 
  92     private LogMessageWithLevel allLogMessages[] = new LogMessageWithLevel[] {
  93         new LogMessageWithLevel("Pre Evacuate Collection Set", Level.INFO),
  94         new LogMessageWithLevel("Evacuate Collection Set", Level.INFO),
  95         new LogMessageWithLevel("Post Evacuate Collection Set", Level.INFO),
  96         new LogMessageWithLevel("Other", Level.INFO),
  97 
  98         // Merge Heap Roots
  99         new LogMessageWithLevel("Merge Heap Roots", Level.INFO),
 100         new LogMessageWithLevel("Prepare Merge Heap Roots", Level.DEBUG),
 101         new LogMessageWithLevel("Eager Reclaim", Level.DEBUG),
 102         new LogMessageWithLevel("Remembered Sets", Level.DEBUG),
 103         new LogMessageWithLevel("Merged Sparse", Level.DEBUG),
 104         new LogMessageWithLevel("Merged Fine", Level.DEBUG),
 105         new LogMessageWithLevel("Merged Coarse", Level.DEBUG),
 106         new LogMessageWithLevel("Hot Card Cache", Level.DEBUG),
 107         new LogMessageWithLevel("Log Buffers", Level.DEBUG),
 108         new LogMessageWithLevel("Dirty Cards", Level.DEBUG),
 109         new LogMessageWithLevel("Skipped Cards", Level.DEBUG),
 110         // Scan Heap Roots
 111         new LogMessageWithLevel("Scan Heap Roots", Level.DEBUG),
 112         new LogMessageWithLevel("Scanned Cards", Level.DEBUG),
 113         new LogMessageWithLevel("Scanned Blocks", Level.DEBUG),
 114         new LogMessageWithLevel("Claimed Chunks", Level.DEBUG),
 115         // Code Roots Scan
 116         new LogMessageWithLevel("Code Root Scan", Level.DEBUG),
 117         // Object Copy
 118         new LogMessageWithLevel("Object Copy", Level.DEBUG),
 119         new LogMessageWithLevel("Copied Bytes", Level.DEBUG),
 120         new LogMessageWithLevel("LAB Waste", Level.DEBUG),
 121         new LogMessageWithLevel("LAB Undo Waste", Level.DEBUG),
 122         // Ext Root Scan
 123         new LogMessageWithLevel("Thread Roots", Level.TRACE),
 124         new LogMessageWithLevel("Universe Roots", Level.TRACE),
 125         new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE),
 126         new LogMessageWithLevel("Management Roots", Level.TRACE),
 127         new LogMessageWithLevel("CLDG Roots", Level.TRACE),
 128         new LogMessageWithLevel("JVMTI Roots", Level.TRACE),
 129         new LogMessageWithLevel("CM RefProcessor Roots", Level.TRACE),
 130         new LogMessageWithLevel("JNI Global Roots", Level.TRACE),
 131         new LogMessageWithLevel("VM Global Roots", Level.TRACE),
 132         // Redirty Cards
 133         new LogMessageWithLevel("Redirty Cards", Level.DEBUG),
 134         new LogMessageWithLevel("Parallel Redirty", Level.TRACE),
 135         new LogMessageWithLevel("Redirtied Cards", Level.TRACE),
 136         // Misc Top-level
 137         new LogMessageWithLevel("Code Roots Purge", Level.DEBUG),
 138         new LogMessageWithLevel("String Deduplication", Level.DEBUG),
 139         new LogMessageWithLevel("Queue Fixup", Level.DEBUG),
 140         new LogMessageWithLevel("Table Fixup", Level.DEBUG),
 141         new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
 142         new LogMessageWithLevel("Region Register", Level.DEBUG),
 143         new LogMessageWithLevel("Prepare Heap Roots", Level.DEBUG),
 144         new LogMessageWithLevel("Concatenate Dirty Card Logs", Level.DEBUG),
 145         // Free CSet
 146         new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
 147         new LogMessageWithLevel("Serial Free Collection Set", Level.TRACE),
 148         new LogMessageWithLevel("Parallel Free Collection Set", Level.TRACE),
 149         new LogMessageWithLevel("Young Free Collection Set", Level.TRACE),
 150         new LogMessageWithLevel("Non-Young Free Collection Set", Level.TRACE),
 151         // Rebuild Free List
 152         new LogMessageWithLevel("Rebuild Free List", Level.DEBUG),
 153         new LogMessageWithLevel("Serial Rebuild Free List", Level.TRACE),
 154         new LogMessageWithLevel("Parallel Rebuild Free List", Level.TRACE),
 155 
 156         // Humongous Eager Reclaim
 157         new LogMessageWithLevel("Humongous Reclaim", Level.DEBUG),
 158         // Merge PSS
 159         new LogMessageWithLevel("Merge Per-Thread State", Level.DEBUG),
 160         // TLAB handling
 161         new LogMessageWithLevel("Prepare TLABs", Level.DEBUG),
 162         new LogMessageWithLevel("Resize TLABs", Level.DEBUG),
 163         // Reference Processing
 164         new LogMessageWithLevel("Reference Processing", Level.DEBUG),
 165         // VM internal reference processing
 166         new LogMessageWithLevel("Weak Processing", Level.DEBUG),
 167         new LogMessageWithLevel("JNI Weak", Level.DEBUG),
 168         new LogMessageWithLevel("StringTable Weak", Level.DEBUG),
 169         new LogMessageWithLevel("ResolvedMethodTable Weak", Level.DEBUG),
 170         new LogMessageWithLevel("VM Weak", Level.DEBUG),
 171 
 172         new LogMessageWithLevelC2OrJVMCIOnly("DerivedPointerTable Update", Level.DEBUG),
 173         new LogMessageWithLevel("Start New Collection Set", Level.DEBUG),
 174     };
 175 
 176     void checkMessagesAtLevel(OutputAnalyzer output, LogMessageWithLevel messages[], Level level) throws Exception {
 177         for (LogMessageWithLevel l : messages) {
 178             if (level.lessThan(l.level) || !l.isAvailable()) {
 179                 output.shouldNotContain(l.message);
 180             } else {
 181                 output.shouldMatch("\\[" + l.level + ".*" + l.message);
 182             }
 183         }
 184     }
 185 
 186     public static void main(String[] args) throws Exception {
 187         new TestGCLogMessages().testNormalLogs();
 188         new TestGCLogMessages().testConcurrentRefinementLogs();
 189         new TestGCLogMessages().testWithToSpaceExhaustionLogs();
 190         new TestGCLogMessages().testWithInitialMark();
 191         new TestGCLogMessages().testExpandHeap();
 192     }
 193 
 194     private void testNormalLogs() throws Exception {
 195 
 196         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 197                                                                   "-Xmx10M",
 198                                                                   GCTest.class.getName());
 199 
 200         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 201         checkMessagesAtLevel(output, allLogMessages, Level.OFF);
 202         output.shouldHaveExitValue(0);
 203 
 204         pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 205                                                    "-XX:+UseStringDeduplication",
 206                                                    "-Xmx10M",
 207                                                    "-Xlog:gc+phases=debug",
 208                                                    GCTest.class.getName());
 209 
 210         output = new OutputAnalyzer(pb.start());
 211         checkMessagesAtLevel(output, allLogMessages, Level.DEBUG);
 212 
 213         pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 214                                                    "-XX:+UseStringDeduplication",
 215                                                    "-Xmx10M",
 216                                                    "-Xlog:gc+phases=trace",
 217                                                    GCTest.class.getName());
 218 
 219         output = new OutputAnalyzer(pb.start());
 220         checkMessagesAtLevel(output, allLogMessages, Level.TRACE);
 221         output.shouldHaveExitValue(0);
 222     }
 223 
 224     LogMessageWithLevel concRefineMessages[] = new LogMessageWithLevel[] {
 225         new LogMessageWithLevel("Mutator refinement: ", Level.DEBUG),
 226         new LogMessageWithLevel("Concurrent refinement: ", Level.DEBUG),
 227         new LogMessageWithLevel("Total refinement: ", Level.DEBUG),
 228         // "Concurrent refinement rate" optionally printed if any.
 229         // "Generate dirty cards rate" optionally printed if any.
 230     };
 231 
 232     private void testConcurrentRefinementLogs() throws Exception {
 233         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 234                                                                   "-Xmx10M",
 235                                                                   "-Xlog:gc+refine+stats=debug",
 236                                                                   GCTest.class.getName());
 237         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 238         checkMessagesAtLevel(output, concRefineMessages, Level.DEBUG);
 239     }
 240 
 241     LogMessageWithLevel exhFailureMessages[] = new LogMessageWithLevel[] {
 242         new LogMessageWithLevel("Evacuation Failure", Level.DEBUG),
 243         new LogMessageWithLevel("Recalculate Used", Level.TRACE),
 244         new LogMessageWithLevel("Remove Self Forwards", Level.TRACE),
 245     };
 246 
 247     private void testWithToSpaceExhaustionLogs() throws Exception {
 248         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 249                                                                   "-Xmx32M",
 250                                                                   "-Xmn16M",
 251                                                                   "-Xlog:gc+phases=debug",
 252                                                                   GCTestWithToSpaceExhaustion.class.getName());
 253 
 254         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 255         checkMessagesAtLevel(output, exhFailureMessages, Level.DEBUG);
 256         output.shouldHaveExitValue(0);
 257 
 258         pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 259                                                    "-Xmx32M",
 260                                                    "-Xmn16M",
 261                                                    "-Xlog:gc+phases=trace",
 262                                                    GCTestWithToSpaceExhaustion.class.getName());
 263 
 264         output = new OutputAnalyzer(pb.start());
 265         checkMessagesAtLevel(output, exhFailureMessages, Level.TRACE);
 266         output.shouldHaveExitValue(0);
 267     }
 268 
 269     private void testWithInitialMark() throws Exception {
 270         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 271                                                                   "-Xmx10M",
 272                                                                   "-Xbootclasspath/a:.",
 273                                                                   "-Xlog:gc*=debug",
 274                                                                   "-XX:+UnlockDiagnosticVMOptions",
 275                                                                   "-XX:+WhiteBoxAPI",
 276                                                                   GCTestWithInitialMark.class.getName());
 277 
 278         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 279         output.shouldContain("Clear Claimed Marks");
 280         output.shouldHaveExitValue(0);
 281     }
 282 
 283     private void testExpandHeap() throws Exception {
 284         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
 285                                                                   "-Xmx10M",
 286                                                                   "-Xbootclasspath/a:.",
 287                                                                   "-Xlog:gc+ergo+heap=debug",
 288                                                                   "-XX:+UnlockDiagnosticVMOptions",
 289                                                                   "-XX:+WhiteBoxAPI",
 290                                                                   GCTest.class.getName());
 291 
 292         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 293         output.shouldContain("Expand the heap. requested expansion amount: ");
 294         output.shouldContain("B expansion amount: ");
 295         output.shouldHaveExitValue(0);
 296     }
 297 
 298 
 299     static class GCTest {
 300         private static byte[] garbage;
 301         public static void main(String [] args) {
 302             System.out.println("Creating garbage");
 303             // create 128MB of garbage. This should result in at least one GC
 304             for (int i = 0; i < 1024; i++) {
 305                 garbage = new byte[128 * 1024];
 306             }
 307             System.out.println("Done");
 308         }
 309     }
 310 
 311     static class GCTestWithToSpaceExhaustion {
 312         private static byte[] garbage;
 313         private static byte[] largeObject;
 314         public static void main(String [] args) {
 315             largeObject = new byte[16*1024*1024];
 316             System.out.println("Creating garbage");
 317             // create 128MB of garbage. This should result in at least one GC,
 318             // some of them with to-space exhaustion.
 319             for (int i = 0; i < 1024; i++) {
 320                 garbage = new byte[128 * 1024];
 321             }
 322             System.out.println("Done");
 323         }
 324     }
 325 
 326     static class GCTestWithInitialMark {
 327         public static void main(String [] args) {
 328             sun.hotspot.WhiteBox WB = sun.hotspot.WhiteBox.getWhiteBox();
 329             WB.g1StartConcMarkCycle();
 330         }
 331     }
 332 
 333 }
 334