-
Notifications
You must be signed in to change notification settings - Fork 25.2k
Use different G1GC options for small heaps #59667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 17 commits
7d987ba
ab6059d
2655315
2003331
3c05949
818226a
f14d2cd
4d033a4
9008ede
d0e34fe
70b4de9
a6f5302
ffec016
80b713b
411cfd4
ec2b891
8d3c734
ac9a568
f326f5b
5ddb619
d628ff9
d8a3840
f2e999a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,25 +53,57 @@ private 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(finalJvmOptions, heapSize); | ||
final boolean tuneG1GCForLargeHeap = tuneG1GCForLargeHeap(finalJvmOptions, heapSize); | ||
if (tuneG1GCForSmallHeap) { | ||
ergonomicChoices.add("-XX:G1HeapRegionSize=4m"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. As mentioned on another channel, I think we should make reserve pct 15 rather than the default 10 - to stay safely clear of real memory circuit breaker exceptions. I also think we should add in the IHOP always if it is not defined, just to be safe. It should not matter for performance since G1 will adaptively adjust the value. |
||
ergonomicChoices.add("-XX:G1ReservePercent=15"); | ||
ergonomicChoices.add("-XX:InitiatingHeapOccupancyPercent=45"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should use 30 in this case too. |
||
} else if (tuneG1GCForLargeHeap) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same comment as above, is surprising that if one of them is specified you loose the other. In particular if IHOP is specified, it seems quite dangerous to no longer set There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you for catching this, I updated the pr. |
||
ergonomicChoices.add("-XX:G1ReservePercent=25"); | ||
ergonomicChoices.add("-XX:InitiatingHeapOccupancyPercent=30"); | ||
} | ||
|
||
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>[^}]+)}" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Drive-by comment, feel free to ignore - should we pass |
||
); | ||
|
||
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 +148,36 @@ private static List<String> readLinesFromInputStream(final InputStream is) throw | |
} | ||
|
||
// 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 unless the user has explicitly set G1HeapRegionSize | ||
static boolean tuneG1GCForSmallHeap(final Map<String, JvmOption> finalJvmOptions, final long heapSize) { | ||
JvmOption g1GC = finalJvmOptions.get("UseG1GC"); | ||
JvmOption g1GCHeapRegion = finalJvmOptions.get("G1HeapRegionSize"); | ||
JvmOption g1GCReservePercent = finalJvmOptions.get("G1ReservePercent"); | ||
JvmOption g1GCInitiatingHeapOccupancyPercent = finalJvmOptions.get("InitiatingHeapOccupancyPercent"); | ||
return (heapSize < 8L << 30 | ||
&& g1GC.getMandatoryValue().equals("true") | ||
&& g1GCHeapRegion.isCommandLineOrigin() == false | ||
&& g1GCReservePercent.isCommandLineOrigin() == false | ||
&& g1GCInitiatingHeapOccupancyPercent.isCommandLineOrigin() == false); | ||
} | ||
|
||
static long extractMaxDirectMemorySize(final Map<String, Optional<String>> finalJvmOptions) { | ||
return Long.parseLong(finalJvmOptions.get("MaxDirectMemorySize").get()); | ||
// Tune G1GC options for heaps >= 8GB unless the user has explicitly set -XX:G1ReservePercent or -XX:InitiatingHeapOccupancyPercent | ||
static boolean tuneG1GCForLargeHeap(final Map<String, JvmOption> finalJvmOptions, final long heapSize) { | ||
JvmOption g1GC = finalJvmOptions.get("UseG1GC"); | ||
JvmOption g1GCReservePercent = finalJvmOptions.get("G1ReservePercent"); | ||
JvmOption g1GCInitiatingHeapOccupancyPercent = finalJvmOptions.get("InitiatingHeapOccupancyPercent"); | ||
return (heapSize >= 8L << 30 | ||
&& g1GC.getMandatoryValue().equals("true") | ||
&& g1GCReservePercent.isCommandLineOrigin() == false | ||
&& g1GCInitiatingHeapOccupancyPercent.isCommandLineOrigin() == false); | ||
} | ||
|
||
private static final Pattern SYSTEM_PROPERTY = Pattern.compile("^-D(?<key>[\\w+].*?)=(?<value>.*)$"); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is surprising that if you manually specify any of the 3 parameters you loose all 3. For instance if they decide to raise
G1ReservePercent
to 20, the region size adjustment is lost.I think the check in
tuneG1GCForSmallHeap
should only check heap size and maybe that G1 is in use.The code below should then only add options where there is no existing
command line
origin option.Alternatively (to the last part), we could swap the two lines here:
elasticsearch/distribution/tools/launchers/src/main/java/org/elasticsearch/tools/launchers/JvmOptionsParser.java
Line 144 in 01dc110
to be:
since that would ensure that the original command line options override the ergonomics picked here.