Skip to content

Commit

Permalink
Revise experimental options printing.
Browse files Browse the repository at this point in the history
This also make sure that `-H:Log` and other `OptionKey`s that are not `HostedOptionKey`s are listed.
  • Loading branch information
fniephaus committed Nov 2, 2023
1 parent d9b146c commit 2c576a3
Showing 1 changed file with 68 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,11 @@
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.concurrent.Executors;
Expand All @@ -52,11 +50,6 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;

import jdk.graal.compiler.options.OptionDescriptor;
import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionStability;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.serviceprovider.GraalServices;
import org.graalvm.nativeimage.ImageSingletons;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.impl.ImageSingletonsSupport;
Expand All @@ -81,6 +74,7 @@
import com.oracle.svm.core.option.HostedOptionValues;
import com.oracle.svm.core.option.LocatableMultiOptionValue;
import com.oracle.svm.core.option.OptionOrigin;
import com.oracle.svm.core.option.RuntimeOptionKey;
import com.oracle.svm.core.option.SubstrateOptionsParser;
import com.oracle.svm.core.util.VMError;
import com.oracle.svm.core.util.json.JsonWriter;
Expand All @@ -98,6 +92,12 @@
import com.oracle.svm.hosted.util.VMErrorReporter;
import com.oracle.svm.util.ImageBuildStatistics;

import jdk.graal.compiler.options.OptionDescriptor;
import jdk.graal.compiler.options.OptionKey;
import jdk.graal.compiler.options.OptionStability;
import jdk.graal.compiler.options.OptionValues;
import jdk.graal.compiler.serviceprovider.GraalServices;

public class ProgressReporter {
private static final boolean IS_CI = SubstrateUtil.isRunningInCI();
private static final int CHARACTERS_PER_LINE;
Expand Down Expand Up @@ -311,74 +311,86 @@ public String toSuffix() {
}

private void printExperimentalOptions(ImageClassLoader classLoader) {
String hostedOptionPrefix = CommonOptionParser.HOSTED_OPTION_PREFIX;

Set<String> rawHostedOptionNamesFromDriver = new HashSet<>();
/*
* Step 1: scan all builder arguments and collect relevant options.
*/
Map<String, OptionOrigin> experimentalBuilderOptionsAndOrigins = new HashMap<>();
for (String arg : DiagnosticUtils.getBuilderArguments(classLoader)) {
if (!arg.startsWith(hostedOptionPrefix)) {
if (!arg.startsWith(CommonOptionParser.HOSTED_OPTION_PREFIX)) {
continue;
}
String rawOption = arg.split("=", 2)[0].split("@", 2)[0];
rawHostedOptionNamesFromDriver.add(rawOption);
String[] optionParts = arg.split("=", 2)[0].split("@", 2);
OptionOrigin optionOrigin = optionParts.length == 2 ? OptionOrigin.from(optionParts[1], false) : null;
if (optionOrigin == null || !isStableOrInternalOrigin(optionOrigin)) {
String prefixedOptionName = optionParts[0];
experimentalBuilderOptionsAndOrigins.put(prefixedOptionName, optionOrigin);
}
}

/*
* Step 2: scan HostedOptionValues and collect migrationMessage, alternatives, and origins.
*/
Map<String, ExperimentalOptionDetails> experimentalOptions = new HashMap<>();
var hostedOptionValues = HostedOptionValues.singleton().getMap();

for (OptionKey<?> option : hostedOptionValues.getKeys()) {
if (option == SubstrateOptions.UnlockExperimentalVMOptions) {
if (option instanceof RuntimeOptionKey || option == SubstrateOptions.UnlockExperimentalVMOptions || option.getDescriptor().getStability() != OptionStability.EXPERIMENTAL) {
continue;
}
if (option instanceof HostedOptionKey<?> hok && option.getDescriptor().getStability() == OptionStability.EXPERIMENTAL) {
OptionDescriptor hokDescriptor = hok.getDescriptor();
String optionPrefix = hostedOptionPrefix;
String origins = "";
/* We use the first extra help item for migration messages for options. */
String migrationMessage = hokDescriptor.getExtraHelp().isEmpty() ? "" : hokDescriptor.getExtraHelp().getFirst();
String alternatives = "";
Object value = option.getValueOrDefault(hostedOptionValues);
if (value instanceof LocatableMultiOptionValue<?> lmov) {
if (lmov.getValuesWithOrigins().allMatch(o -> o.getRight().isStable())) {
continue;
} else {
origins = lmov.getValuesWithOrigins().filter(p -> !isStableOrInternalOrigin(p.getRight())).map(p -> p.getRight().toString()).collect(Collectors.joining(", "));
if (alternatives.isEmpty()) {
alternatives = lmov.getValuesWithOrigins().map(p -> SubstrateOptionsParser.commandArgument(hok, p.getLeft().toString())).filter(c -> !c.startsWith(hostedOptionPrefix))
.collect(Collectors.joining(", "));
}
}
OptionDescriptor descriptor = option.getDescriptor();
Object optionValue = option.getValueOrDefault(hostedOptionValues);
String emptyOrBooleanValue = "";
if (descriptor.getOptionValueType() == Boolean.class) {
emptyOrBooleanValue = Boolean.valueOf(optionValue.toString()) ? "+" : "-";
}
String prefixedOptionName = CommonOptionParser.HOSTED_OPTION_PREFIX + emptyOrBooleanValue + option.getName();
if (!experimentalBuilderOptionsAndOrigins.containsKey(prefixedOptionName)) {
/* Only check builder arguments, ignore options that were set as part of others. */
continue;
}
String origins = "";
/* The first extra help item is used for migration messages of options. */
String migrationMessage = descriptor.getExtraHelp().isEmpty() ? "" : descriptor.getExtraHelp().getFirst();
String alternatives = "";

if (optionValue instanceof LocatableMultiOptionValue<?> lmov) {
if (lmov.getValuesWithOrigins().allMatch(o -> o.getRight().isStable())) {
continue;
} else {
OptionOrigin origin = hok.getLastOrigin();
if (origin == null /* unknown */ || isStableOrInternalOrigin(origin)) {
continue;
}
origins = origin.toString();
String valueString;
if (hokDescriptor.getOptionValueType() == Boolean.class) {
valueString = Boolean.valueOf(value.toString()) ? "+" : "-";
optionPrefix += valueString;
} else {
valueString = value.toString();
}
if (alternatives.isEmpty()) {
String command = SubstrateOptionsParser.commandArgument(hok, valueString);
if (!command.startsWith(hostedOptionPrefix)) {
alternatives = command;
}
}
origins = lmov.getValuesWithOrigins().filter(p -> !isStableOrInternalOrigin(p.getRight())).map(p -> p.getRight().toString()).collect(Collectors.joining(", "));
alternatives = lmov.getValuesWithOrigins().map(p -> SubstrateOptionsParser.commandArgument(option, p.getLeft().toString()))
.filter(c -> !c.startsWith(CommonOptionParser.HOSTED_OPTION_PREFIX))
.collect(Collectors.joining(", "));
}
} else {
OptionOrigin origin = experimentalBuilderOptionsAndOrigins.get(prefixedOptionName);
if (origin == null && option instanceof HostedOptionKey<?> hok) {
origin = hok.getLastOrigin();
}
if (origin == null /* unknown */ || isStableOrInternalOrigin(origin)) {
continue;
}
String rawHostedOptionName = optionPrefix + hok.getName();
if (rawHostedOptionNamesFromDriver.contains(rawHostedOptionName)) {
experimentalOptions.put(rawHostedOptionName, new ExperimentalOptionDetails(migrationMessage, alternatives, origins));
origins = origin.toString();
String optionValueString;
if (descriptor.getOptionValueType() == Boolean.class) {
assert !emptyOrBooleanValue.isEmpty();
optionValueString = emptyOrBooleanValue;
} else {
optionValueString = String.valueOf(optionValue);
}
String command = SubstrateOptionsParser.commandArgument(option, optionValueString);
if (!command.startsWith(CommonOptionParser.HOSTED_OPTION_PREFIX)) {
alternatives = command;
}
}
experimentalOptions.put(prefixedOptionName, new ExperimentalOptionDetails(migrationMessage, alternatives, origins));
}
/*
* Step 3: print list of experimental options (if any).
*/
if (experimentalOptions.isEmpty()) {
return;
}
l().printLineSeparator();
l().yellowBold().a(" ").a(experimentalOptions.size()).a(" ").doclink("experimental option(s)", "#glossary-experimental-options").a(" unlocked").reset().a(":").println();

for (var optionAndDetails : experimentalOptions.entrySet()) {
l().a(" - '%s'%s", optionAndDetails.getKey(), optionAndDetails.getValue().toSuffix()).println();
}
Expand Down

0 comments on commit 2c576a3

Please sign in to comment.