Add blaze flag and support for splitting OPTIMIZATION bytecode optimizer action.
This adds a blaze flag ("split_bytecode_optimization_pass") to JavaOptions.
There is no functional difference this CL makes as long as the flag isn't
specified.
When the flag is specified, the OPTIMIZATION stage in the bytecode optimizer
will be split into 2 stages (OPTIMIZATION_INITIAL, OPTIMIZATION_FINAL),
each taking slightly over half the time of the original OPTIMIZATION stage.
PiperOrigin-RevId: 324702687
diff --git a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java b/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java
index db2038b..c86b6f4 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/android/ProguardHelper.java
@@ -16,6 +16,7 @@
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
+import com.google.common.base.Ascii;
import com.google.common.base.Joiner;
import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
@@ -380,7 +381,9 @@
proguardAction.addCommandLine(commandLine.build());
ruleContext.registerAction(proguardAction.build(ruleContext));
} else {
- JavaConfiguration.NamedLabel optimizer = getBytecodeOptimizer(ruleContext);
+ JavaConfiguration javaConfiguration =
+ ruleContext.getConfiguration().getFragment(JavaConfiguration.class);
+ JavaConfiguration.NamedLabel optimizer = javaConfiguration.getBytecodeOptimizer();
String mnemonic = optimizer.name();
Optional<Label> optimizerTarget = optimizer.label();
FilesToRunProvider executable = null;
@@ -426,39 +429,51 @@
initialAction.addCommandLine(initialCommandLine.build());
ruleContext.registerAction(initialAction.build(ruleContext));
for (int i = 1; i <= optimizationPasses; i++) {
- Artifact optimizationOutput =
- getProguardTempArtifact(ruleContext, mnemonic + "_optimization_" + i + ".jar");
- SpawnAction.Builder optimizationAction = new SpawnAction.Builder();
- CustomCommandLine.Builder optimizationCommandLine = CustomCommandLine.builder();
- defaultAction(
- optimizationAction,
- optimizationCommandLine,
- executable,
- programJar,
- proguardSpecs,
- proguardMapping,
- proguardDictionary,
- libraryJars,
- output.getOutputJar(),
- /* proguardOutputMap */ null,
- /* proguardOutputProtoMap */ null,
- /* proguardSeeds */ null,
- /* proguardUsage */ null,
- /* constantStringObfuscatedMapping */ null,
- /* proguardConfigOutput */ null,
- mnemonic);
- optimizationAction
- .setProgressMessage("Trimming binary with %s: Optimization Pass %d", mnemonic, +i)
- .setMnemonic(mnemonic)
- .addInput(lastStageOutput)
- .addOutput(optimizationOutput);
- optimizationCommandLine
- .add("-runtype OPTIMIZATION")
- .addExecPath("-laststageoutput", lastStageOutput)
- .addExecPath("-nextstageoutput", optimizationOutput);
- optimizationAction.addCommandLine(optimizationCommandLine.build());
- ruleContext.registerAction(optimizationAction.build(ruleContext));
- lastStageOutput = optimizationOutput;
+ if (javaConfiguration.splitBytecodeOptimizationPass()) {
+ lastStageOutput =
+ createSingleOptimizationAction(
+ "_INITIAL",
+ ruleContext,
+ mnemonic,
+ i,
+ executable,
+ programJar,
+ proguardSpecs,
+ proguardMapping,
+ proguardDictionary,
+ libraryJars,
+ output,
+ lastStageOutput);
+ lastStageOutput =
+ createSingleOptimizationAction(
+ "_FINAL",
+ ruleContext,
+ mnemonic,
+ i,
+ executable,
+ programJar,
+ proguardSpecs,
+ proguardMapping,
+ proguardDictionary,
+ libraryJars,
+ output,
+ lastStageOutput);
+ } else {
+ lastStageOutput =
+ createSingleOptimizationAction(
+ /* runtypeSuffix */ "",
+ ruleContext,
+ mnemonic,
+ i,
+ executable,
+ programJar,
+ proguardSpecs,
+ proguardMapping,
+ proguardDictionary,
+ libraryJars,
+ output,
+ lastStageOutput);
+ }
}
SpawnAction.Builder finalAction = new SpawnAction.Builder();
@@ -493,6 +508,70 @@
return output;
}
+ /**
+ * Creates a single build stage where the run type of the optimizer is "OPTMIZATION*" where "*" is
+ * the value of the provided runtypeSuffix. For example, if runtypeSuffix is "_INITIAL", the run
+ * type will be "OPTIMIZATION_INITIAL".
+ *
+ * @return The output artifact from the last "OPTIMIZATION*" stage.
+ */
+ private static Artifact createSingleOptimizationAction(
+ String runtypeSuffix,
+ RuleContext ruleContext,
+ String mnemonic,
+ int optimizationPassNum,
+ FilesToRunProvider executable,
+ Artifact programJar,
+ ImmutableList<Artifact> proguardSpecs,
+ @Nullable Artifact proguardMapping,
+ @Nullable Artifact proguardDictionary,
+ NestedSet<Artifact> libraryJars,
+ ProguardOutput output,
+ Artifact lastStageOutput) {
+ Artifact optimizationOutput =
+ getProguardTempArtifact(
+ ruleContext,
+ mnemonic
+ + "_optimization"
+ + Ascii.toLowerCase(runtypeSuffix)
+ + "_"
+ + optimizationPassNum
+ + ".jar");
+ SpawnAction.Builder optimizationAction = new SpawnAction.Builder();
+ CustomCommandLine.Builder optimizationCommandLine = CustomCommandLine.builder();
+ defaultAction(
+ optimizationAction,
+ optimizationCommandLine,
+ executable,
+ programJar,
+ proguardSpecs,
+ proguardMapping,
+ proguardDictionary,
+ libraryJars,
+ output.getOutputJar(),
+ /* proguardOutputMap */ null,
+ /* proguardOutputProtoMap */ null,
+ /* proguardSeeds */ null,
+ /* proguardUsage */ null,
+ /* constantStringObfuscatedMapping */ null,
+ /* proguardConfigOutput */ null,
+ mnemonic);
+ optimizationAction
+ .setProgressMessage(
+ "Trimming binary with %s: Optimization%s Pass %d",
+ mnemonic, Ascii.toLowerCase(runtypeSuffix), optimizationPassNum)
+ .setMnemonic(mnemonic)
+ .addInput(lastStageOutput)
+ .addOutput(optimizationOutput);
+ optimizationCommandLine
+ .addDynamicString("-runtype OPTIMIZATION" + runtypeSuffix)
+ .addExecPath("-laststageoutput", lastStageOutput)
+ .addExecPath("-nextstageoutput", optimizationOutput);
+ optimizationAction.addCommandLine(optimizationCommandLine.build());
+ ruleContext.registerAction(optimizationAction.build(ruleContext));
+ return optimizationOutput;
+ }
+
private static void defaultAction(
SpawnAction.Builder builder,
CustomCommandLine.Builder commandLine,
@@ -604,11 +683,4 @@
Label label, ActionConstructionContext context, String prefix) {
return getProguardTempArtifact(label, context, prefix, "proguard.cfg");
}
-
- private static JavaConfiguration.NamedLabel getBytecodeOptimizer(RuleContext ruleContext) {
- return ruleContext
- .getConfiguration()
- .getFragment(JavaConfiguration.class)
- .getBytecodeOptimizer();
- }
}
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
index aac1a32..977af5f 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaConfiguration.java
@@ -98,6 +98,7 @@
private final TriState bundleTranslations;
private final ImmutableList<Label> translationTargets;
private final NamedLabel bytecodeOptimizer;
+ private final boolean splitBytecodeOptimizationPass;
private final boolean enforceProguardFileExtension;
private final Label toolchainLabel;
private final Label runtimeLabel;
@@ -131,6 +132,7 @@
this.fixDepsTool = javaOptions.fixDepsTool;
this.proguardBinary = javaOptions.proguard;
this.extraProguardSpecs = ImmutableList.copyOf(javaOptions.extraProguardSpecs);
+ this.splitBytecodeOptimizationPass = javaOptions.splitBytecodeOptimizationPass;
this.enforceProguardFileExtension = javaOptions.enforceProguardFileExtension;
this.bundleTranslations = javaOptions.bundleTranslations;
this.toolchainLabel = javaOptions.javaToolchain;
@@ -308,6 +310,14 @@
return extraProguardSpecs;
}
+ /**
+ * Returns whether the OPTIMIZATION stage of the bytecode optimizer will be split across multiple
+ * actions.
+ */
+ public boolean splitBytecodeOptimizationPass() {
+ return splitBytecodeOptimizationPass;
+ }
+
/** Returns whether ProGuard configuration files are required to use a *.pgcfg extension. */
public boolean enforceProguardFileExtension() {
return enforceProguardFileExtension;
diff --git a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
index bbaad01..a8ab30e 100644
--- a/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
+++ b/src/main/java/com/google/devtools/build/lib/rules/java/JavaOptions.java
@@ -387,6 +387,18 @@
help = "Do not use.")
public Map<String, Label> bytecodeOptimizers;
+ /**
+ * If true, the OPTIMIZATION stage of the bytecode optimizer will be split across multiple
+ * actions.
+ */
+ @Option(
+ name = "split_bytecode_optimization_pass",
+ defaultValue = "false",
+ documentationCategory = OptionDocumentationCategory.UNDOCUMENTED,
+ effectTags = {OptionEffectTag.UNKNOWN},
+ help = "Do not use.")
+ public boolean splitBytecodeOptimizationPass;
+
@Option(
name = "enforce_proguard_file_extension",
defaultValue = "false",
@@ -705,6 +717,8 @@
host.javaLanguageVersion = hostJavaLanguageVersion;
host.bytecodeOptimizers = bytecodeOptimizers;
+ host.splitBytecodeOptimizationPass = splitBytecodeOptimizationPass;
+
host.enforceProguardFileExtension = enforceProguardFileExtension;
host.extraProguardSpecs = extraProguardSpecs;
host.proguard = proguard;
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
index baf6f57..e03f21c 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBinaryTest.java
@@ -3766,6 +3766,7 @@
"b_proguard.jar",
false,
null,
+ /*splitOptimizationPass=*/ false,
targetConfig.getBinFragment()
+ "/java/com/google/android/hello/proguard/b/legacy_b_combined_library_jars.jar");
}
@@ -3905,7 +3906,12 @@
" proguard_specs = ['proguard-spec.pro'],",
" proguard_generate_mapping = 1)");
checkProguardUse(
- "//java/com/google/android/hello:b", "b_proguard.jar", true, null, getAndroidJarPath());
+ "//java/com/google/android/hello:b",
+ "b_proguard.jar",
+ true,
+ null,
+ /*splitOptimizationPass=*/ false,
+ getAndroidJarPath());
}
@Test
@@ -3957,7 +3963,12 @@
" manifest = 'AndroidManifest.xml',",
" proguard_specs = ['proguard-spec.pro'])");
checkProguardUse(
- "//java/com/google/android/hello:b", "b_proguard.jar", false, null, getAndroidJarPath());
+ "//java/com/google/android/hello:b",
+ "b_proguard.jar",
+ false,
+ null,
+ /*splitOptimizationPass=*/ false,
+ getAndroidJarPath());
SpawnAction action =
(SpawnAction)
@@ -3983,7 +3994,12 @@
" manifest = 'AndroidManifest.xml',",
" proguard_specs = ['proguard-spec.pro'])");
checkProguardUse(
- "//java/com/google/android/hello:b", "b_proguard.jar", false, null, getAndroidJarPath());
+ "//java/com/google/android/hello:b",
+ "b_proguard.jar",
+ false,
+ null,
+ /*splitOptimizationPass=*/ false,
+ getAndroidJarPath());
SpawnAction action =
(SpawnAction)
@@ -4304,6 +4320,7 @@
"abin_proguard.jar",
/*expectMapping=*/ false,
/*passes=*/ null,
+ /*splitOptimizationPass=*/ false,
getAndroidJarPath());
}
diff --git a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
index f33fcad..5e9de5f 100644
--- a/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
+++ b/src/test/java/com/google/devtools/build/lib/rules/android/AndroidBuildViewTestCase.java
@@ -330,6 +330,7 @@
String artifact,
boolean expectMapping,
@Nullable Integer passes,
+ boolean splitOptimizationPass,
String... expectedlibraryJars)
throws Exception {
ConfiguredTarget binary = getConfiguredTarget(target);
@@ -373,16 +374,36 @@
SpawnAction lastStageAction = proguardAction;
// Verify Obfuscation config.
for (int pass = passes; pass > 0; pass--) {
- Artifact lastStageOutput =
- ActionsTestUtil.getFirstArtifactEndingWith(
- lastStageAction.getInputs(), "Proguard_optimization_" + pass + ".jar");
- assertWithMessage("Proguard_optimization_" + pass + ".jar is not in rule output")
- .that(lastStageOutput)
- .isNotNull();
- lastStageAction = getGeneratingSpawnAction(lastStageOutput);
+ if (splitOptimizationPass) {
+ Artifact lastStageOutput =
+ ActionsTestUtil.getFirstArtifactEndingWith(
+ lastStageAction.getInputs(), "_optimization_final_" + pass + ".jar");
+ assertWithMessage("optimization_final_" + pass + ".jar is not in rule output")
+ .that(lastStageOutput)
+ .isNotNull();
+ lastStageAction = getGeneratingSpawnAction(lastStageOutput);
+ assertThat(lastStageAction.getArguments()).contains("-runtype OPTIMIZATION_FINAL");
- // Verify Optimization pass config.
- assertThat(lastStageAction.getArguments()).contains("-runtype OPTIMIZATION");
+ lastStageOutput =
+ ActionsTestUtil.getFirstArtifactEndingWith(
+ lastStageAction.getInputs(), "_optimization_initial_" + pass + ".jar");
+ assertWithMessage("optimization_initial_" + pass + ".jar is not in rule output")
+ .that(lastStageOutput)
+ .isNotNull();
+ lastStageAction = getGeneratingSpawnAction(lastStageOutput);
+ assertThat(lastStageAction.getArguments()).contains("-runtype OPTIMIZATION_INITIAL");
+ } else {
+ Artifact lastStageOutput =
+ ActionsTestUtil.getFirstArtifactEndingWith(
+ lastStageAction.getInputs(), "_optimization_" + pass + ".jar");
+ assertWithMessage("Proguard_optimization_" + pass + ".jar is not in rule output")
+ .that(lastStageOutput)
+ .isNotNull();
+ lastStageAction = getGeneratingSpawnAction(lastStageOutput);
+
+ // Verify Optimization pass config.
+ assertThat(lastStageAction.getArguments()).contains("-runtype OPTIMIZATION");
+ }
checkProguardLibJars(lastStageAction, expectedlibraryJars);
}