|
1 /* |
|
2 * Copyright (c) 2013, 2018, 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 metaspace.gc; |
|
25 |
|
26 import java.util.Arrays; |
|
27 import vm.share.VMRuntimeEnvUtils; |
|
28 |
|
29 /** |
|
30 * Test metaspace ergonomic. |
|
31 * |
|
32 * <ul> |
|
33 * <li>MetaspaceSize |
|
34 * <li>MaxMetaspaceSize |
|
35 * <li>MinMetaspaceFreeRatio |
|
36 * <li>MaxMetaspaceFreeRatio |
|
37 * </ul> |
|
38 * |
|
39 * The test loads classes until the committed metaspace achieves the certain |
|
40 * level between MetaspaceSize and MaxMetaspaceSize. |
|
41 * Then it counts how many times GC has been induced. |
|
42 * Test verifies that MinMetaspaceFreeRatio/MaxMetaspaceFreeRatio settings |
|
43 * affect the frequency of GC. (High-water mark) |
|
44 * |
|
45 * Note: The test doesn't check the GC count if CMS is used. |
|
46 * |
|
47 * Quoting: Java SE 8 HotSpot[tm] Virtual Machine Garbage Collection Tuning |
|
48 * <pre> |
|
49 * Class metadata is deallocated when the corresponding Java class is unloaded. |
|
50 * Java classes are unloaded as a results of garbage collection and garbage |
|
51 * collections may be induced in order to unload classes and deallocate class |
|
52 * metadata. When the space used for class metadata reaches a certain level |
|
53 * (call it a high-water mark), a garbage collection is induced. |
|
54 * After the garbage collection the high-water mark may be raised or lowered |
|
55 * depending on the amount of space freed from class metadata. The high-water |
|
56 * mark would be raised so as not to induce another garbage collection too soon. |
|
57 * The high-water mark is initially set to the value of the command-line |
|
58 * flag MetaspaceSize . It is raised or lowered based on the flags |
|
59 * MaxMetaspaceFreeRatio and MinMetaspaceFreeRatio. |
|
60 * If the committed space available for class metadata as a percentage of |
|
61 * the total committed space for class metadata is greater than |
|
62 * MaxMetaspaceFreeRatio, the high-water mark will be lowered. |
|
63 * If it is less than MinMetaspaceFreeRatio, the high-water mark will be raised. |
|
64 * </pre> |
|
65 */ |
|
66 public class HighWaterMarkTest extends FirstGCTest { |
|
67 |
|
68 public static void main(String... args) { |
|
69 new HighWaterMarkTest().run(args); |
|
70 } |
|
71 |
|
72 // value given in -XX:MetaspaceSize=<value> |
|
73 private long metaspaceSize = -1; |
|
74 |
|
75 // value given in -XX:MaxMetaspaceSize=<value> |
|
76 private long maxMetaspaceSize = -1; |
|
77 |
|
78 // value given in -XX:MinMetaspaceFreeRatio=<value> |
|
79 private long minMetaspaceFreeRatio = -1; |
|
80 |
|
81 // value given in -XX:MaxMetaspaceFreeRatio=<value> |
|
82 private long maxMetaspaceFreeRatio = -1; |
|
83 |
|
84 /** |
|
85 * Parses arguments and vm options. |
|
86 * Throws Fault in cases of wrong values or missed parameters. |
|
87 * |
|
88 * @param args command line options |
|
89 */ |
|
90 @Override |
|
91 protected void parseArgs(String[] args) { |
|
92 if (args.length > 0) { |
|
93 printUsage(); |
|
94 throw new Fault("Illegal arguments: " + Arrays.asList(args)); |
|
95 } |
|
96 |
|
97 if (gclogFileName == null) { |
|
98 printUsage(); |
|
99 throw new Fault("Log file name is not given"); |
|
100 } |
|
101 |
|
102 final String metaSize = "-XX:MetaspaceSize="; |
|
103 final String maxMetaSize = "-XX:MaxMetaspaceSize="; |
|
104 final String minRatio = "-XX:MinMetaspaceFreeRatio="; |
|
105 final String maxRatio = "-XX:MaxMetaspaceFreeRatio="; |
|
106 |
|
107 for (String va: vmArgs) { |
|
108 if (va.startsWith(metaSize)) { |
|
109 metaspaceSize = parseValue(va.substring(metaSize.length())); |
|
110 } else if (va.startsWith(maxMetaSize)) { |
|
111 maxMetaspaceSize = parseValue(va.substring(maxMetaSize.length())); |
|
112 } else if (va.startsWith(minRatio)) { |
|
113 minMetaspaceFreeRatio = parseValue(va.substring(minRatio.length())); |
|
114 } else if (va.startsWith(maxRatio)) { |
|
115 maxMetaspaceFreeRatio = parseValue(va.substring(maxRatio.length())); |
|
116 } |
|
117 } |
|
118 |
|
119 if (metaspaceSize < 0) { |
|
120 printUsage(); |
|
121 throw new Fault("-XX:MetaspaceSize is not specified"); |
|
122 } else if (maxMetaspaceSize < 0) { |
|
123 printUsage(); |
|
124 throw new Fault("-XX:MaxMetaspaceSize is not specified"); |
|
125 } else if (minMetaspaceFreeRatio < 0) { |
|
126 printUsage(); |
|
127 throw new Fault("-XX:MinMetaspaceFreeRatio is not specified"); |
|
128 } else if (maxMetaspaceFreeRatio < 0) { |
|
129 printUsage(); |
|
130 throw new Fault("-XX:MaxMetaspaceFreeRatio is not specified"); |
|
131 } |
|
132 |
|
133 } |
|
134 |
|
135 private void printUsage() { |
|
136 System.err.println("Usage: "); |
|
137 System.err.println("java [-Xlog:gc:<filename>] [-XX:MetaspaceSize=..] [-XX:MaxMetaspaceSize=..] [-XX:MinMetaspaceFreeRatio=..] [-XX:MaxMetaspaceFreeRatio=..] \\"); |
|
138 System.err.println(" " + HighWaterMarkTest.class.getCanonicalName()); |
|
139 } |
|
140 |
|
141 /** |
|
142 * Check that MinMetaspaceFreeRatio/MaxMetaspaceFreeRatio settings |
|
143 * affects the moment of the next GC. |
|
144 * |
|
145 * Eats memory until amount of committed metaspace achieves a certain level |
|
146 * (between MetaspaceSize and MaxMetaspaceSize). |
|
147 * Then checks how many times GC has been invoked. |
|
148 * |
|
149 */ |
|
150 @Override |
|
151 public void doCheck() { |
|
152 |
|
153 // to avoid timeouts we limit the number of attempts |
|
154 int attempts = 0; |
|
155 int maxAttempts = 10_000; |
|
156 |
|
157 // in between metaspaceSize and maxMetaspaceSize |
|
158 // no OOM is exepcted. |
|
159 long committedLevel = (metaspaceSize + maxMetaspaceSize) / 2; |
|
160 |
|
161 while (getCommitted() < committedLevel && attempts < maxAttempts) { |
|
162 attempts++; |
|
163 loadNewClasses(9, true); // load classes and keep references |
|
164 loadNewClasses(1, false); // load classes without keeping references |
|
165 } |
|
166 |
|
167 |
|
168 System.out.println("% Classes loaded: " + attempts*10); |
|
169 System.out.println("% Used metaspace : " + bytes2k(getUsed())); |
|
170 System.out.println("% Committed metaspce: " + bytes2k(getCommitted())); |
|
171 |
|
172 cleanLoadedClasses(); |
|
173 |
|
174 if (attempts == maxAttempts) { |
|
175 throw new Fault("Committed amount hasn't achieved " + bytes2k(committedLevel)); |
|
176 } |
|
177 |
|
178 if (VMRuntimeEnvUtils.isVMOptionEnabled("UseConcMarkSweepGC")) { |
|
179 System.out.println("ConcMarkSweep is used, cannot count GC"); |
|
180 return; |
|
181 } |
|
182 |
|
183 int gcCount = getMetaspaceGCCount(); |
|
184 if (gcCount < 0) { |
|
185 // perhpas, it's better to silently pass here... Let's see. |
|
186 throw new Fault ("Unable to count full collections, could be an env issue"); |
|
187 } |
|
188 System.out.println("% GC has been invoked: " + gcCount + " times"); |
|
189 |
|
190 if (VMRuntimeEnvUtils.isVMOptionEnabled("UseG1GC") && |
|
191 VMRuntimeEnvUtils.isVMOptionEnabled("ClassUnloadingWithConcurrentMark")) { |
|
192 System.out.println("% isG1ClassUnloading: true"); |
|
193 if (gcCount != 0) { |
|
194 throw new Fault ("G1 should unload classes, full GC is not expected"); |
|
195 } |
|
196 } else { |
|
197 if (maxMetaspaceFreeRatio <= 1) { |
|
198 // min/max = 0/1 boundary value |
|
199 // GC should happen very often |
|
200 checkGCCount(gcCount, 20, -1); |
|
201 } else if (minMetaspaceFreeRatio >= 99) { |
|
202 // min/max = 99/100 boundary value |
|
203 // GC should happen very rare |
|
204 checkGCCount(gcCount, -1, 2); |
|
205 } else if (minMetaspaceFreeRatio >= 10 && maxMetaspaceFreeRatio <= 20) { |
|
206 // GC should happen quite often |
|
207 checkGCCount(gcCount, 3, 30); |
|
208 } else if (minMetaspaceFreeRatio >= 70 && maxMetaspaceFreeRatio <= 80) { |
|
209 // GC should happen quite often |
|
210 checkGCCount(gcCount, 1, 3); |
|
211 } else { |
|
212 // hard to estimate |
|
213 } |
|
214 } |
|
215 |
|
216 } |
|
217 /** |
|
218 * Checks that count of GC fits the expected range. |
|
219 * Throws Fault if count is unexpected. |
|
220 * |
|
221 * @param count how many times GC has happened |
|
222 * @param min expected minimum, if under zero - undefined |
|
223 * @param max expected maximum, if under zero - undefined |
|
224 */ |
|
225 void checkGCCount(int count, int min, int max) { |
|
226 if (min < 0) { |
|
227 if(count > max) { |
|
228 throw new Fault("GC has happened too often: " + count + " times, " + |
|
229 "expected count: less than " + max); |
|
230 } |
|
231 } else if (max < 0) { |
|
232 if(count < min) { |
|
233 throw new Fault("GC has happened too rare: " + count + " times, " + |
|
234 "expected count greater than " + min); |
|
235 } |
|
236 } else if (count < min || count > max ) { |
|
237 throw new Fault ("GC has happened " + count + " times, " + |
|
238 "approximate count is " + min + " to " + max); |
|
239 } |
|
240 } |
|
241 |
|
242 } |