rev 60538 : imported patch jep387-all.patch
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.io.IOException;
27 import java.lang.management.ManagementFactory;
28 import java.lang.management.MemoryPoolMXBean;
29 import java.lang.management.MemoryUsage;
30 import java.lang.reflect.Field;
31 import java.lang.reflect.InvocationHandler;
32 import java.lang.reflect.Method;
33 import java.lang.reflect.Proxy;
34 import java.net.URL;
35 import java.net.URLClassLoader;
36 import java.nio.file.Files;
37 import java.nio.file.Paths;
38 import java.util.HashMap;
39 import java.util.HashSet;
40 import java.util.List;
41 import java.util.Map;
42 import java.util.Set;
43 import jdk.internal.misc.Unsafe;
44
45 /**
46 * Test that checks how GC works with Metaspace and "Compared Class Space".
47 *
48 * It comprises 3 test cases:
49 * <ul>
50 * <li>testcase1 - checks that used/committed memory doesn't grow
51 * when gc is invoked</li>
52 * <li>testcase2 - checks that gc is invoked when the class metadata u
53 * sage reaches MetaspaceSize</li>
54 * <li>testcase3 - checks used/committed grow, inspite of gc is invoked</li>
55 * </ul>
56 *
57 * It's supposed that this class will be executed with various setting of VM
58 * flags. Via execute args it's possible to say which test cases to run and
59 * what space to test: Metaspace or Compared Class Space.
60 */
61 public abstract class MetaspaceBaseGC {
62
63 // storage of loaded classes
64 private final Map<String, MetaspaceBaseGC.Foo> loadedClasses = new HashMap<>();
65 private static int counter = 0;
66
67 // pool to test
68 protected MemoryPoolMXBean pool = null;
69
70 // memory page size
71 protected static final long PAGE_SIZE = detectPageSize();
72
73 // true when PAGE_SIZE is large and
74 protected boolean useLargepages = false;
75
76 // where the log will be saved
77 protected String gclogFileName = null;
78
79 protected final Set<String> vmArgs = new HashSet<>();
80
81 protected abstract void parseArgs(String args[]);
82 protected abstract String getPoolName();
83 protected abstract void doCheck();
84
85 public final void run(String args[]) {
86 configure(args);
87 if (pool == null) {
88 System.out.println("%%% Cannot pull the pool, most likely 32-bits only");
89 return;
90 }
91 System.out.println("%%% Working with " + getPoolName());
92 for (String vmA: vmArgs) {
93 if (vmA.contains("Metaspace") || vmA.contains("Compressed")) {
94 System.out.println("% " + vmA);
95 }
96 }
97 doCheck();
98 System.out.println("% Test passed.");
99 }
100
101
102 protected void configure(String args[]) {
103 vmArgs.addAll(ManagementFactory.getRuntimeMXBean().getInputArguments());
104 useLargepages = PAGE_SIZE > 1_000_000 && !vmArgs.contains("-XX:-UseLargePagesInMetaspace");
105
106 System.out.println(vmArgs);
107
108 pool = getMemoryPool(getPoolName());
109 if (pool == null) {
110 return; // nothing to check
111 }
112 for (String arg: vmArgs) {
113 if (arg.startsWith("-Xlog:gc") && arg.length() > 8) {
114 gclogFileName = arg.substring(arg.lastIndexOf(':') + 1);
115 }
116 }
117 parseArgs(args);
118 }
119
120
121 /**
122 * Imitates class loading.
123 * Each invocation of this method causes a new class loader object is created
124 * and a new class is loaded by this class loader.
125 * Method throws OOM when run out of memory.
126 *
127 * @param times how many classes to load
128 * @param keepRefs true, if references to created classes should be stored
129 */
130 protected void loadNewClasses(int times, boolean keepRefs) {
131 for (int i = 0; i < times; i++) {
132 try {
133 String jarUrl = "file:" + counter + ".jar";
134 counter++;
135 URL[] urls = new URL[]{new URL(jarUrl)};
136 URLClassLoader cl = new URLClassLoader(urls);
137 MetaspaceBaseGC.Foo foo = (MetaspaceBaseGC.Foo) Proxy.newProxyInstance(cl,
138 new Class[]{MetaspaceBaseGC.Foo.class},
139 new MetaspaceBaseGC.FooInvocationHandler(new MetaspaceBaseGC.FooBar()));
140 if (keepRefs) {
141 loadedClasses.put(jarUrl, foo);
142 }
143 } catch (java.net.MalformedURLException badThing) {
144 // should never occur
145 System.err.println("Unexpeted error: " + badThing);
146 throw new RuntimeException(badThing);
147 }
148 }
149
150 }
151
152 /**
153 * Cleans references to loaded classes.
154 */
155 protected void cleanLoadedClasses() {
156 loadedClasses.clear();
157 }
158
159 /**
160 * Invokes System.gc() and sleeps a little.
161 */
162 protected void gc() {
163 System.gc();
164 try {
165 Thread.currentThread().sleep(500);
166 } catch (Exception whatever) {
167 }
168 }
169
170 /**
171 * Reads gc.log file and returns it as a list of lines.
172 * It's supposed that the test is executed with -Xlog:gc:gc.log option.
173 *
174 * @return List of strings the gc.log file is comprised.
175 * @throws IOException if problem occurred while reading.
176 */
177 protected List<String> readGCLog() throws IOException {
178 return Files.readAllLines(Paths.get(".", gclogFileName));
179 }
180
181 /**
182 * Reads gc.log file and counts GC induced by metaspace.
183 * @return how many times GC induced by metaspace has occurred.
184 */
185 protected int getMetaspaceGCCount() {
186 int count = 0;
187 try {
188 for (String line: readGCLog()) {
189 if (line.indexOf("Metadata GC ") > 0) {
190 count++;
191 }
192 }
193 return count;
194 } catch (Throwable t) {
195 t.printStackTrace(System.err);
196 return -1;
197 }
198 }
199
200 protected String lastGCLogLine() {
201 if (gclogFileName == null) {
202 return "";
203 }
204 try {
205 List<String> list = Files.readAllLines(Paths.get(".", gclogFileName));
206 return list.get(list.size() - 1);
207 } catch (IOException e) {
208 return "File not found";
209 }
210 }
211
212 /**
213 * Does it best to checks if the last GC was caused by metaspace.
214 *
215 * This method looks into gc.log file (if -Xloggc:file is given) and returns
216 * true if the last line in the log contains the "Metadata" word.
217 * It's not very reliable way to check, log might not be flushed yet.
218 *
219 * @return
220 */
221 protected boolean isMetaspaceGC() {
222 return lastGCLogLine().contains("Metadata");
223 }
224
225 /**
226 * Prints amounts of used and committed metaspace preceeded by the message
227 * @param mesg a message to printed prior usages
228 */
229 protected void printMemoryUsage(String mesg) {
230 MemoryUsage mu = pool.getUsage();
231 printMemoryUsage(mesg, mu.getUsed(), mu.getCommitted());
232 }
233 protected void printMemoryUsage(String mesg, long v1, long v2) {
234 System.out.println(mesg + ": " + bytes2k(v1) + " : " + bytes2k(v2));
235 }
236 protected String bytes2k(long v) {
237 return (v / 1024) + "k";
238 }
239
240
241
242 /**
243 * @return amount of used memory
244 */
245 public long getUsed() {
246 return pool.getUsage().getUsed();
247 }
248
249 /**
250 * @return amount of committed memory
251 */
252 public long getCommitted() {
253 return pool.getUsage().getCommitted();
254 }
255
256 private static MemoryPoolMXBean getMemoryPool(String name) {
257 List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
258 for (MemoryPoolMXBean pool : pools) {
259 if (pool.getName().equals(name)) {
260 return pool;
261 }
262 }
263 return null;
264 }
265
266 private static long detectPageSize() {
267 try {
268 Unsafe unsafe = Unsafe.getUnsafe();
269
270 int pageSize = unsafe.pageSize();
271 System.out.println("Page size: " + pageSize);
272 return pageSize;
273 } catch (Exception e) {
274 throw new Fault("Cannot detect page size");
275 }
276 }
277
278
279 long parseValue(String s) {
280 s = s.toLowerCase();
281 int multiplier = 1;
282 switch (s.charAt(s.length() - 1)) {
283 case 'g': multiplier = 1024*1024*1024; break;
284 case 'm': multiplier = 1024*1024; break;
285 case 'k': multiplier = 1024; break;
286 }
287 if (multiplier == 1) {
288 return Long.parseLong(s);
289 } else {
290 return Long.parseLong(s.substring(0, s.length() - 1)) * multiplier;
291 }
292 }
293
294 public static interface Foo {
295 }
296
297 public static class FooBar implements Foo {
298 }
299
300 class FooInvocationHandler implements InvocationHandler {
301 private final Foo foo;
302
303 FooInvocationHandler(MetaspaceBaseGC.Foo foo) {
304 this.foo = foo;
305 }
306
307 @Override
308 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
309 return method.invoke(foo, args);
310 }
311 }
312
313 }
--- EOF ---