Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/openjdk-multiarch-jdk8u
Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/test/gc/g1/TestStringDeduplicationTools.java
32284 views
1
/*
2
* Copyright (c) 2014, 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
/*
25
* Common code for string deduplication tests
26
*/
27
28
import java.lang.management.*;
29
import java.lang.reflect.*;
30
import java.security.*;
31
import java.util.*;
32
import com.oracle.java.testlibrary.*;
33
import sun.misc.*;
34
35
class TestStringDeduplicationTools {
36
private static final String YoungGC = "YoungGC";
37
private static final String FullGC = "FullGC";
38
39
private static final int Xmn = 50; // MB
40
private static final int Xms = 100; // MB
41
private static final int Xmx = 100; // MB
42
private static final int MB = 1024 * 1024;
43
private static final int StringLength = 50;
44
45
private static Field valueField;
46
private static Unsafe unsafe;
47
private static byte[] dummy;
48
49
static {
50
try {
51
Field field = Unsafe.class.getDeclaredField("theUnsafe");
52
field.setAccessible(true);
53
unsafe = (Unsafe)field.get(null);
54
55
valueField = String.class.getDeclaredField("value");
56
valueField.setAccessible(true);
57
} catch (Exception e) {
58
throw new RuntimeException(e);
59
}
60
}
61
62
private static Object getValue(String string) {
63
try {
64
return valueField.get(string);
65
} catch (Exception e) {
66
throw new RuntimeException(e);
67
}
68
}
69
70
private static void doFullGc(int numberOfTimes) {
71
for (int i = 0; i < numberOfTimes; i++) {
72
System.out.println("Begin: Full GC " + (i + 1) + "/" + numberOfTimes);
73
System.gc();
74
System.out.println("End: Full GC " + (i + 1) + "/" + numberOfTimes);
75
}
76
}
77
78
private static void doYoungGc(int numberOfTimes) {
79
// Provoke at least numberOfTimes young GCs
80
final int objectSize = 128;
81
final int maxObjectInYoung = (Xmn * MB) / objectSize;
82
for (int i = 0; i < numberOfTimes; i++) {
83
System.out.println("Begin: Young GC " + (i + 1) + "/" + numberOfTimes);
84
for (int j = 0; j < maxObjectInYoung + 1; j++) {
85
dummy = new byte[objectSize];
86
}
87
System.out.println("End: Young GC " + (i + 1) + "/" + numberOfTimes);
88
}
89
}
90
91
private static void forceDeduplication(int ageThreshold, String gcType) {
92
// Force deduplication to happen by either causing a FullGC or a YoungGC.
93
// We do several collections to also provoke a situation where the the
94
// deduplication thread needs to yield while processing the queue. This
95
// also tests that the references in the deduplication queue are adjusted
96
// accordingly.
97
if (gcType.equals(FullGC)) {
98
doFullGc(3);
99
} else {
100
doYoungGc(ageThreshold + 3);
101
}
102
}
103
104
private static String generateString(int id) {
105
StringBuilder builder = new StringBuilder(StringLength);
106
107
builder.append("DeduplicationTestString:" + id + ":");
108
109
while (builder.length() < StringLength) {
110
builder.append('X');
111
}
112
113
return builder.toString();
114
}
115
116
private static ArrayList<String> createStrings(int total, int unique) {
117
System.out.println("Creating strings: total=" + total + ", unique=" + unique);
118
if (total % unique != 0) {
119
throw new RuntimeException("Total must be divisible by unique");
120
}
121
122
ArrayList<String> list = new ArrayList<String>(total);
123
for (int j = 0; j < total / unique; j++) {
124
for (int i = 0; i < unique; i++) {
125
list.add(generateString(i));
126
}
127
}
128
129
return list;
130
}
131
132
private static void verifyStrings(ArrayList<String> list, int uniqueExpected) {
133
for (;;) {
134
// Check number of deduplicated strings
135
ArrayList<Object> unique = new ArrayList<Object>(uniqueExpected);
136
for (String string: list) {
137
Object value = getValue(string);
138
boolean uniqueValue = true;
139
for (Object obj: unique) {
140
if (obj == value) {
141
uniqueValue = false;
142
break;
143
}
144
}
145
146
if (uniqueValue) {
147
unique.add(value);
148
}
149
}
150
151
System.out.println("Verifying strings: total=" + list.size() +
152
", uniqueFound=" + unique.size() +
153
", uniqueExpected=" + uniqueExpected);
154
155
if (unique.size() == uniqueExpected) {
156
System.out.println("Deduplication completed");
157
break;
158
} else {
159
System.out.println("Deduplication not completed, waiting...");
160
161
// Give the deduplication thread time to complete
162
try {
163
Thread.sleep(1000);
164
} catch (Exception e) {
165
throw new RuntimeException(e);
166
}
167
}
168
}
169
}
170
171
private static OutputAnalyzer runTest(String... extraArgs) throws Exception {
172
String[] defaultArgs = new String[] {
173
"-Xmn" + Xmn + "m",
174
"-Xms" + Xms + "m",
175
"-Xmx" + Xmx + "m",
176
"-XX:+UseG1GC",
177
"-XX:+UnlockDiagnosticVMOptions",
178
"-XX:+VerifyAfterGC" // Always verify after GC
179
};
180
181
ArrayList<String> args = new ArrayList<String>();
182
args.addAll(Arrays.asList(defaultArgs));
183
args.addAll(Arrays.asList(extraArgs));
184
185
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(args.toArray(new String[args.size()]));
186
OutputAnalyzer output = new OutputAnalyzer(pb.start());
187
System.err.println(output.getStderr());
188
System.out.println(output.getStdout());
189
return output;
190
}
191
192
private static class DeduplicationTest {
193
public static void main(String[] args) {
194
System.out.println("Begin: DeduplicationTest");
195
196
final int numberOfStrings = Integer.parseUnsignedInt(args[0]);
197
final int numberOfUniqueStrings = Integer.parseUnsignedInt(args[1]);
198
final int ageThreshold = Integer.parseUnsignedInt(args[2]);
199
final String gcType = args[3];
200
201
ArrayList<String> list = createStrings(numberOfStrings, numberOfUniqueStrings);
202
forceDeduplication(ageThreshold, gcType);
203
verifyStrings(list, numberOfUniqueStrings);
204
205
System.out.println("End: DeduplicationTest");
206
}
207
208
public static OutputAnalyzer run(int numberOfStrings, int ageThreshold, String gcType, String... extraArgs) throws Exception {
209
String[] defaultArgs = new String[] {
210
"-XX:+UseStringDeduplication",
211
"-XX:StringDeduplicationAgeThreshold=" + ageThreshold,
212
DeduplicationTest.class.getName(),
213
"" + numberOfStrings,
214
"" + numberOfStrings / 2,
215
"" + ageThreshold,
216
gcType
217
};
218
219
ArrayList<String> args = new ArrayList<String>();
220
args.addAll(Arrays.asList(extraArgs));
221
args.addAll(Arrays.asList(defaultArgs));
222
223
return runTest(args.toArray(new String[args.size()]));
224
}
225
}
226
227
private static class InternedTest {
228
public static void main(String[] args) {
229
// This test verifies that interned strings are always
230
// deduplicated when being interned, and never after
231
// being interned.
232
233
System.out.println("Begin: InternedTest");
234
235
final int ageThreshold = Integer.parseUnsignedInt(args[0]);
236
final String baseString = "DeduplicationTestString:" + InternedTest.class.getName();
237
238
// Create duplicate of baseString
239
StringBuilder sb1 = new StringBuilder(baseString);
240
String dupString1 = sb1.toString();
241
if (getValue(dupString1) == getValue(baseString)) {
242
throw new RuntimeException("Values should not match");
243
}
244
245
// Force baseString to be inspected for deduplication
246
// and be inserted into the deduplication hashtable.
247
forceDeduplication(ageThreshold, FullGC);
248
249
// Wait for deduplication to occur
250
while (getValue(dupString1) != getValue(baseString)) {
251
System.out.println("Waiting...");
252
try {
253
Thread.sleep(100);
254
} catch (Exception e) {
255
throw new RuntimeException(e);
256
}
257
}
258
259
// Create a new duplicate of baseString
260
StringBuilder sb2 = new StringBuilder(baseString);
261
String dupString2 = sb2.toString();
262
if (getValue(dupString2) == getValue(baseString)) {
263
throw new RuntimeException("Values should not match");
264
}
265
266
// Intern the new duplicate
267
Object beforeInternedValue = getValue(dupString2);
268
String internedString = dupString2.intern();
269
if (internedString != dupString2) {
270
throw new RuntimeException("String should match");
271
}
272
if (getValue(internedString) != getValue(baseString)) {
273
throw new RuntimeException("Values should match");
274
}
275
276
// Check original value of interned string, to make sure
277
// deduplication happened on the interned string and not
278
// on the base string
279
if (beforeInternedValue == getValue(baseString)) {
280
throw new RuntimeException("Values should not match");
281
}
282
283
System.out.println("End: InternedTest");
284
}
285
286
public static OutputAnalyzer run() throws Exception {
287
return runTest("-XX:+PrintGC",
288
"-XX:+PrintGCDetails",
289
"-XX:+UseStringDeduplication",
290
"-XX:+PrintStringDeduplicationStatistics",
291
"-XX:StringDeduplicationAgeThreshold=" + DefaultAgeThreshold,
292
InternedTest.class.getName(),
293
"" + DefaultAgeThreshold);
294
}
295
}
296
297
/*
298
* Tests
299
*/
300
301
private static final int LargeNumberOfStrings = 10000;
302
private static final int SmallNumberOfStrings = 10;
303
304
private static final int MaxAgeThreshold = 15;
305
private static final int DefaultAgeThreshold = 3;
306
private static final int MinAgeThreshold = 1;
307
308
private static final int TooLowAgeThreshold = MinAgeThreshold - 1;
309
private static final int TooHighAgeThreshold = MaxAgeThreshold + 1;
310
311
public static void testYoungGC() throws Exception {
312
// Do young GC to age strings to provoke deduplication
313
OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
314
DefaultAgeThreshold,
315
YoungGC,
316
"-XX:+PrintGC",
317
"-XX:+PrintStringDeduplicationStatistics");
318
output.shouldNotContain("Full GC");
319
output.shouldContain("GC pause (G1 Evacuation Pause) (young)");
320
output.shouldContain("GC concurrent-string-deduplication");
321
output.shouldContain("Deduplicated:");
322
output.shouldHaveExitValue(0);
323
}
324
325
public static void testFullGC() throws Exception {
326
// Do full GC to age strings to provoke deduplication
327
OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
328
DefaultAgeThreshold,
329
FullGC,
330
"-XX:+PrintGC",
331
"-XX:+PrintStringDeduplicationStatistics");
332
output.shouldNotContain("GC pause (G1 Evacuation Pause) (young)");
333
output.shouldContain("Full GC");
334
output.shouldContain("GC concurrent-string-deduplication");
335
output.shouldContain("Deduplicated:");
336
output.shouldHaveExitValue(0);
337
}
338
339
public static void testTableResize() throws Exception {
340
// Test with StringDeduplicationResizeALot
341
OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
342
DefaultAgeThreshold,
343
YoungGC,
344
"-XX:+PrintGC",
345
"-XX:+PrintStringDeduplicationStatistics",
346
"-XX:+StringDeduplicationResizeALot");
347
output.shouldContain("GC concurrent-string-deduplication");
348
output.shouldContain("Deduplicated:");
349
output.shouldNotContain("Resize Count: 0");
350
output.shouldHaveExitValue(0);
351
}
352
353
public static void testTableRehash() throws Exception {
354
// Test with StringDeduplicationRehashALot
355
OutputAnalyzer output = DeduplicationTest.run(LargeNumberOfStrings,
356
DefaultAgeThreshold,
357
YoungGC,
358
"-XX:+PrintGC",
359
"-XX:+PrintStringDeduplicationStatistics",
360
"-XX:+StringDeduplicationRehashALot");
361
output.shouldContain("GC concurrent-string-deduplication");
362
output.shouldContain("Deduplicated:");
363
output.shouldNotContain("Rehash Count: 0");
364
output.shouldNotContain("Hash Seed: 0x0");
365
output.shouldHaveExitValue(0);
366
}
367
368
public static void testAgeThreshold() throws Exception {
369
OutputAnalyzer output;
370
371
// Test with max age theshold
372
output = DeduplicationTest.run(SmallNumberOfStrings,
373
MaxAgeThreshold,
374
YoungGC,
375
"-XX:+PrintGC",
376
"-XX:+PrintStringDeduplicationStatistics");
377
output.shouldContain("GC concurrent-string-deduplication");
378
output.shouldContain("Deduplicated:");
379
output.shouldHaveExitValue(0);
380
381
// Test with min age theshold
382
output = DeduplicationTest.run(SmallNumberOfStrings,
383
MinAgeThreshold,
384
YoungGC,
385
"-XX:+PrintGC",
386
"-XX:+PrintStringDeduplicationStatistics");
387
output.shouldContain("GC concurrent-string-deduplication");
388
output.shouldContain("Deduplicated:");
389
output.shouldHaveExitValue(0);
390
391
// Test with too low age threshold
392
output = DeduplicationTest.run(SmallNumberOfStrings,
393
TooLowAgeThreshold,
394
YoungGC);
395
output.shouldContain("StringDeduplicationAgeThreshold of " + TooLowAgeThreshold +
396
" is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
397
output.shouldHaveExitValue(1);
398
399
// Test with too high age threshold
400
output = DeduplicationTest.run(SmallNumberOfStrings,
401
TooHighAgeThreshold,
402
YoungGC);
403
output.shouldContain("StringDeduplicationAgeThreshold of " + TooHighAgeThreshold +
404
" is invalid; must be between " + MinAgeThreshold + " and " + MaxAgeThreshold);
405
output.shouldHaveExitValue(1);
406
}
407
408
public static void testPrintOptions() throws Exception {
409
OutputAnalyzer output;
410
411
// Test without PrintGC and without PrintStringDeduplicationStatistics
412
output = DeduplicationTest.run(SmallNumberOfStrings,
413
DefaultAgeThreshold,
414
YoungGC);
415
output.shouldNotContain("GC concurrent-string-deduplication");
416
output.shouldNotContain("Deduplicated:");
417
output.shouldHaveExitValue(0);
418
419
// Test with PrintGC but without PrintStringDeduplicationStatistics
420
output = DeduplicationTest.run(SmallNumberOfStrings,
421
DefaultAgeThreshold,
422
YoungGC,
423
"-XX:+PrintGC");
424
output.shouldContain("GC concurrent-string-deduplication");
425
output.shouldNotContain("Deduplicated:");
426
output.shouldHaveExitValue(0);
427
}
428
429
public static void testInterned() throws Exception {
430
// Test that interned strings are deduplicated before being interned
431
OutputAnalyzer output = InternedTest.run();
432
output.shouldHaveExitValue(0);
433
}
434
}
435
436