Add more detailed timing information

Change-Id: I923e63ed536717eb4bca890af53f5fdcc9f5169c
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5223520..100b5aa 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -717,7 +717,7 @@
           // TODO(b/112437944): Avoid iterating the entire application to post-process every
           //  dynamicMethod() method.
           appView.withGeneratedMessageLiteShrinker(
-              shrinker -> shrinker.postOptimizeDynamicMethods(converter));
+              shrinker -> shrinker.postOptimizeDynamicMethods(converter, timing));
 
           // If proto shrinking is enabled, we need to post-process every
           // findLiteExtensionByNumber() method. This ensures that there are no references to dead
@@ -725,7 +725,7 @@
           // TODO(b/112437944): Avoid iterating the entire application to post-process every
           //  findLiteExtensionByNumber() method.
           appView.withGeneratedExtensionRegistryShrinker(
-              shrinker -> shrinker.postOptimizeGeneratedExtensionRegistry(converter));
+              shrinker -> shrinker.postOptimizeGeneratedExtensionRegistry(converter, timing));
         }
       }
 
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
index 8374410..29d7dcc 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/EnqueuerAnalysis.java
@@ -9,6 +9,7 @@
 import com.android.tools.r8.graph.DexProgramClass;
 import com.android.tools.r8.shaking.Enqueuer;
 import com.android.tools.r8.shaking.EnqueuerWorklist;
+import com.android.tools.r8.utils.Timing;
 
 public abstract class EnqueuerAnalysis {
 
@@ -28,7 +29,7 @@
    * Called when the Enqueuer reaches a fixpoint. This may happen multiple times, since each
    * analysis may enqueue items into the worklist upon the fixpoint using {@param worklist}.
    */
-  public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist) {}
+  public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist, Timing timing) {}
 
   /**
    * Called when the Enqueuer has reached the final fixpoint. Each analysis may use this callback to
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
index e540a06..3e96616 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -30,6 +30,7 @@
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoCollection;
 import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Timing;
 
 public class InstanceFieldValueAnalysis extends FieldValueAnalysis {
 
@@ -66,6 +67,20 @@
       IRCode code,
       ClassInitializerDefaultsResult classInitializerDefaultsResult,
       OptimizationFeedback feedback,
+      DexEncodedMethod method,
+      Timing timing) {
+    timing.begin("Analyze instance initializer");
+    InstanceFieldInitializationInfoCollection result =
+        run(appView, code, classInitializerDefaultsResult, feedback, method);
+    timing.end();
+    return result;
+  }
+
+  private static InstanceFieldInitializationInfoCollection run(
+      AppView<?> appView,
+      IRCode code,
+      ClassInitializerDefaultsResult classInitializerDefaultsResult,
+      OptimizationFeedback feedback,
       DexEncodedMethod method) {
     assert appView.appInfo().hasLiveness();
     assert appView.enableWholeProgramOptimizations();
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 10dd287..f467406 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -29,6 +29,7 @@
 import com.android.tools.r8.ir.optimize.ClassInitializerDefaultsOptimization.ClassInitializerDefaultsResult;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Timing;
 
 public class StaticFieldValueAnalysis extends FieldValueAnalysis {
 
@@ -46,13 +47,16 @@
       IRCode code,
       ClassInitializerDefaultsResult classInitializerDefaultsResult,
       OptimizationFeedback feedback,
-      DexEncodedMethod method) {
+      DexEncodedMethod method,
+      Timing timing) {
     assert appView.appInfo().hasLiveness();
     assert appView.enableWholeProgramOptimizations();
     assert method.isClassInitializer();
+    timing.begin("Analyze class initializer");
     DexProgramClass clazz = appView.definitionFor(method.method.holder).asProgramClass();
     new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback, clazz, method)
         .computeFieldOptimizationInfo(classInitializerDefaultsResult);
+    timing.end();
   }
 
   @Override
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
index 4de5c39..2a70440 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedExtensionRegistryShrinker.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.shaking.TreePrunerConfiguration;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.Timing;
 import com.google.common.base.Predicates;
 import com.google.common.collect.Sets;
 import java.io.IOException;
@@ -155,13 +156,15 @@
     return removedExtensionFields.contains(field);
   }
 
-  public void postOptimizeGeneratedExtensionRegistry(IRConverter converter) {
+  public void postOptimizeGeneratedExtensionRegistry(IRConverter converter, Timing timing) {
+    timing.begin("[Proto] Post optimize generated extension registry");
     forEachFindLiteExtensionByNumberMethod(
         method ->
             converter.processMethod(
                 method,
                 OptimizationFeedbackIgnore.getInstance(),
                 OneTimeMethodProcessor.getInstance()));
+    timing.end(); // [Proto] Post optimize generated extension registry
   }
 
   private void forEachFindLiteExtensionByNumberMethod(Consumer<DexEncodedMethod> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
index cc7307f..b7ceccf 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteShrinker.java
@@ -32,6 +32,7 @@
 import com.android.tools.r8.ir.conversion.OneTimeMethodProcessor;
 import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackIgnore;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Timing;
 import java.util.List;
 import java.util.function.Consumer;
 
@@ -69,13 +70,15 @@
     }
   }
 
-  public void postOptimizeDynamicMethods(IRConverter converter) {
+  public void postOptimizeDynamicMethods(IRConverter converter, Timing timing) {
+    timing.begin("[Proto] Post optimize dynamic methods");
     forEachDynamicMethod(
         method ->
             converter.processMethod(
                 method,
                 OptimizationFeedbackIgnore.getInstance(),
                 OneTimeMethodProcessor.getInstance()));
+    timing.end();
   }
 
   private void forEachDynamicMethod(Consumer<DexEncodedMethod> consumer) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
index bf6c8b1..e2837c4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/schema/ProtoEnqueuerExtension.java
@@ -37,6 +37,7 @@
 import com.android.tools.r8.shaking.KeepReason;
 import com.android.tools.r8.utils.BitUtils;
 import com.android.tools.r8.utils.OptionalBool;
+import com.android.tools.r8.utils.Timing;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Sets;
 import java.util.IdentityHashMap;
@@ -171,7 +172,8 @@
   }
 
   @Override
-  public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist) {
+  public void notifyFixpoint(Enqueuer enqueuer, EnqueuerWorklist worklist, Timing timing) {
+    timing.begin("[Proto] Extend fixpoint");
     populateExtensionGraph(enqueuer);
 
     markMapOrRequiredFieldsAsReachable(enqueuer, worklist);
@@ -187,6 +189,7 @@
         tracePendingInstructionsInDynamicMethods(enqueuer, worklist);
       }
     }
+    timing.end();
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index d968d31..a0934cd 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -1599,15 +1599,20 @@
     if (method.isInitializer()) {
       if (method.isClassInitializer()) {
         StaticFieldValueAnalysis.run(
-            appView, code, classInitializerDefaultsResult, feedback, code.method);
+            appView, code, classInitializerDefaultsResult, feedback, code.method, timing);
       } else {
         instanceFieldInitializationInfos =
             InstanceFieldValueAnalysis.run(
-                appView, code, classInitializerDefaultsResult, feedback, code.method);
+                appView, code, classInitializerDefaultsResult, feedback, code.method, timing);
       }
     }
     methodOptimizationInfoCollector.collectMethodOptimizationInfo(
-        code.method, code, feedback, dynamicTypeOptimization, instanceFieldInitializationInfos);
+        code.method,
+        code,
+        feedback,
+        dynamicTypeOptimization,
+        instanceFieldInitializationInfos,
+        timing);
   }
 
   public void removeDeadCodeAndFinalizeIR(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index bbf2f22..05e6fa5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -95,6 +95,7 @@
 import com.android.tools.r8.utils.ListUtils;
 import com.android.tools.r8.utils.MethodSignatureEquivalence;
 import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.Timing;
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.base.Equivalence.Wrapper;
 import com.google.common.collect.Sets;
@@ -123,20 +124,29 @@
       IRCode code,
       OptimizationFeedback feedback,
       DynamicTypeOptimization dynamicTypeOptimization,
-      InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
-    identifyClassInlinerEligibility(method, code, feedback);
-    identifyParameterUsages(method, code, feedback);
-    identifyReturnsArgument(method, code, feedback);
+      InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos,
+      Timing timing) {
+    identifyClassInlinerEligibility(method, code, feedback, timing);
+    identifyParameterUsages(method, code, feedback, timing);
+    identifyReturnsArgument(method, code, feedback, timing);
     if (options.enableInlining) {
-      identifyInvokeSemanticsForInlining(method, code, appView, feedback);
+      identifyInvokeSemanticsForInlining(method, code, feedback, timing);
     }
-    computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code);
-    computeInitializedClassesOnNormalExit(feedback, method, code);
-    computeInstanceInitializerInfo(method, code, feedback, instanceFieldInitializationInfos);
-    computeMayHaveSideEffects(feedback, method, code);
-    computeReturnValueOnlyDependsOnArguments(feedback, method, code);
-    computeNonNullParamOrThrow(feedback, method, code);
-    computeNonNullParamOnNormalExits(feedback, code);
+    computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code, timing);
+    computeInitializedClassesOnNormalExit(feedback, method, code, timing);
+    computeInstanceInitializerInfo(
+        method, code, feedback, instanceFieldInitializationInfos, timing);
+    computeMayHaveSideEffects(feedback, method, code, timing);
+    computeReturnValueOnlyDependsOnArguments(feedback, method, code, timing);
+    computeNonNullParamOrThrow(feedback, method, code, timing);
+    computeNonNullParamOnNormalExits(feedback, code, timing);
+  }
+
+  private void identifyClassInlinerEligibility(
+      DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+    timing.begin("Identify class inliner eligibility");
+    identifyClassInlinerEligibility(method, code, feedback);
+    timing.end();
   }
 
   private void identifyClassInlinerEligibility(
@@ -283,6 +293,13 @@
   }
 
   private void identifyParameterUsages(
+      DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+    timing.begin("Identify parameter usages");
+    identifyParameterUsages(method, code, feedback);
+    timing.end();
+  }
+
+  private void identifyParameterUsages(
       DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     List<ParameterUsage> usages = new ArrayList<>();
     List<Value> values = code.collectArguments();
@@ -322,6 +339,13 @@
   }
 
   private void identifyReturnsArgument(
+      DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+    timing.begin("Identify returns argument");
+    identifyReturnsArgument(method, code, feedback);
+    timing.end();
+  }
+
+  private void identifyReturnsArgument(
       DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     List<BasicBlock> normalExits = code.computeNormalExitBlocks();
     if (normalExits.isEmpty()) {
@@ -365,6 +389,17 @@
       DexEncodedMethod method,
       IRCode code,
       OptimizationFeedback feedback,
+      InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos,
+      Timing timing) {
+    timing.begin("Compute instance initializer info");
+    computeInstanceInitializerInfo(method, code, feedback, instanceFieldInitializationInfos);
+    timing.end();
+  }
+
+  private void computeInstanceInitializerInfo(
+      DexEncodedMethod method,
+      IRCode code,
+      OptimizationFeedback feedback,
       InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos) {
     assert !appView.appInfo().isPinned(method.method);
 
@@ -641,7 +676,14 @@
   }
 
   private void identifyInvokeSemanticsForInlining(
-      DexEncodedMethod method, IRCode code, AppView<?> appView, OptimizationFeedback feedback) {
+      DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
+    timing.begin("Identify invoke semantics for inlining");
+    identifyInvokeSemanticsForInlining(method, code, feedback);
+    timing.end();
+  }
+
+  private void identifyInvokeSemanticsForInlining(
+      DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
     if (method.isStatic()) {
       // Identifies if the method preserves class initialization after inlining.
       feedback.markTriggerClassInitBeforeAnySideEffect(
@@ -899,6 +941,17 @@
       DynamicTypeOptimization dynamicTypeOptimization,
       OptimizationFeedback feedback,
       DexEncodedMethod method,
+      IRCode code,
+      Timing timing) {
+    timing.begin("Compute dynamic return type");
+    computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code);
+    timing.end();
+  }
+
+  private void computeDynamicReturnType(
+      DynamicTypeOptimization dynamicTypeOptimization,
+      OptimizationFeedback feedback,
+      DexEncodedMethod method,
       IRCode code) {
     if (dynamicTypeOptimization != null) {
       DexType staticReturnTypeRaw = method.method.proto.returnType;
@@ -925,6 +978,13 @@
   }
 
   private void computeInitializedClassesOnNormalExit(
+      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code, Timing timing) {
+    timing.begin("Compute initialized classes on normal exits");
+    computeInitializedClassesOnNormalExit(feedback, method, code);
+    timing.end();
+  }
+
+  private void computeInitializedClassesOnNormalExit(
       OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
     if (options.enableInitializedClassesAnalysis && appView.appInfo().hasLiveness()) {
       AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
@@ -938,6 +998,13 @@
   }
 
   private void computeMayHaveSideEffects(
+      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code, Timing timing) {
+    timing.begin("Compute may have side effects");
+    computeMayHaveSideEffects(feedback, method, code);
+    timing.end();
+  }
+
+  private void computeMayHaveSideEffects(
       OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
     // If the method is native, we don't know what could happen.
     assert !method.accessFlags.isNative();
@@ -1018,6 +1085,13 @@
   }
 
   private void computeReturnValueOnlyDependsOnArguments(
+      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code, Timing timing) {
+    timing.begin("Return value only depends on argument");
+    computeReturnValueOnlyDependsOnArguments(feedback, method, code);
+    timing.end();
+  }
+
+  private void computeReturnValueOnlyDependsOnArguments(
       OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
     if (!options.enableDeterminismAnalysis) {
       return;
@@ -1029,6 +1103,13 @@
     }
   }
 
+  private void computeNonNullParamOrThrow(
+      OptimizationFeedback feedback, DexEncodedMethod method, IRCode code, Timing timing) {
+    timing.begin("Compute non-null-param-or-throw");
+    computeReturnValueOnlyDependsOnArguments(feedback, method, code);
+    timing.end();
+  }
+
   // Track usage of parameters and compute their nullability and possibility of NPE.
   private void computeNonNullParamOrThrow(
       OptimizationFeedback feedback, DexEncodedMethod method, IRCode code) {
@@ -1058,6 +1139,13 @@
     }
   }
 
+  private void computeNonNullParamOnNormalExits(
+      OptimizationFeedback feedback, IRCode code, Timing timing) {
+    timing.begin("Compute non-null-param-on-normal-exits");
+    computeNonNullParamOnNormalExits(feedback, code, timing);
+    timing.end();
+  }
+
   private void computeNonNullParamOnNormalExits(OptimizationFeedback feedback, IRCode code) {
     Set<BasicBlock> normalExits = Sets.newIdentityHashSet();
     normalExits.addAll(code.computeNormalExitBlocks());
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 2bc230c..1dd374d 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2893,7 +2893,7 @@
 
         // Notify each analysis that a fixpoint has been reached, and give each analysis an
         // opportunity to add items to the worklist.
-        analyses.forEach(analysis -> analysis.notifyFixpoint(this, workList));
+        analyses.forEach(analysis -> analysis.notifyFixpoint(this, workList, timing));
         if (!workList.isEmpty()) {
           continue;
         }