Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/gc/gp/GarbageUtils.java
41162 views
1
/*
2
* Copyright (c) 2007, 2019, 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 nsk.share.gc.gp;
25
26
import java.io.IOException;
27
import java.io.PrintWriter;
28
import java.io.StringWriter;
29
import java.lang.invoke.*;
30
import java.util.*;
31
import nsk.share.gc.gp.array.*;
32
import nsk.share.gc.gp.string.*;
33
import nsk.share.gc.gp.list.*;
34
import nsk.share.gc.gp.tree.*;
35
import nsk.share.gc.gp.misc.*;
36
import nsk.share.gc.gp.classload.*;
37
import nsk.share.gc.Memory;
38
import nsk.share.TestBug;
39
import nsk.share.test.*;
40
41
/**
42
* Utility methods for garbage producers.
43
*/
44
public final class GarbageUtils {
45
private static final int ALLOCATION_LIMIT = 50000000; //50 Mb
46
private static GarbageProducers garbageProducers;
47
private static List<GarbageProducer> primitiveArrayProducers;
48
private static List<GarbageProducer> arrayProducers;
49
private static final GarbageProducer byteArrayProducer = new ByteArrayProducer();
50
public static enum OOM_TYPE {
51
ANY (),
52
HEAP("Java heap space"),
53
METASPACE("Metaspace", "Compressed class space");
54
55
private final String[] expectedStrings;
56
OOM_TYPE(String... expectedStrings) {
57
this.expectedStrings = expectedStrings;
58
}
59
60
/**
61
* Returns true if the given error message matches
62
* one of expected strings.
63
*/
64
public boolean accept(String errorMessage) {
65
if (expectedStrings == null || expectedStrings.length == 0 || errorMessage == null) {
66
return true;
67
}
68
for (String s: expectedStrings) {
69
if (errorMessage.indexOf(s) != -1) {
70
return true;
71
}
72
}
73
return false;
74
}
75
};
76
77
// Force loading of OOM_TYPE and calling of enum constructors when loading GarbageUtils class.
78
public static final Object[] thisIsGarbageArray_theOnlyPurposeForCreatingItAndDeclaringItPublicIsToInitializeIntancesOfOOMEnumberation = new Object[] { OOM_TYPE.ANY, OOM_TYPE.HEAP, OOM_TYPE.METASPACE };
79
80
// Force early loading of classes that might otherwise unexpectedly fail
81
// class loading during testing due to high memory pressure.
82
public static final StringWriter preloadStringWriter = new StringWriter(1);
83
public static final PrintWriter preloadPrintWriter = new PrintWriter(preloadStringWriter);
84
public static final Throwable preloadThrowable = new Throwable("preload");
85
86
private GarbageUtils() {
87
}
88
89
/**
90
* Eat memory using execution controller that waits for 2 minutes.
91
* @return number of OOME occured
92
*/
93
public static int eatMemory() {
94
return eatMemory(2 * 60 * 1000);
95
}
96
97
/**
98
* Eat memory using execution controller that waits for timeout.
99
* @return number of OOME occured
100
*/
101
public static int eatMemory(final long timeout) {
102
return eatMemory(new ExecutionController() {
103
final long initialTime = System.currentTimeMillis();
104
105
@Override
106
public void start(long stdIterations) {}
107
108
@Override
109
public boolean iteration() {return false;}
110
111
@Override
112
public boolean continueExecution() {
113
return System.currentTimeMillis() - initialTime < timeout;
114
}
115
116
@Override
117
public long getIteration() {return 0;}
118
119
@Override
120
public void finish() {}
121
});
122
}
123
124
125
/**
126
* Eat memory using given execution controller and garbage producer.
127
*
128
* @param stresser execution controller
129
* @param gp garbage producer
130
* @return number of OOME occured
131
*/
132
public static int eatMemory(ExecutionController stresser) {
133
return eatMemory(stresser, byteArrayProducer, 50, 100, 2, OOM_TYPE.ANY);
134
}
135
136
/**
137
* Eat memory using given execution controller and garbage producer.
138
*
139
* @param stresser execution controller
140
* @param gp garbage producer
141
* @return number of OOME occured
142
*/
143
public static int eatMemory(ExecutionController stresser, GarbageProducer gp) {
144
return eatMemory(stresser, gp, 50, 100, 2, OOM_TYPE.ANY);
145
}
146
147
/**
148
* Eat memory using given garbage producer and given factor.
149
*
150
* @param gp garbage producer
151
* @param factor factor to divide the array size by
152
* @return number of OOME occured
153
*/
154
public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long factor) {
155
return eatMemory(stresser, gp, 50, 100, factor, OOM_TYPE.ANY);
156
}
157
158
/**
159
* Eat memory using default(byte[]) garbage producer.
160
*
161
* Note that this method can throw Failure if any exception
162
* is thrown while eating memory. To avoid OOM while allocating
163
* exception we preallocate it before the lunch starts. It means
164
* that exception stack trace does not correspond to the place
165
* where exception is thrown, but points at start of the method.
166
*
167
* @param stresser stresser
168
* @param initialFactor determines which portion of initial memory initial chunk will be
169
* @param minMemoryChunk determines when to stop
170
* @param factor factor to divide the array size by
171
* @return number of OOME occured
172
*/
173
public static int eatMemory(ExecutionController stresser,long initialFactor, long minMemoryChunk, long factor) {
174
return eatMemory(stresser, byteArrayProducer, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);
175
}
176
177
/**
178
* Eat memory using given garbage producer.
179
*
180
* Note that this method can throw Failure if any exception
181
* is thrown while eating memory. To avoid OOM while allocating
182
* exception we preallocate it before the lunch starts. It means
183
* that exception stack trace does not correspond to the place
184
* where exception is thrown, but points at start of the method.
185
*
186
* @param stresser stresser to use
187
* @param gp garbage producer
188
* @param initialFactor determines which portion of initial memory initial chunk will be
189
* @param minMemoryChunk determines when to stop
190
* @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME
191
* @param type of OutOfMemory Exception: Java heap space or Metadata space
192
* @return number of OOME occured
193
*/
194
public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor) {
195
return eatMemory(stresser, gp, initialFactor, minMemoryChunk, factor, OOM_TYPE.ANY);
196
}
197
198
static int numberOfOOMEs = 0;
199
200
/**
201
* Minimal wrapper of the main implementation. Catches any OOM
202
* that might be thrown when rematerializing Objects when deoptimizing.
203
*
204
* It is Important that the impl is not inlined.
205
*/
206
207
public static int eatMemory(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) {
208
try {
209
// Using a methodhandle invoke of eatMemoryImpl to prevent inlining of it
210
MethodHandles.Lookup lookup = MethodHandles.lookup();
211
MethodType mt = MethodType.methodType(
212
int.class,
213
ExecutionController.class,
214
GarbageProducer.class,
215
long.class,
216
long.class,
217
long.class,
218
OOM_TYPE.class);
219
MethodHandle eat = lookup.findStatic(GarbageUtils.class, "eatMemoryImpl", mt);
220
return (int) eat.invoke(stresser, gp, initialFactor, minMemoryChunk, factor, type);
221
} catch (OutOfMemoryError e) {
222
return numberOfOOMEs++;
223
} catch (Throwable t) {
224
throw new RuntimeException(t);
225
}
226
}
227
228
/**
229
* Eat memory using given garbage producer.
230
*
231
* Note that this method can throw Failure if any exception
232
* is thrown while eating memory. To avoid OOM while allocating
233
* exception we preallocate it before the lunch starts. It means
234
* that exception stack trace does not correspond to the place
235
* where exception is thrown, but points at start of the method.
236
*
237
* @param stresser stresser to use
238
* @param gp garbage producer
239
* @param initialFactor determines which portion of initial memory initial chunk will be
240
* @param minMemoryChunk determines when to stop
241
* @param factor factor to divide the array size by. A value of 0 means that method returns after first OOME
242
* @param type of OutOfMemory Exception: Java heap space or Metadata space
243
* @return number of OOME occured
244
*/
245
246
public static int eatMemoryImpl(ExecutionController stresser, GarbageProducer gp, long initialFactor, long minMemoryChunk, long factor, OOM_TYPE type) {
247
numberOfOOMEs = 0;
248
try {
249
byte[] someMemory = new byte[200000]; //200 Kb
250
try {
251
Runtime runtime = Runtime.getRuntime();
252
long maxMemory = runtime.maxMemory();
253
long maxMemoryChunk = maxMemory / initialFactor;
254
long chunk = maxMemoryChunk;
255
chunk = chunk > ALLOCATION_LIMIT ? ALLOCATION_LIMIT : chunk;
256
int allocations = 0;
257
List<Object> storage = new ArrayList<Object>();
258
259
while (chunk > minMemoryChunk && stresser.continueExecution()) {
260
try {
261
storage.add(gp.create(chunk));
262
if (Thread.currentThread().isInterrupted()) {
263
return numberOfOOMEs;
264
}
265
// if we are able to eat chunk*factor let
266
// try to increase size of chunk
267
if (chunk * factor < maxMemoryChunk
268
&& factor != 0 && allocations++ == factor + 1) {
269
chunk = chunk * factor;
270
allocations = 0;
271
}
272
} catch (OutOfMemoryError e) {
273
someMemory = null;
274
if (type != OOM_TYPE.ANY) {
275
if (type.accept(e.toString())) {
276
numberOfOOMEs++;
277
} else {
278
// Trying to catch situation when Java generates OOM different type that test trying to catch
279
throw new TestBug("Test throw OOM of unexpected type." + e.toString());
280
}
281
} else {
282
numberOfOOMEs++;
283
}
284
allocations = 0;
285
if (factor == 0) {
286
return numberOfOOMEs;
287
} else {
288
chunk = chunk / factor;
289
}
290
}
291
}
292
} catch (OutOfMemoryError e) {
293
someMemory = null;
294
if (type != OOM_TYPE.ANY) {
295
if (type.accept(e.toString())) {
296
numberOfOOMEs++;
297
} else {
298
// Trying to catch situation when Java generates OOM different type that test trying to catch
299
throw new TestBug("Test throw OOM of unexpected type." + e.toString());
300
}
301
} else {
302
numberOfOOMEs++;
303
}
304
// all memory is eaten now even before we start, just return
305
}
306
} catch (OutOfMemoryError e) {
307
numberOfOOMEs++;
308
}
309
return numberOfOOMEs;
310
}
311
312
/**
313
* Get all primitive array producers.
314
*/
315
public static List<GarbageProducer> getPrimitiveArrayProducers() {
316
return getGarbageProducers().getPrimitiveArrayProducers();
317
}
318
319
/**
320
* Get all array producers.
321
*/
322
public static List<GarbageProducer> getArrayProducers() {
323
return getGarbageProducers().getArrayProducers();
324
}
325
326
/**
327
* Determine size of each object in array which will occupy given
328
* memory with distribution determined by given memory strategy.
329
*/
330
public static long getArraySize(long memory, MemoryStrategy memoryStrategy) {
331
return memoryStrategy.getSize(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());
332
}
333
334
/**
335
* Determine object count in array which will occupy given
336
* memory with distribution determined by given memory strategy.
337
*/
338
public static int getArrayCount(long memory, MemoryStrategy memoryStrategy) {
339
return memoryStrategy.getCount(memory - Memory.getArrayExtraSize(), Memory.getReferenceSize());
340
}
341
342
/**
343
* Get garbage producer by identifier.
344
*
345
* @param id identifier
346
* @return garbage producer for this identifier
347
*/
348
public static GarbageProducer getGarbageProducer(String id) {
349
if (id == null || id.equals("byteArr"))
350
return new ByteArrayProducer();
351
else if (id.equals("booleanArr"))
352
return new BooleanArrayProducer();
353
else if (id.equals("shortArr"))
354
return new ShortArrayProducer();
355
else if (id.equals("charArr"))
356
return new CharArrayProducer();
357
else if (id.equals("intArr"))
358
return new IntArrayProducer();
359
else if (id.equals("longArr"))
360
return new LongArrayProducer();
361
else if (id.equals("floatArr"))
362
return new FloatArrayProducer();
363
else if (id.equals("doubleArr"))
364
return new DoubleArrayProducer();
365
else if (id.equals("objectArr"))
366
return new ObjectArrayProducer();
367
else if (id.equals("randomString"))
368
return new RandomStringProducer();
369
else if (id.equals("simpleString"))
370
return new SimpleStringProducer();
371
else if (id.startsWith("interned("))
372
return new InternedStringProducer(getGarbageProducer(getInBrackets(id)));
373
else if (id.startsWith("linearList("))
374
return new LinearListProducer(MemoryStrategy.fromString(getInBrackets(id)));
375
else if (id.startsWith("circularList("))
376
return new CircularListProducer(MemoryStrategy.fromString(getInBrackets(id)));
377
else if (id.startsWith("nonbranchyTree("))
378
return new NonbranchyTreeProducer(MemoryStrategy.fromString(getInBrackets(id)));
379
else if (id.equals("class"))
380
return new GeneratedClassProducer();
381
else if (id.startsWith("hashed("))
382
return new HashedGarbageProducer(getGarbageProducer(getInBrackets(id)));
383
else if (id.startsWith("random("))
384
return new RandomProducer(getGarbageProducerList(getInBrackets(id)));
385
else if (id.startsWith("twofields("))
386
return new TwoFieldsObjectProducer(getGarbageProducer(getInBrackets(id)));
387
else if (id.startsWith("arrayof("))
388
return new ArrayOfProducer(getGarbageProducer(getInBrackets(id)));
389
else if (id.startsWith("trace("))
390
return new TraceProducer(getGarbageProducer(getInBrackets(id)));
391
else
392
throw new TestBug("Invalid garbage producer identifier: " + id);
393
}
394
395
private static String getInBrackets(String s) {
396
int n1 = s.indexOf('(');
397
if (n1 == -1)
398
throw new TestBug("Opening bracket not found: " + s);
399
int n2 = s.lastIndexOf(')');
400
if (n2 == -1)
401
throw new TestBug("Closing bracket not found: " + s);
402
return s.substring(n1 + 1, n2);
403
}
404
405
private static List<GarbageProducer> getGarbageProducerList(String s) {
406
if (s.equals("primitiveArrays"))
407
return getPrimitiveArrayProducers();
408
else if (s.equals("arrays"))
409
return getArrayProducers();
410
else {
411
String[] ids = s.split(",");
412
List<GarbageProducer> garbageProducers = new ArrayList<GarbageProducer>(ids.length);
413
for (int i = 0; i < ids.length; ++i)
414
garbageProducers.add(getGarbageProducer(ids[i]));
415
return garbageProducers;
416
//throw new TestBug("Invalid id for list of garbage producers: " + id);
417
}
418
}
419
420
public static GarbageProducers getGarbageProducers() {
421
if (garbageProducers == null)
422
garbageProducers = new GarbageProducers();
423
return garbageProducers;
424
}
425
}
426
427