Record time spent in individual Error Prone checks
PiperOrigin-RevId: 245821511
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/errorprone/ErrorPronePlugin.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/errorprone/ErrorPronePlugin.java
index 18c3fac..df46c38 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/errorprone/ErrorPronePlugin.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/plugins/errorprone/ErrorPronePlugin.java
@@ -14,11 +14,14 @@
package com.google.devtools.build.buildjar.javac.plugins.errorprone;
+import static java.util.Comparator.comparing;
+
+import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.buildjar.InvalidCommandLineException;
import com.google.devtools.build.buildjar.javac.plugins.BlazeJavaCompilerPlugin;
import com.google.devtools.build.buildjar.javac.statistics.BlazeJavacStatistics;
-import com.google.devtools.build.buildjar.javac.statistics.BlazeJavacStatistics.StopwatchSpan;
import com.google.errorprone.BaseErrorProneJavaCompiler;
import com.google.errorprone.ErrorProneAnalyzer;
import com.google.errorprone.ErrorProneError;
@@ -33,8 +36,10 @@
import com.sun.tools.javac.main.JavaCompiler;
import com.sun.tools.javac.util.Context;
import com.sun.tools.javac.util.Log;
+import java.time.Duration;
import java.util.Arrays;
import java.util.List;
+import java.util.Map;
/**
* A plugin for BlazeJavaCompiler that performs Error Prone analysis. Error Prone is a static
@@ -62,6 +67,51 @@
private ErrorProneAnalyzer errorProneAnalyzer;
private ErrorProneOptions epOptions;
+ private ErrorProneTimings timings;
+ private final Stopwatch elapsed = Stopwatch.createUnstarted();
+
+ // TODO(cushon): delete this shim after the next Error Prone update
+ static class ErrorProneTimings {
+ static Class<?> clazz;
+
+ static {
+ try {
+ clazz = Class.forName("com.google.errorprone.ErrorProneTimings");
+ } catch (ClassNotFoundException e) {
+ // ignored
+ }
+ }
+
+ private final Object instance;
+
+ public ErrorProneTimings(Object instance) {
+ this.instance = instance;
+ }
+
+ public static ErrorProneTimings instance(Context context) {
+ Object instance = null;
+ if (clazz != null) {
+ try {
+ instance = clazz.getMethod("instance", Context.class).invoke(null, context);
+ } catch (ReflectiveOperationException e) {
+ throw new LinkageError(e.getMessage(), e);
+ }
+ }
+ return new ErrorProneTimings(instance);
+ }
+
+ @SuppressWarnings("unchecked") // reflection
+ public Map<String, Duration> timings() {
+ if (clazz == null) {
+ return ImmutableMap.of();
+ }
+ try {
+ return (Map<String, Duration>) clazz.getMethod("timings").invoke(instance);
+ } catch (ReflectiveOperationException e) {
+ throw new LinkageError(e.getMessage(), e);
+ }
+ }
+ }
/** Registers our message bundle. */
public static void setupMessageBundle(Context context) {
@@ -108,22 +158,31 @@
}
errorProneAnalyzer =
ErrorProneAnalyzer.createByScanningForPlugins(scannerSupplier, epOptions, context);
+ timings = ErrorProneTimings.instance(context);
}
/** Run Error Prone analysis after performing dataflow checks. */
@Override
public void postFlow(Env<AttrContext> env) {
- try (StopwatchSpan ignored =
- statisticsBuilder.newTimingSpan(
- duration ->
- statisticsBuilder.addErrorProneTiming(
- env.toplevel.sourcefile.getName(), duration))) {
+ elapsed.start();
+ try {
errorProneAnalyzer.finished(new TaskEvent(Kind.ANALYZE, env.toplevel, env.enclClass.sym));
} catch (ErrorProneError e) {
e.logFatalError(log);
// let the exception propagate to javac's main, where it will cause the compilation to
// terminate with Result.ABNORMAL
throw e;
+ } finally {
+ elapsed.stop();
}
}
+
+ @Override
+ public void finish() {
+ statisticsBuilder.totalErrorProneTime(elapsed.elapsed());
+ timings.timings().entrySet().stream()
+ .sorted(comparing((Map.Entry<String, Duration> e) -> e.getValue()).reversed())
+ .limit(10) // best-effort to stay under the action metric size limit
+ .forEachOrdered((e) -> statisticsBuilder.addBugpatternTiming(e.getKey(), e.getValue()));
+ }
}
diff --git a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/statistics/BlazeJavacStatistics.java b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/statistics/BlazeJavacStatistics.java
index 4ba80b3..5f09b30 100644
--- a/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/statistics/BlazeJavacStatistics.java
+++ b/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/javac/statistics/BlazeJavacStatistics.java
@@ -14,17 +14,14 @@
package com.google.devtools.build.buildjar.javac.statistics;
import com.google.auto.value.AutoValue;
-import com.google.common.base.Stopwatch;
-import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
-import com.google.errorprone.annotations.MustBeClosed;
import com.sun.tools.javac.util.Context;
import java.time.Duration;
import java.util.Collections;
+import java.util.Optional;
import java.util.Set;
import java.util.WeakHashMap;
-import java.util.function.Consumer;
/**
* A class representing statistics for an invocation of {@link
@@ -68,7 +65,9 @@
public abstract ImmutableMap<AuxiliaryDataSource, byte[]> auxiliaryData();
- public abstract ImmutableListMultimap<String, Duration> errorProneTicks();
+ public abstract Optional<Duration> totalErrorProneTime();
+
+ public abstract ImmutableMap<String, Duration> bugpatternTiming();
public abstract ImmutableSet<String> processors();
@@ -103,7 +102,9 @@
@AutoValue.Builder
public abstract static class Builder {
- abstract ImmutableListMultimap.Builder<String, Duration> errorProneTicksBuilder();
+ public abstract Builder totalErrorProneTime(Duration totalErrorProneTime);
+
+ abstract ImmutableMap.Builder<String, Duration> bugpatternTimingBuilder();
abstract ImmutableMap.Builder<AuxiliaryDataSource, byte[]> auxiliaryDataBuilder();
@@ -117,8 +118,8 @@
public abstract Builder transitiveClasspathFallback(boolean fallback);
- public Builder addErrorProneTiming(String key, Duration value) {
- errorProneTicksBuilder().put(key, value);
+ public Builder addBugpatternTiming(String key, Duration value) {
+ bugpatternTimingBuilder().put(key, value);
return this;
}
@@ -138,28 +139,9 @@
return this;
}
- @MustBeClosed
- public final StopwatchSpan newTimingSpan(Consumer<Duration> consumer) {
- Stopwatch stopwatch = Stopwatch.createStarted();
- return () -> {
- stopwatch.stop();
- consumer.accept(stopwatch.elapsed());
- };
- }
-
public Builder addProcessor(String processor) {
processorsBuilder().add(processor);
return this;
}
}
-
- /**
- * A simple AutoClosable interface where the {@link #close} method doesn't throw an exception.
- *
- * <p>Returned from {@link Builder#newTimingSpan(Consumer)}
- */
- public interface StopwatchSpan extends AutoCloseable {
- @Override
- void close();
- }
}