1 /*
2  * Copyright (c) 2018, 2021, 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.mixedgc;
25 
26 import static sun.hotspot.WhiteBox.getWhiteBox;
27 
28 import java.lang.management.*;
29 import java.util.ArrayList;
30 import java.util.List;
31 
32 import gc.testlibrary.g1.MixedGCProvoker;
33 
34 /*
35  * @test TestOldGenCollectionUsage.java
36  * @bug 8195115
37  * @summary G1 Old Gen's CollectionUsage.used is zero after mixed GC which is incorrect
38  * @requires vm.gc.G1
39  * @library /test/lib /
40  * @modules java.base/jdk.internal.misc
41  * @modules java.management
42  * @build sun.hotspot.WhiteBox
43  * @run driver jdk.test.lib.helpers.ClassFileInstaller sun.hotspot.WhiteBox
44  * @run main/othervm -Xbootclasspath/a:. -XX:+UseG1GC -XX:+UnlockExperimentalVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -verbose:gc -XX:NewSize=2m -XX:MaxNewSize=2m -Xmx14m -Xms14m -XX:+AlwaysTenure -XX:InitiatingHeapOccupancyPercent=100 -XX:-G1UseAdaptiveIHOP -XX:G1MixedGCCountTarget=4 -XX:MaxGCPauseMillis=30000 -XX:G1HeapRegionSize=1m -XX:G1HeapWastePercent=0 -XX:G1MixedGCLiveThresholdPercent=100 gc.g1.mixedgc.TestOldGenCollectionUsage
45  */
46 
47 // 8195115 says that for the "G1 Old Gen" MemoryPool, CollectionUsage.used
48 // is zero for G1 after a mixed collection, which is incorrect. We can not guarantee
49 // that we start with an old gen occupancy of zero though due to allocation during
50 // initialization. We check for "increases during mixed gc" instead.
51 
52 public class TestOldGenCollectionUsage {
53 
54     private static final int HeapRegionSize = 1024 * 1024;
55     private static final int ObjectSize = 20_000;
56 
57     private String poolName = "G1 Old Gen";
58     private String collectorName = "G1 Young Generation";
59 
main(String [] args)60     public static void main(String [] args) throws Exception {
61         TestOldGenCollectionUsage t = new TestOldGenCollectionUsage();
62         t.run();
63     }
64 
TestOldGenCollectionUsage()65     public TestOldGenCollectionUsage() {
66         System.out.println("Monitor G1 Old Gen pool with G1 Young Generation collector.");
67     }
68 
run()69     public void run() {
70         // Find memory pool and collector
71         List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
72         MemoryPoolMXBean pool = null;
73         boolean foundPool = false;
74         for (int i = 0; i < pools.size(); i++) {
75             pool = pools.get(i);
76             String name = pool.getName();
77             if (name.contains(poolName)) {
78                 System.out.println("Found pool: " + name);
79                 foundPool = true;
80                 break;
81             }
82         }
83         if (!foundPool) {
84             throw new RuntimeException(poolName + " not found, test with -XX:+UseG1GC");
85         }
86 
87         List<GarbageCollectorMXBean> collectors = ManagementFactory.getGarbageCollectorMXBeans();
88         GarbageCollectorMXBean collector = null;
89         boolean foundCollector = false;
90         for (int i = 0; i < collectors.size(); i++) {
91             collector = collectors.get(i);
92             String name = collector.getName();
93             if (name.contains(collectorName)) {
94                 System.out.println("Found collector: " + name);
95                 foundCollector = true;
96                 break;
97             }
98         }
99         if (!foundCollector) {
100             throw new RuntimeException(collectorName + " not found, test with -XX:+UseG1GC");
101         }
102 
103         getWhiteBox().fullGC(); // Make sure the heap is in a known state.
104 
105         var liveOldObjects = new ArrayList<byte[]>();
106         MixedGCProvoker.allocateOldObjects(liveOldObjects, HeapRegionSize, ObjectSize);
107 
108         long baseUsage = pool.getCollectionUsage().getUsed();
109         System.out.println(poolName + ": usage after GC = " + baseUsage);
110 
111         // Verify that collections were done
112         long collectionCount = collector.getCollectionCount();
113         System.out.println(collectorName + ": collection count = "
114                            + collectionCount);
115         long collectionTime = collector.getCollectionTime();
116         System.out.println(collectorName + ": collection time  = "
117                            + collectionTime);
118         if (collectionCount <= 0) {
119             throw new RuntimeException("Collection count <= 0");
120         }
121         if (collectionTime <= 0) {
122             throw new RuntimeException("Collector has not run");
123         }
124 
125         MixedGCProvoker.provokeMixedGC(liveOldObjects);
126 
127         long usage = pool.getCollectionUsage().getUsed();
128         System.out.println(poolName + ": usage after GC = " + usage);
129         if (usage <= baseUsage) {
130             throw new RuntimeException(poolName + " found not updating usage");
131         }
132 
133         long newCollectionCount = collector.getCollectionCount();
134         System.out.println(collectorName + ": collection count = "
135                            + newCollectionCount);
136         long newCollectionTime = collector.getCollectionTime();
137         System.out.println(collectorName + ": collection time  = "
138                            + newCollectionTime);
139         if (newCollectionCount <= collectionCount) {
140             throw new RuntimeException("No new collection");
141         }
142         if (newCollectionTime <= collectionTime) {
143             throw new RuntimeException("Collector has not run some more");
144         }
145 
146         System.out.println("Test passed.");
147     }
148 }
149 
150