|
@@ -53,25 +53,62 @@ final class JvmErgonomics {
|
|
|
*/
|
|
|
static List<String> choose(final List<String> userDefinedJvmOptions) throws InterruptedException, IOException {
|
|
|
final List<String> ergonomicChoices = new ArrayList<>();
|
|
|
- final Map<String, Optional<String>> finalJvmOptions = finalJvmOptions(userDefinedJvmOptions);
|
|
|
+ final Map<String, JvmOption> finalJvmOptions = finalJvmOptions(userDefinedJvmOptions);
|
|
|
final long heapSize = extractHeapSize(finalJvmOptions);
|
|
|
final long maxDirectMemorySize = extractMaxDirectMemorySize(finalJvmOptions);
|
|
|
if (maxDirectMemorySize == 0) {
|
|
|
ergonomicChoices.add("-XX:MaxDirectMemorySize=" + heapSize / 2);
|
|
|
}
|
|
|
+
|
|
|
+ final boolean tuneG1GCForSmallHeap = tuneG1GCForSmallHeap(heapSize);
|
|
|
+ final boolean tuneG1GCHeapRegion = tuneG1GCHeapRegion(finalJvmOptions, tuneG1GCForSmallHeap);
|
|
|
+ final boolean tuneG1GCInitiatingHeapOccupancyPercent = tuneG1GCInitiatingHeapOccupancyPercent(finalJvmOptions);
|
|
|
+ final int tuneG1GCReservePercent = tuneG1GCReservePercent(finalJvmOptions, tuneG1GCForSmallHeap);
|
|
|
+
|
|
|
+ if (tuneG1GCHeapRegion) {
|
|
|
+ ergonomicChoices.add("-XX:G1HeapRegionSize=4m");
|
|
|
+ }
|
|
|
+ if (tuneG1GCInitiatingHeapOccupancyPercent) {
|
|
|
+ ergonomicChoices.add("-XX:InitiatingHeapOccupancyPercent=30");
|
|
|
+ }
|
|
|
+ if (tuneG1GCReservePercent != 0) {
|
|
|
+ ergonomicChoices.add("-XX:G1ReservePercent=" + tuneG1GCReservePercent);
|
|
|
+ }
|
|
|
+
|
|
|
return ergonomicChoices;
|
|
|
}
|
|
|
|
|
|
private static final Pattern OPTION = Pattern.compile(
|
|
|
- "^\\s*\\S+\\s+(?<flag>\\S+)\\s+:?=\\s+(?<value>\\S+)?\\s+\\{[^}]+?\\}\\s+\\{[^}]+}"
|
|
|
+ "^\\s*\\S+\\s+(?<flag>\\S+)\\s+:?=\\s+(?<value>\\S+)?\\s+\\{[^}]+?\\}\\s+\\{(?<origin>[^}]+)}"
|
|
|
);
|
|
|
|
|
|
- static Map<String, Optional<String>> finalJvmOptions(final List<String> userDefinedJvmOptions) throws InterruptedException,
|
|
|
- IOException {
|
|
|
+ private static class JvmOption {
|
|
|
+ private final String value;
|
|
|
+ private final String origin;
|
|
|
+
|
|
|
+ JvmOption(String value, String origin) {
|
|
|
+ this.value = value;
|
|
|
+ this.origin = origin;
|
|
|
+ }
|
|
|
+
|
|
|
+ public Optional<String> getValue() {
|
|
|
+ return Optional.ofNullable(value);
|
|
|
+ }
|
|
|
+
|
|
|
+ public String getMandatoryValue() {
|
|
|
+ return value;
|
|
|
+ }
|
|
|
+
|
|
|
+ public boolean isCommandLineOrigin() {
|
|
|
+ return "command line".equals(this.origin);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ static Map<String, JvmOption> finalJvmOptions(final List<String> userDefinedJvmOptions) throws InterruptedException, IOException {
|
|
|
return flagsFinal(userDefinedJvmOptions).stream()
|
|
|
.map(OPTION::matcher)
|
|
|
.filter(Matcher::matches)
|
|
|
- .collect(Collectors.toUnmodifiableMap(m -> m.group("flag"), m -> Optional.ofNullable(m.group("value"))));
|
|
|
+ .collect(Collectors.toUnmodifiableMap(m -> m.group("flag"), m -> new JvmOption(m.group("value"), m.group("origin"))));
|
|
|
}
|
|
|
|
|
|
private static List<String> flagsFinal(final List<String> userDefinedJvmOptions) throws InterruptedException, IOException {
|
|
@@ -116,12 +153,42 @@ final class JvmErgonomics {
|
|
|
}
|
|
|
|
|
|
// package private for testing
|
|
|
- static Long extractHeapSize(final Map<String, Optional<String>> finalJvmOptions) {
|
|
|
- return Long.parseLong(finalJvmOptions.get("MaxHeapSize").get());
|
|
|
+ static Long extractHeapSize(final Map<String, JvmOption> finalJvmOptions) {
|
|
|
+ return Long.parseLong(finalJvmOptions.get("MaxHeapSize").getMandatoryValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ static long extractMaxDirectMemorySize(final Map<String, JvmOption> finalJvmOptions) {
|
|
|
+ return Long.parseLong(finalJvmOptions.get("MaxDirectMemorySize").getMandatoryValue());
|
|
|
+ }
|
|
|
+
|
|
|
+ // Tune G1GC options for heaps < 8GB
|
|
|
+ static boolean tuneG1GCForSmallHeap(final long heapSize) {
|
|
|
+ return heapSize < 8L << 30;
|
|
|
+ }
|
|
|
+
|
|
|
+ static boolean tuneG1GCHeapRegion(final Map<String, JvmOption> finalJvmOptions, final boolean tuneG1GCForSmallHeap) {
|
|
|
+ JvmOption g1GCHeapRegion = finalJvmOptions.get("G1HeapRegionSize");
|
|
|
+ JvmOption g1GC = finalJvmOptions.get("UseG1GC");
|
|
|
+ return (tuneG1GCForSmallHeap && g1GC.getMandatoryValue().equals("true") && g1GCHeapRegion.isCommandLineOrigin() == false);
|
|
|
+ }
|
|
|
+
|
|
|
+ static int tuneG1GCReservePercent(final Map<String, JvmOption> finalJvmOptions, final boolean tuneG1GCForSmallHeap) {
|
|
|
+ JvmOption g1GC = finalJvmOptions.get("UseG1GC");
|
|
|
+ JvmOption g1GCReservePercent = finalJvmOptions.get("G1ReservePercent");
|
|
|
+ if (g1GC.getMandatoryValue().equals("true")) {
|
|
|
+ if (g1GCReservePercent.isCommandLineOrigin() == false && tuneG1GCForSmallHeap) {
|
|
|
+ return 15;
|
|
|
+ } else if (g1GCReservePercent.isCommandLineOrigin() == false && tuneG1GCForSmallHeap == false) {
|
|
|
+ return 25;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
- static long extractMaxDirectMemorySize(final Map<String, Optional<String>> finalJvmOptions) {
|
|
|
- return Long.parseLong(finalJvmOptions.get("MaxDirectMemorySize").get());
|
|
|
+ static boolean tuneG1GCInitiatingHeapOccupancyPercent(final Map<String, JvmOption> finalJvmOptions) {
|
|
|
+ JvmOption g1GC = finalJvmOptions.get("UseG1GC");
|
|
|
+ JvmOption g1GCInitiatingHeapOccupancyPercent = finalJvmOptions.get("InitiatingHeapOccupancyPercent");
|
|
|
+ return g1GCInitiatingHeapOccupancyPercent.isCommandLineOrigin() == false && g1GC.getMandatoryValue().equals("true");
|
|
|
}
|
|
|
|
|
|
private static final Pattern SYSTEM_PROPERTY = Pattern.compile("^-D(?<key>[\\w+].*?)=(?<value>.*)$");
|