Add support for printtimes in R8 partial

Fixes: b/388737731
Change-Id: Iae21765701892cb11b34721c03c45240ec60b108
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index ae6a649..cfa7aa6 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -201,7 +201,7 @@
       System.out.println("D8 is running with free memory:" + runtime.freeMemory());
       System.out.println("D8 is running with max memory:" + runtime.maxMemory());
     }
-    Timing timing = Timing.create("D8 " + Version.LABEL, options);
+    Timing timing = Timing.createRoot("D8 " + Version.LABEL, options);
     try {
       timing.begin("Pre conversion");
       // Synthetic assertion to check that testing assertions works and can be enabled.
@@ -340,7 +340,7 @@
       inputApp.signalFinishedToProviders(options.reporter);
       options.signalFinishedToConsumers();
       // Dump timings.
-      if (options.printTimes) {
+      if (options.isPrintTimesReportingEnabled()) {
         timing.report();
       }
     }
diff --git a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
index f0445dd..02eca77 100644
--- a/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
+++ b/src/main/java/com/android/tools/r8/GlobalSyntheticsGenerator.java
@@ -144,7 +144,7 @@
             } finally {
               options.signalFinishedToConsumers();
               // Dump timings.
-              if (options.printTimes) {
+              if (options.isPrintTimesReportingEnabled()) {
                 timing.report();
               }
             }
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index 62fe407..e90d5fc 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -155,7 +155,7 @@
       inputApp.signalFinishedToProviders(options.reporter);
       options.signalFinishedToConsumers();
       // Dump timings.
-      if (options.printTimes) {
+      if (options.isPrintTimesReportingEnabled()) {
         timing.report();
       }
     }
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index bea277e..a499d54 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -177,7 +177,7 @@
     if (options.printMemory) {
       System.gc();
     }
-    timing = Timing.create("R8 " + Version.LABEL, options);
+    timing = Timing.createRoot("R8 " + Version.LABEL, options);
   }
 
   /**
@@ -892,7 +892,7 @@
 
       options.printWarnings();
 
-      if (options.printTimes) {
+      if (options.isPrintTimesReportingEnabled()) {
         timing.report();
       }
     } catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/R8Partial.java b/src/main/java/com/android/tools/r8/R8Partial.java
index c5a573f..b4d257f 100644
--- a/src/main/java/com/android/tools/r8/R8Partial.java
+++ b/src/main/java/com/android/tools/r8/R8Partial.java
@@ -58,6 +58,7 @@
   private final Consumer<AndroidApp> d8InputAppConsumer;
   private final Consumer<AndroidApp> r8OutputAppConsumer;
   private final Consumer<AndroidApp> d8OutputAppConsumer;
+  private final Timing timing;
 
   R8Partial(InternalOptions options) {
     this.options = options;
@@ -65,6 +66,7 @@
     this.d8InputAppConsumer = options.partialCompilationConfiguration.d8InputAppConsumer;
     this.r8OutputAppConsumer = options.partialCompilationConfiguration.r8OutputAppConsumer;
     this.d8OutputAppConsumer = options.partialCompilationConfiguration.d8OutputAppConsumer;
+    this.timing = Timing.create("R8 partial " + Version.LABEL, options);
   }
 
   static void runForTesting(AndroidApp app, InternalOptions options)
@@ -82,27 +84,44 @@
   }
 
   void runInternal(AndroidApp app, ExecutorService executor) throws IOException, ResourceException {
-    Timing timing = Timing.create("R8 partial " + Version.LABEL, options);
     if (!(options.programConsumer instanceof DexIndexedConsumer)) {
       throw options.reporter.fatalError(
           "Partial shrinking does not support generating class files");
     }
 
-    R8PartialInput input = runProcessInputStep(app, timing);
+    timing.begin("Process input");
+    R8PartialInput input = runProcessInputStep(app);
+
+    timing.end().begin("Run D8 dexing");
     R8PartialD8DexResult d8DexResult = runD8DexStep(input, executor);
+
+    timing.end().begin("Run trace resources");
     R8PartialTraceResourcesResult traceResourcesResult = runTraceResourcesStep(d8DexResult);
+
+    timing.end().begin("Run D8 desugaring");
     R8PartialDesugarResult desugarResult = runDesugarStep(input, executor);
+
+    timing.end().begin("Run trace references");
     R8PartialTraceReferencesResult traceReferencesResult =
         runTraceReferencesStep(input, desugarResult);
+
+    timing.end().begin("Run R8");
     R8PartialR8Result r8Result =
         runR8PartialStep(
             input, desugarResult, traceReferencesResult, traceResourcesResult, executor);
+
+    timing.end().begin("Run D8 merging");
     runD8MergeStep(input, d8DexResult, r8Result, executor);
 
     // Feed the data resource output by R8 to the output consumer. Keeping this at the end after the
     // merge keeps the order of calls to the output consumer closer to full R8.
+    timing.end().begin("Supply consumers");
     r8Result.supplyConsumers(options);
     timing.end();
+
+    if (options.isPrintTimesReportingEnabled()) {
+      timing.report();
+    }
   }
 
   private R8PartialTraceResourcesResult runTraceResourcesStep(R8PartialD8DexResult d8DexResult)
@@ -121,8 +140,7 @@
     return new R8PartialTraceResourcesResult(resourceTracingCallback.getPotentialIds());
   }
 
-  private R8PartialInput runProcessInputStep(AndroidApp androidApp, Timing timing)
-      throws IOException {
+  private R8PartialInput runProcessInputStep(AndroidApp androidApp) throws IOException {
     // Create a dump of the compiler input.
     // TODO(b/309743298): Do not use compiler dump to handle splitting the compilation. This should
     //  be all in memory.
@@ -201,7 +219,8 @@
     }
     InternalOptions d8Options = d8Command.getInternalOptions();
     options.partialCompilationConfiguration.d8DexOptionsConsumer.accept(d8Options);
-    d8Options.partialSubCompilationConfiguration = new R8PartialD8SubCompilationConfiguration();
+    d8Options.partialSubCompilationConfiguration =
+        new R8PartialD8SubCompilationConfiguration(timing);
     D8.runInternal(d8App, d8Options, executor);
     if (d8OutputAppConsumer != null) {
       d8OutputAppConsumer.accept(d8OutputAppSink.build());
@@ -227,7 +246,8 @@
     AndroidApp d8App = d8Command.getInputApp();
     InternalOptions d8Options = d8Command.getInternalOptions();
     options.partialCompilationConfiguration.d8DesugarOptionsConsumer.accept(d8Options);
-    d8Options.partialSubCompilationConfiguration = new R8PartialD8SubCompilationConfiguration();
+    d8Options.partialSubCompilationConfiguration =
+        new R8PartialD8SubCompilationConfiguration(timing);
     D8.runInternal(d8App, d8Options, executor);
     return new R8PartialDesugarResult(desugarOutput);
   }
@@ -302,7 +322,8 @@
     InternalOptions r8Options = r8Command.getInternalOptions();
     options.partialCompilationConfiguration.r8OptionsConsumer.accept(r8Options);
     r8Options.partialSubCompilationConfiguration =
-        new R8PartialR8SubCompilationConfiguration(traceResourcesResult.getResourceIdsToTrace());
+        new R8PartialR8SubCompilationConfiguration(
+            traceResourcesResult.getResourceIdsToTrace(), timing);
     r8Options.mapConsumer = options.mapConsumer;
     if (options.androidResourceProvider != null) {
       r8Options.androidResourceProvider = options.androidResourceProvider;
@@ -333,7 +354,8 @@
     AndroidApp mergeApp = mergeCommand.getInputApp();
     InternalOptions mergeOptions = mergeCommand.getInternalOptions();
     options.partialCompilationConfiguration.d8MergeOptionsConsumer.accept(mergeOptions);
-    mergeOptions.partialSubCompilationConfiguration = new R8PartialD8SubCompilationConfiguration();
+    mergeOptions.partialSubCompilationConfiguration =
+        new R8PartialD8SubCompilationConfiguration(timing);
     D8.runInternal(mergeApp, mergeOptions, executor);
   }
 
diff --git a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
index ee13cc8..1276fcf 100644
--- a/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
+++ b/src/main/java/com/android/tools/r8/partial/R8PartialSubCompilationConfiguration.java
@@ -3,11 +3,18 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.partial;
 
+import com.android.tools.r8.utils.Timing;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import it.unimi.dsi.fastutil.ints.IntSets;
 
 public abstract class R8PartialSubCompilationConfiguration {
 
+  public final Timing timing;
+
+  R8PartialSubCompilationConfiguration(Timing timing) {
+    this.timing = timing;
+  }
+
   public IntSet getD8TracedResourceIds() {
     return IntSets.EMPTY_SET;
   }
@@ -18,14 +25,20 @@
 
   // Currently shared by all D8 compilations in R8 partial (i.e., dexing, desugaring, merging).
   public static class R8PartialD8SubCompilationConfiguration
-      extends R8PartialSubCompilationConfiguration {}
+      extends R8PartialSubCompilationConfiguration {
+
+    public R8PartialD8SubCompilationConfiguration(Timing timing) {
+      super(timing);
+    }
+  }
 
   public static class R8PartialR8SubCompilationConfiguration
       extends R8PartialSubCompilationConfiguration {
 
-    public final IntSet d8TracedResourceIds;
+    private final IntSet d8TracedResourceIds;
 
-    public R8PartialR8SubCompilationConfiguration(IntSet d8TracedResourceIds) {
+    public R8PartialR8SubCompilationConfiguration(IntSet d8TracedResourceIds, Timing timing) {
+      super(timing);
       this.d8TracedResourceIds = d8TracedResourceIds;
     }
 
diff --git a/src/main/java/com/android/tools/r8/relocator/Relocator.java b/src/main/java/com/android/tools/r8/relocator/Relocator.java
index d74a6e9..972edee 100644
--- a/src/main/java/com/android/tools/r8/relocator/Relocator.java
+++ b/src/main/java/com/android/tools/r8/relocator/Relocator.java
@@ -90,7 +90,7 @@
       inputApp.signalFinishedToProviders(options.reporter);
       options.signalFinishedToConsumers();
       // Dump timings.
-      if (options.printTimes) {
+      if (options.isPrintTimesReportingEnabled()) {
         timing.report();
       }
     }
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 09c90d1..da5cbd5 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -382,6 +382,10 @@
   // To print memory one also have to enable printtimes.
   public boolean printMemory = System.getProperty("com.android.tools.r8.printmemory") != null;
 
+  public boolean isPrintTimesReportingEnabled() {
+    return printTimes && partialSubCompilationConfiguration == null;
+  }
+
   // TODO(b/340669208): Figure out if this should be default behavior.
   public boolean ensureJvmCompatibleStepOutBehavior =
       System.getProperty("com.android.tools.r8.enableJvmCompatibleStepOutBehavior") != null
diff --git a/src/main/java/com/android/tools/r8/utils/Timing.java b/src/main/java/com/android/tools/r8/utils/Timing.java
index 7e4a8e1..d89ac01 100644
--- a/src/main/java/com/android/tools/r8/utils/Timing.java
+++ b/src/main/java/com/android/tools/r8/utils/Timing.java
@@ -59,8 +59,9 @@
         }
 
         @Override
-        public void end() {
+        public Timing end() {
           // Ignore.
+          return this;
         }
 
         @Override
@@ -103,8 +104,9 @@
     }
 
     @Override
-    public void end() {
+    public Timing end() {
       timing.end();
+      return this;
     }
 
     @Override
@@ -130,6 +132,13 @@
     }
   }
 
+  public static Timing createRoot(String title, InternalOptions options) {
+    if (options.partialSubCompilationConfiguration != null) {
+      return options.partialSubCompilationConfiguration.timing;
+    }
+    return create(title, options);
+  }
+
   public static Timing create(String title, InternalOptions options) {
     // We also create a timer when running assertions to validate wellformedness of the node stack.
     Timing timing =
@@ -493,9 +502,10 @@
     end();
   }
 
-  public void end() {
+  public Timing end() {
     stack.peek().end();  // record time.
     stack.pop();
+    return this;
   }
 
   public void report() {