Add more timings to R8 enqueuer.
Change-Id: I74d18a865f6f7809b68ed0e1b41a0098d9cdccf6
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 3102f0d..88f233f 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -318,6 +318,7 @@
List<ProguardConfigurationRule> synthesizedProguardRules = new ArrayList<>();
timing.begin("Strip unused code");
+ timing.begin("Before enqueuer");
RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder =
new RuntimeTypeCheckInfo.Builder(appView);
try {
@@ -356,6 +357,8 @@
AnnotationRemover.Builder annotationRemoverBuilder =
options.isShrinking() ? AnnotationRemover.builder(Mode.INITIAL_TREE_SHAKING) : null;
+ timing.end();
+ timing.begin("Enqueuer");
AppView<AppInfoWithLiveness> appViewWithLiveness =
runEnqueuer(
annotationRemoverBuilder,
@@ -363,7 +366,8 @@
appView,
subtypingInfo,
classMergingEnqueuerExtensionBuilder);
-
+ timing.end();
+ timing.begin("After enqueuer");
assert appView.rootSet().verifyKeptFieldsAreAccessedAndLive(appViewWithLiveness);
assert appView.rootSet().verifyKeptMethodsAreTargetedAndLive(appViewWithLiveness);
assert appView.rootSet().verifyKeptTypesAreLive(appViewWithLiveness);
@@ -429,6 +433,7 @@
assert appView.checkForTesting(() -> allReferencesAssignedApiLevel(appViewWithLiveness));
}
+ timing.end();
} finally {
timing.end();
}
@@ -982,6 +987,7 @@
SubtypingInfo subtypingInfo,
RuntimeTypeCheckInfo.Builder classMergingEnqueuerExtensionBuilder)
throws ExecutionException {
+ timing.begin("Set up enqueuer");
Enqueuer enqueuer =
EnqueuerFactory.createForInitialTreeShaking(appView, executorService, subtypingInfo);
enqueuer.setAnnotationRemoverBuilder(annotationRemoverBuilder);
@@ -999,9 +1005,12 @@
if (options.isClassMergingExtensionRequired(enqueuer.getMode())) {
classMergingEnqueuerExtensionBuilder.attach(enqueuer);
}
-
+ timing.end();
+ timing.begin("Trace application");
EnqueuerResult enqueuerResult =
enqueuer.traceApplication(appView.rootSet(), executorService, timing);
+ timing.end();
+ timing.begin("Finalize enqueuer result");
AppView<AppInfoWithLiveness> appViewWithLiveness =
appView.setAppInfo(enqueuerResult.getAppInfo());
if (InternalOptions.assertionsEnabled()) {
@@ -1015,6 +1024,7 @@
shrinker ->
shrinker.rewriteDeadBuilderReferencesFromDynamicMethods(
appViewWithLiveness, executorService, timing));
+ timing.end();
return appViewWithLiveness;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6c5c07b..59b7ae3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -3606,6 +3606,7 @@
this.rootSet = rootSet;
rootSet.pendingMethodMoveInverse.forEach(pendingMethodMoveInverse::put);
// Translate the result of root-set computation into enqueuer actions.
+ timing.begin("Register analysis");
if (mode.isTreeShaking()
&& appView.options().hasProguardConfiguration()
&& !options.kotlinOptimizationOptions().disableKotlinSpecificOptimizations) {
@@ -3620,14 +3621,20 @@
if (options.apiModelingOptions().enableLibraryApiModeling) {
registerAnalysis(new ApiModelAnalysis(appView));
}
+ timing.end();
// Transfer the minimum keep info from the root set into the Enqueuer state.
+ timing.begin("Transfer minimum keep info");
includeMinimumKeepInfo(rootSet);
+ timing.end();
if (mode.isInitialTreeShaking()) {
// Amend library methods with covariant return types.
+ timing.begin("Model library");
modelLibraryMethodsWithCovariantReturnTypes();
+ timing.end();
} else if (appView.getKeepInfo() != null) {
+ timing.begin("Retain keep info");
EnqueuerEvent preconditionEvent = UnconditionalKeepInfoEvent.get();
appView
.getKeepInfo()
@@ -3638,24 +3645,38 @@
(field, minimumKeepInfo) ->
applyMinimumKeepInfoWhenLive(field, minimumKeepInfo, preconditionEvent),
this::applyMinimumKeepInfoWhenLiveOrTargeted);
+ timing.end();
}
+ timing.begin("Enqueue all");
enqueueAllIfNotShrinking();
+ timing.end();
+ timing.begin("Trace");
trace(executorService, timing);
+ timing.end();
options.reporter.failIfPendingErrors();
+ timing.begin("Finalize library override");
finalizeLibraryMethodOverrideInformation();
+ timing.end();
+ timing.begin("Finish analysis");
analyses.forEach(analyses -> analyses.done(this));
+ timing.end();
assert verifyKeptGraph();
+ timing.begin("Finish compat building");
if (mode.isInitialTreeShaking() && forceProguardCompatibility) {
appView.setProguardCompatibilityActions(proguardCompatibilityActionsBuilder.build());
} else {
assert proguardCompatibilityActionsBuilder == null;
}
+ timing.end();
if (mode.isWhyAreYouKeeping()) {
// For why are you keeping the information is reported through the kept graph callbacks and
// no AppInfo is returned.
return null;
}
- return createEnqueuerResult(appInfo);
+ timing.begin("Create result");
+ EnqueuerResult result = createEnqueuerResult(appInfo, timing);
+ timing.end();
+ return result;
}
private void includeMinimumKeepInfo(RootSetBase rootSet) {
@@ -4163,38 +4184,47 @@
return true;
}
- private EnqueuerResult createEnqueuerResult(AppInfoWithClassHierarchy appInfo)
+ private EnqueuerResult createEnqueuerResult(AppInfoWithClassHierarchy appInfo, Timing timing)
throws ExecutionException {
+ timing.begin("Remove dead protos");
// Compute the set of dead proto types.
deadProtoTypeCandidates.removeIf(this::isTypeLive);
Set<DexType> deadProtoTypes =
SetUtils.newIdentityHashSet(deadProtoTypeCandidates.size() + initialDeadProtoTypes.size());
deadProtoTypeCandidates.forEach(deadProtoType -> deadProtoTypes.add(deadProtoType.type));
deadProtoTypes.addAll(initialDeadProtoTypes);
+ timing.end();
// Remove the temporary mappings that have been inserted into the field access info collection
// and verify that the mapping is then one-to-one.
+ timing.begin("Prune field access mappings");
fieldAccessInfoCollection.removeIf(
(field, info) -> field != info.getField() || info == MISSING_FIELD_ACCESS_INFO);
assert fieldAccessInfoCollection.verifyMappingIsOneToOne();
+ timing.end();
// Verify all references on the input app before synthesizing definitions.
assert verifyReferences(appInfo.app());
// Prune the root set items that turned out to be dead.
// TODO(b/150736225): Pruning of dead root set items is still incomplete.
- rootSet.pruneDeadItems(appView, this);
+ timing.begin("Prune dead items");
+ rootSet.pruneDeadItems(appView, this, timing);
if (mode.isTreeShaking() && appView.hasMainDexRootSet()) {
assert rootSet != appView.getMainDexRootSet();
- appView.getMainDexRootSet().pruneDeadItems(appView, this);
+ appView.getMainDexRootSet().pruneDeadItems(appView, this, timing);
}
+ timing.end();
// Ensure references from all hard coded factory items.
+ timing.begin("Ensure static factory references");
appView
.dexItemFactory()
.forEachPossiblyCompilerSynthesizedType(this::recordCompilerSynthesizedTypeReference);
+ timing.end();
// Rebuild a new app only containing referenced types.
+ timing.begin("Rebuild application");
Set<DexLibraryClass> libraryClasses = Sets.newIdentityHashSet();
Set<DexClasspathClass> classpathClasses = Sets.newIdentityHashSet();
// Ensure all referenced non program types have their hierarchy built as live.
@@ -4220,6 +4250,7 @@
.replaceLibraryClasses(libraryClasses)
.replaceClasspathClasses(classpathClasses)
.build();
+ timing.end();
// Verify the references on the pruned application after type synthesis.
assert verifyReferences(app);
@@ -4232,7 +4263,10 @@
: ImmutableSet.of(syntheticClass.getType());
};
amendKeepInfoWithCompanionMethods();
+ timing.begin("Rewrite with deferred results");
deferredTracing.rewriteApplication(executorService);
+ timing.end();
+ timing.begin("Create app info with liveness");
AppInfoWithLiveness appInfoWithLiveness =
new AppInfoWithLiveness(
appInfo.getSyntheticItems().commit(app),
@@ -4275,6 +4309,7 @@
lockCandidates,
initClassReferences,
recordFieldValuesReferences);
+ timing.end();
appInfo.markObsolete();
if (options.testing.enqueuerInspector != null) {
options.testing.enqueuerInspector.accept(appInfoWithLiveness, mode);
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
index 9e1f28f..a728063 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetUtils.java
@@ -71,6 +71,7 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
+import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.google.common.base.Equivalence.Wrapper;
@@ -1918,12 +1919,17 @@
minimumKeepInfoForDefinition -> !minimumKeepInfoForDefinition.isShrinkingAllowed());
}
- public void pruneDeadItems(DexDefinitionSupplier definitions, Enqueuer enqueuer) {
+ public void pruneDeadItems(
+ DexDefinitionSupplier definitions, Enqueuer enqueuer, Timing timing) {
+ timing.begin("Prune keep info");
getDependentMinimumKeepInfo().pruneDeadItems(definitions, enqueuer);
+ timing.end();
+ timing.begin("Prune others");
pruneDeadReferences(noUnusedInterfaceRemoval, definitions, enqueuer);
pruneDeadReferences(noVerticalClassMerging, definitions, enqueuer);
pruneDeadReferences(noHorizontalClassMerging, definitions, enqueuer);
pruneDeadReferences(alwaysInline, definitions, enqueuer);
+ timing.end();
}
private static void pruneDeadReferences(