Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/test/hotspot/jtreg/runtime/CommandLine/OptionsValidation/common/optionsvalidation/JVMOptionsUtils.java
41161 views
1
/*
2
* Copyright (c) 2015, 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 optionsvalidation;
25
26
import java.io.BufferedReader;
27
import java.io.IOException;
28
import java.io.InputStreamReader;
29
import java.io.Reader;
30
import java.lang.management.GarbageCollectorMXBean;
31
import java.lang.management.ManagementFactory;
32
import java.math.BigDecimal;
33
import java.util.ArrayList;
34
import java.util.Arrays;
35
import java.util.List;
36
import java.util.LinkedHashMap;
37
import java.util.Map;
38
import java.util.StringTokenizer;
39
import java.util.function.Predicate;
40
import jdk.test.lib.process.OutputAnalyzer;
41
import jdk.test.lib.Platform;
42
import jdk.test.lib.process.ProcessTools;
43
44
public class JVMOptionsUtils {
45
46
/* Java option which print options with ranges */
47
private static final String PRINT_FLAGS_RANGES = "-XX:+PrintFlagsRanges";
48
49
private static final String UNLOCK_FLAG1 = "-XX:+UnlockDiagnosticVMOptions";
50
private static final String UNLOCK_FLAG2 = "-XX:+UnlockExperimentalVMOptions";
51
52
/* StringBuilder to accumulate failed message */
53
private static final StringBuilder finalFailedMessage = new StringBuilder();
54
55
/* Used to start the JVM with the same type as current */
56
static String VMType;
57
58
/* Used to start the JVM with the same GC type as current */
59
static String GCType;
60
61
private static Map<String, JVMOption> optionsAsMap;
62
63
static {
64
if (Platform.isServer()) {
65
VMType = "-server";
66
} else if (Platform.isClient()) {
67
VMType = "-client";
68
} else if (Platform.isMinimal()) {
69
VMType = "-minimal";
70
} else {
71
VMType = null;
72
}
73
74
List<GarbageCollectorMXBean> gcMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
75
76
GCType = null;
77
78
for (GarbageCollectorMXBean gcMxBean : gcMxBeans) {
79
switch (gcMxBean.getName()) {
80
case "MarkSweepCompact":
81
GCType = "-XX:+UseSerialGC";
82
break;
83
case "PS Scavenge":
84
GCType = "-XX:+UseParallelGC";
85
break;
86
case "G1 Old Generation":
87
GCType = "-XX:+UseG1GC";
88
break;
89
}
90
}
91
}
92
93
public static boolean fitsRange(String optionName, BigDecimal number) throws Exception {
94
JVMOption option;
95
String minRangeString = null;
96
String maxRangeString = null;
97
boolean fits = true;
98
99
if (optionsAsMap == null) {
100
optionsAsMap = getOptionsWithRangeAsMap();
101
}
102
103
option = optionsAsMap.get(optionName);
104
if (option != null) {
105
minRangeString = option.getMin();
106
if (minRangeString != null) {
107
fits = (number.compareTo(new BigDecimal(minRangeString)) >= 0);
108
}
109
maxRangeString = option.getMax();
110
if (maxRangeString != null) {
111
fits &= (number.compareTo(new BigDecimal(maxRangeString)) <= 0);
112
}
113
}
114
115
return fits;
116
}
117
118
public static boolean fitsRange(String optionName, String number) throws Exception {
119
String lowerCase = number.toLowerCase();
120
String multiplier = "1";
121
if (lowerCase.endsWith("k")) {
122
multiplier = "1024";
123
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
124
} else if (lowerCase.endsWith("m")) {
125
multiplier = "1048576"; //1024*1024
126
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
127
} else if (lowerCase.endsWith("g")) {
128
multiplier = "1073741824"; //1024*1024*1024
129
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
130
} else if (lowerCase.endsWith("t")) {
131
multiplier = "1099511627776"; //1024*1024*1024*1024
132
lowerCase = lowerCase.substring(0, lowerCase.length()-1);
133
}
134
BigDecimal valueBig = new BigDecimal(lowerCase);
135
BigDecimal multiplierBig = new BigDecimal(multiplier);
136
return fitsRange(optionName, valueBig.multiply(multiplierBig));
137
}
138
139
public static String getMinOptionRange(String optionName) throws Exception {
140
JVMOption option;
141
String minRange = null;
142
143
if (optionsAsMap == null) {
144
optionsAsMap = getOptionsWithRangeAsMap();
145
}
146
147
option = optionsAsMap.get(optionName);
148
if (option != null) {
149
minRange = option.getMin();
150
}
151
152
return minRange;
153
}
154
155
public static String getMaxOptionRange(String optionName) throws Exception {
156
JVMOption option;
157
String maxRange = null;
158
159
if (optionsAsMap == null) {
160
optionsAsMap = getOptionsWithRangeAsMap();
161
}
162
163
option = optionsAsMap.get(optionName);
164
if (option != null) {
165
maxRange = option.getMax();
166
}
167
168
return maxRange;
169
}
170
171
/**
172
* Add dependency for option depending on it's name. E.g. enable G1 GC for
173
* G1 options or add prepend options to not hit constraints.
174
*
175
* @param option option
176
*/
177
private static void addNameDependency(JVMOption option) {
178
String name = option.getName();
179
180
if (name.startsWith("G1")) {
181
option.addPrepend("-XX:+UseG1GC");
182
}
183
184
if (name.startsWith("NUMA")) {
185
option.addPrepend("-XX:+UseNUMA");
186
}
187
188
if (name.contains("JVMCI")) {
189
option.addPrepend("-XX:+EnableJVMCI");
190
}
191
192
switch (name) {
193
case "MinHeapFreeRatio":
194
option.addPrepend("-XX:MaxHeapFreeRatio=100");
195
break;
196
case "MaxHeapFreeRatio":
197
option.addPrepend("-XX:MinHeapFreeRatio=0");
198
break;
199
case "MinMetaspaceFreeRatio":
200
option.addPrepend("-XX:MaxMetaspaceFreeRatio=100");
201
break;
202
case "MaxMetaspaceFreeRatio":
203
option.addPrepend("-XX:MinMetaspaceFreeRatio=0");
204
break;
205
case "G1RefProcDrainInterval":
206
option.addPrepend("-XX:+ExplicitGCInvokesConcurrent");
207
break;
208
case "InitialTenuringThreshold":
209
option.addPrepend("-XX:MaxTenuringThreshold=" + option.getMax());
210
break;
211
case "NUMAInterleaveGranularity":
212
option.addPrepend("-XX:+UseNUMAInterleaving");
213
break;
214
case "VerifyGCStartAt":
215
option.addPrepend("-XX:+VerifyBeforeGC");
216
option.addPrepend("-XX:+VerifyAfterGC");
217
break;
218
case "NewSizeThreadIncrease":
219
option.addPrepend("-XX:+UseSerialGC");
220
break;
221
case "SharedBaseAddress":
222
case "SharedSymbolTableBucketSize":
223
option.addPrepend("-XX:+UnlockDiagnosticVMOptions");
224
option.addPrepend("-XX:SharedArchiveFile=TestOptionsWithRanges.jsa");
225
option.addPrepend("-Xshare:dump");
226
break;
227
case "TLABWasteIncrement":
228
option.addPrepend("-XX:+UseParallelGC");
229
break;
230
case "BootstrapJVMCI":
231
case "PrintBootstrap":
232
case "JVMCIThreads":
233
case "JVMCIHostThreads":
234
option.addPrepend("-XX:+UseJVMCICompiler");
235
break;
236
default:
237
/* Do nothing */
238
break;
239
}
240
}
241
242
/**
243
* Parse JVM Options. Get input from "inputReader". Parse using
244
* "-XX:+PrintFlagsRanges" output format.
245
*
246
* @param inputReader input data for parsing
247
* @param withRanges true if needed options with defined ranges inside JVM
248
* @param acceptOrigin predicate for option origins. Origins can be
249
* "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
250
* to true.
251
* @return map from option name to the JVMOption object
252
* @throws IOException if an error occurred while reading the data
253
*/
254
private static Map<String, JVMOption> getJVMOptions(Reader inputReader,
255
boolean withRanges, Predicate<String> acceptOrigin) throws IOException {
256
BufferedReader reader = new BufferedReader(inputReader);
257
String type;
258
String line;
259
String token;
260
String name;
261
StringTokenizer st;
262
JVMOption option;
263
Map<String, JVMOption> allOptions = new LinkedHashMap<>();
264
265
// Skip first line
266
line = reader.readLine();
267
268
while ((line = reader.readLine()) != null) {
269
/*
270
* Parse option from following line:
271
* <type> <name> [ <min, optional> ... <max, optional> ] {<origin>}
272
*/
273
st = new StringTokenizer(line);
274
275
type = st.nextToken();
276
277
name = st.nextToken();
278
279
option = JVMOption.createVMOption(type, name);
280
281
/* Skip '[' */
282
token = st.nextToken();
283
284
/* Read min range or "..." if range is absent */
285
token = st.nextToken();
286
287
if (token.equals("...") == false) {
288
if (!withRanges) {
289
/*
290
* Option have range, but asked for options without
291
* ranges => skip it
292
*/
293
continue;
294
}
295
296
/* Mark this option as option which range is defined in VM */
297
option.optionWithRange();
298
299
option.setMin(token);
300
301
/* Read "..." and skip it */
302
token = st.nextToken();
303
304
/* Get max value */
305
token = st.nextToken();
306
option.setMax(token);
307
} else if (withRanges) {
308
/*
309
* Option not have range, but asked for options with
310
* ranges => skip it
311
*/
312
continue;
313
}
314
315
/* Skip ']' */
316
token = st.nextToken();
317
318
/* Read origin of the option */
319
token = st.nextToken();
320
321
while (st.hasMoreTokens()) {
322
token += st.nextToken();
323
};
324
token = token.substring(1, token.indexOf("}"));
325
326
if (acceptOrigin.test(token)) {
327
addNameDependency(option);
328
329
allOptions.put(name, option);
330
}
331
}
332
333
return allOptions;
334
}
335
336
static void failedMessage(String optionName, String value, boolean valid, String message) {
337
String temp;
338
339
if (valid) {
340
temp = "valid";
341
} else {
342
temp = "invalid";
343
}
344
345
failedMessage(String.format("Error processing option %s with %s value '%s'! %s",
346
optionName, temp, value, message));
347
}
348
349
static void failedMessage(String message) {
350
System.err.println("TEST FAILED: " + message);
351
finalFailedMessage.append(String.format("(%s)%n", message));
352
}
353
354
static void printOutputContent(OutputAnalyzer output) {
355
System.err.println(String.format("stdout content[%s]", output.getStdout()));
356
System.err.println(String.format("stderr content[%s]%n", output.getStderr()));
357
}
358
359
/**
360
* Return string with accumulated failure messages
361
*
362
* @return string with accumulated failure messages
363
*/
364
public static String getMessageWithFailures() {
365
return finalFailedMessage.toString();
366
}
367
368
/**
369
* Run command line tests for options passed in the list
370
*
371
* @param options list of options to test
372
* @return number of failed tests
373
* @throws Exception if java process can not be started
374
*/
375
public static int runCommandLineTests(List<? extends JVMOption> options) throws Exception {
376
int failed = 0;
377
378
for (JVMOption option : options) {
379
failed += option.testCommandLine();
380
}
381
382
return failed;
383
}
384
385
/**
386
* Test passed options using DynamicVMOption isValidValue and isInvalidValue
387
* methods. Only tests writeable options.
388
*
389
* @param options list of options to test
390
* @return number of failed tests
391
*/
392
public static int runDynamicTests(List<? extends JVMOption> options) {
393
int failed = 0;
394
395
for (JVMOption option : options) {
396
failed += option.testDynamic();
397
}
398
399
return failed;
400
}
401
402
/**
403
* Test passed options using Jcmd. Only tests writeable options.
404
*
405
* @param options list of options to test
406
* @return number of failed tests
407
*/
408
public static int runJcmdTests(List<? extends JVMOption> options) {
409
int failed = 0;
410
411
for (JVMOption option : options) {
412
failed += option.testJcmd();
413
}
414
415
return failed;
416
}
417
418
/**
419
* Test passed option using attach method. Only tests writeable options.
420
*
421
* @param options list of options to test
422
* @return number of failed tests
423
* @throws Exception if an error occurred while attaching to the target JVM
424
*/
425
public static int runAttachTests(List<? extends JVMOption> options) throws Exception {
426
int failed = 0;
427
428
for (JVMOption option : options) {
429
failed += option.testAttach();
430
}
431
432
return failed;
433
}
434
435
/**
436
* Get JVM options as map. Can return options with defined ranges or options
437
* without range depending on "withRanges" argument. "acceptOrigin"
438
* predicate can be used to filter option origin.
439
*
440
* @param withRanges true if needed options with defined ranges inside JVM
441
* @param acceptOrigin predicate for option origins. Origins can be
442
* "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
443
* to true.
444
* @param additionalArgs additional arguments to the Java process which ran
445
* with "-XX:+PrintFlagsRanges"
446
* @return map from option name to the JVMOption object
447
* @throws Exception if a new process can not be created or an error
448
* occurred while reading the data
449
*/
450
private static Map<String, JVMOption> getOptionsAsMap(boolean withRanges, Predicate<String> acceptOrigin,
451
String... additionalArgs) throws Exception {
452
Map<String, JVMOption> result;
453
Process p;
454
List<String> runJava = new ArrayList<>();
455
456
if (additionalArgs.length > 0) {
457
runJava.addAll(Arrays.asList(additionalArgs));
458
}
459
460
if (VMType != null) {
461
runJava.add(VMType);
462
}
463
464
if (GCType != null) {
465
runJava.add(GCType);
466
}
467
runJava.add(UNLOCK_FLAG1);
468
runJava.add(UNLOCK_FLAG2);
469
runJava.add(PRINT_FLAGS_RANGES);
470
runJava.add("-version");
471
472
p = ProcessTools.createJavaProcessBuilder(runJava).start();
473
474
result = getJVMOptions(new InputStreamReader(p.getInputStream()), withRanges, acceptOrigin);
475
476
p.waitFor();
477
478
return result;
479
}
480
481
/**
482
* Get JVM options as list. Can return options with defined ranges or
483
* options without range depending on "withRanges" argument. "acceptOrigin"
484
* predicate can be used to filter option origin.
485
*
486
* @param withRanges true if needed options with defined ranges inside JVM
487
* @param acceptOrigin predicate for option origins. Origins can be
488
* "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
489
* to true.
490
* @param additionalArgs additional arguments to the Java process which ran
491
* with "-XX:+PrintFlagsRanges"
492
* @return List of options
493
* @throws Exception if a new process can not be created or an error
494
* occurred while reading the data
495
*/
496
public static List<JVMOption> getOptions(boolean withRanges, Predicate<String> acceptOrigin,
497
String... additionalArgs) throws Exception {
498
return new ArrayList<>(getOptionsAsMap(withRanges, acceptOrigin, additionalArgs).values());
499
}
500
501
/**
502
* Get JVM options with ranges as list. "acceptOrigin" predicate can be used
503
* to filter option origin.
504
*
505
* @param acceptOrigin predicate for option origins. Origins can be
506
* "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
507
* to true.
508
* @param additionalArgs additional arguments to the Java process which ran
509
* with "-XX:+PrintFlagsRanges"
510
* @return List of options
511
* @throws Exception if a new process can not be created or an error
512
* occurred while reading the data
513
*/
514
public static List<JVMOption> getOptionsWithRange(Predicate<String> acceptOrigin, String... additionalArgs) throws Exception {
515
return getOptions(true, acceptOrigin, additionalArgs);
516
}
517
518
/**
519
* Get JVM options with ranges as list.
520
*
521
* @param additionalArgs additional arguments to the Java process which ran
522
* with "-XX:+PrintFlagsRanges"
523
* @return list of options
524
* @throws Exception if a new process can not be created or an error
525
* occurred while reading the data
526
*/
527
public static List<JVMOption> getOptionsWithRange(String... additionalArgs) throws Exception {
528
return getOptionsWithRange(origin -> true, additionalArgs);
529
}
530
531
/**
532
* Get JVM options with range as map. "acceptOrigin" predicate can be used
533
* to filter option origin.
534
*
535
* @param acceptOrigin predicate for option origins. Origins can be
536
* "product", "diagnostic" etc. Accept option only if acceptOrigin evaluates
537
* to true.
538
* @param additionalArgs additional arguments to the Java process which ran
539
* with "-XX:+PrintFlagsRanges"
540
* @return Map from option name to the JVMOption object
541
* @throws Exception if a new process can not be created or an error
542
* occurred while reading the data
543
*/
544
public static Map<String, JVMOption> getOptionsWithRangeAsMap(Predicate<String> acceptOrigin, String... additionalArgs) throws Exception {
545
return getOptionsAsMap(true, acceptOrigin, additionalArgs);
546
}
547
548
/**
549
* Get JVM options with range as map
550
*
551
* @param additionalArgs additional arguments to the Java process which ran
552
* with "-XX:+PrintFlagsRanges"
553
* @return map from option name to the JVMOption object
554
* @throws Exception if a new process can not be created or an error
555
* occurred while reading the data
556
*/
557
public static Map<String, JVMOption> getOptionsWithRangeAsMap(String... additionalArgs) throws Exception {
558
return getOptionsWithRangeAsMap(origin -> true, additionalArgs);
559
}
560
}
561
562