Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Speed up Refaster bug checker #261

Draft
wants to merge 55 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
55 commits
Select commit Hold shift + click to select a range
69386f0
Emit website link along with Refaster refactor suggestions
Stephan202 Sep 21, 2022
84061fc
More extensible approach
Stephan202 Sep 22, 2022
827880b
WIP: Some plumbing for annotation support
Stephan202 Sep 22, 2022
0f44844
Another round
Stephan202 Sep 22, 2022
0e46f9c
Tweaks
Stephan202 Sep 23, 2022
914d30a
Better annotation support, simplify setup
Stephan202 Sep 23, 2022
458fb99
Flag why build currently doesn't fail, while it should.
Stephan202 Sep 23, 2022
db8cf3c
Improve logic and test coverage
Stephan202 Sep 24, 2022
abb6cea
Properly document URL placeholder usage
Stephan202 Sep 24, 2022
cf772c4
Expand test coverage
Stephan202 Sep 24, 2022
d26bc18
Flag classpath issue
Stephan202 Sep 25, 2022
01b7e5b
Improve text and minor improvements
rickie Sep 27, 2022
3482641
Use `@AutoValue` for the `AnnotatedCompositeCodeTransformer`
rickie Sep 29, 2022
12d09ad
Support `AllSuggestionsAsWarnings` and add a suggestion
rickie Sep 29, 2022
74d6c9a
Tweak
rickie Sep 29, 2022
c4b6a5f
Suggestions, introduce `ErrorProneFork`
Stephan202 Sep 29, 2022
d899a8a
Also this
Stephan202 Sep 29, 2022
20d194b
Clarify how the default Refaster hit severity comes to be
Stephan202 Sep 30, 2022
ad1c98d
Align documentation of reported description names by the Refaster check
Badbond Sep 30, 2022
50443d1
Suggestion
Badbond Sep 30, 2022
7e49b08
Pass null for urlLink to Description.Builder
Badbond Sep 30, 2022
594f51c
Tweaks
Stephan202 Sep 30, 2022
e6caceb
Move `AnnotatedCompositeCodeTransformer` and `ErrorProneFork` to `ref…
rickie Oct 4, 2022
b2ef631
`s/information/content/`
rickie Oct 4, 2022
8bd88bb
Improve Javadoc `AnnotatedCompositeCodeTransformer`
rickie Oct 4, 2022
302e20b
Revert changes in `OptionalTemplates`
rickie Oct 4, 2022
32300ff
Tweak `AnnotatedCompositeCodeTransformer` Javadoc
Badbond Oct 4, 2022
d21ac59
Apply `StringJoin` suggestion
Stephan202 Oct 7, 2022
0484762
Suggestions
Stephan202 Oct 8, 2022
1624ebf
WIP: Speed up `Refaster` check
Stephan202 May 1, 2022
ee74279
Compatibility with stock Error Prone
Stephan202 Sep 12, 2022
344f4e4
Initial copy over of the improved algorithm
rickie Sep 23, 2022
6739cb4
Improve code and algorithm for Refaster
rickie Sep 23, 2022
72ff8ae
Drop unnecessary `@AutoService` annotation
rickie Sep 23, 2022
39dc9aa
Add XXXs
rickie Sep 23, 2022
2a93011
Merge `RefasterRuleSelector` type hierarchy
Stephan202 Sep 25, 2022
1c5077f
Create selector only once per `Refaster` instantiation
Stephan202 Sep 25, 2022
2c137c0
Move all `RefasterRuleSelector` construction logic into the relevant …
Stephan202 Sep 25, 2022
c3a5106
Push sorting requirements into `Node`, minimize tree, add tests
Stephan202 Sep 25, 2022
9151287
Suggestion
rickie Sep 27, 2022
a27d635
Extract the `TreeScanner`s to their own classes
rickie Sep 27, 2022
2003bd2
Introduce `getClass` method to deduplicate
rickie Sep 27, 2022
7889148
Reorder methods in `RefasterIntrospection`
rickie Sep 27, 2022
afdcf52
Apply some suggestions
Stephan202 Sep 30, 2022
ab03739
Optimize code, introduce benchmark, simplify test
Stephan202 Oct 1, 2022
457a8e2
Comment style, explain both performance-only pieces of code
Stephan202 Oct 2, 2022
63ad14e
Fix typo
rickie Oct 4, 2022
0cf891c
Suggestions
ibabiankou Oct 7, 2022
2cb4bd0
Suggestions
Stephan202 Oct 8, 2022
c34fa4d
Fix typo
rickie Oct 9, 2022
d59b626
Merge remote-tracking branch 'origin/sschroevers/refaster-custom-urls…
Stephan202 Oct 9, 2022
5ba7075
Introduce `AnnotatedCompositeCodeTransformerTest`
Stephan202 Oct 9, 2022
0157692
Merge remote-tracking branch 'origin/sschroevers/refaster-custom-urls…
Stephan202 Oct 9, 2022
72f8881
Suggestions
Stephan202 Oct 9, 2022
77bc107
Merge branch 'master' into sschroevers/refaster-speed-up
Stephan202 Dec 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 101 additions & 13 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,12 @@
<version.error-prone-fork>v${version.error-prone-orig}-picnic-1</version.error-prone-fork>
<version.error-prone-orig>2.24.0</version.error-prone-orig>
<version.jdk>11</version.jdk>
<version.jmh>1.37</version.jmh>
<version.maven>3.8.7</version.maven>
<!-- XXX: Consider providing our own implementation with similar
functionality, and designing it such that JMH classes would not need to
be annotated `@Open`. -->
<version.nopen>1.0.1</version.nopen>
<version.pitest-git>1.1.4</version.pitest-git>
</properties>

Expand Down Expand Up @@ -322,10 +327,15 @@
<artifactId>truth</artifactId>
<version>1.2.0</version>
</dependency>
<dependency>
<groupId>com.jakewharton.nopen</groupId>
<artifactId>nopen-annotations</artifactId>
<version>${version.nopen}</version>
</dependency>
<dependency>
<groupId>com.jakewharton.nopen</groupId>
<artifactId>nopen-checker</artifactId>
<version>1.0.1</version>
<version>${version.nopen}</version>
</dependency>
<dependency>
<groupId>com.uber.nullaway</groupId>
Expand Down Expand Up @@ -451,6 +461,16 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>${version.jmh}</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>${version.jmh}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-bom</artifactId>
Expand Down Expand Up @@ -545,7 +565,6 @@
<configuration>
<bundledSignatures>
<bundledSignature>jdk-internal</bundledSignature>
<bundledSignature>jdk-reflection</bundledSignature>
<bundledSignature>jdk-system-out</bundledSignature>
<!-- Other bundles are available but currently not
enabled:
Expand All @@ -555,6 +574,10 @@
- jdk-deprecated: we compile with `-Xlint:all`,
which causes the build to fail when _any_
deprecated method is called.
- jdk-reflection: this bundle should probably be
enabled, but currently
`java.lang.reflect.AccessibleObject#setAccessible`
is still called in various places.
- jdk-non-portable: the Error Prone integration
crucially relies on some of these APIs.
- jdk-unsafe: see
Expand Down Expand Up @@ -887,10 +910,19 @@
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
</path>
<path>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value</artifactId>
<version>${version.auto-value}</version>
</path>
<path>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service</artifactId>
</path>
<path>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
</path>
</annotationProcessorPaths>
<compilerArgs>
<arg>--add-exports=jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED</arg>
Expand Down Expand Up @@ -1156,6 +1188,11 @@
<artifactId>build-helper-maven-plugin</artifactId>
<version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>3.1.1</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>license-maven-plugin</artifactId>
Expand Down Expand Up @@ -1230,6 +1267,7 @@
<!-- -->
GPL-2.0-with-classpath-exception
| CDDL/GPLv2+CE
| GNU General Public License (GPL), version 2, with the Classpath exception
| GNU General Public License, version 2 (GPL2), with the classpath exception
| GNU General Public License, version 2, with the Classpath Exception
| GPL2 w/ CPE
Expand Down Expand Up @@ -1438,17 +1476,6 @@
</rules>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<systemPropertyVariables>
<!-- Property used by `ErrorProneForkTest`
to verify fork identification. -->
<error-prone-fork-in-use>true</error-prone-fork-in-use>
</systemPropertyVariables>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
Expand Down Expand Up @@ -1942,5 +1969,66 @@
</plugins>
</build>
</profile>
<profile>
<!-- Enables execution of a JMH benchmark. Given a benchmark class
`tech.picnic.MyBenchmark`, the following command (executed against
the (sub)module in which the benchmark resides) will compile and
execute said benchmark:

mvn process-test-classes -Dverification.skip \
-Djmh.run-benchmark=tech.picnic.MyBenchmark
-->
<id>run-jmh-benchmark</id>
<activation>
<property>
<name>jmh.run-benchmark</name>
</property>
</activation>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>build-jmh-runtime-classpath</id>
<goals>
<goal>build-classpath</goal>
</goals>
<configuration>
<outputProperty>testClasspath</outputProperty>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<id>run-jmh-benchmark</id>
<goals>
<goal>java</goal>
</goals>
<phase>process-test-classes</phase>
<configuration>
<classpathScope>test</classpathScope>
<mainClass>${jmh.run-benchmark}</mainClass>
<systemProperties>
<!-- The runtime classpath is defined
in this way so that any JVMs forked by
JMH will have the desired classpath. -->
<systemProperty>
<key>java.class.path</key>
<value>${project.build.testOutputDirectory}${path.separator}${project.build.outputDirectory}${path.separator}${testClasspath}</value>
</systemProperty>
</systemProperties>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
25 changes: 24 additions & 1 deletion refaster-runner/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@
<artifactId>error_prone_check_api</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_core</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>${groupId.error-prone}</groupId>
<artifactId>error_prone_test_helpers</artifactId>
Expand All @@ -45,18 +50,31 @@
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>refaster-support</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.google.auto</groupId>
<artifactId>auto-common</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.auto.service</groupId>
<artifactId>auto-service-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.google.auto.value</groupId>
<artifactId>auto-value-annotations</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.jakewharton.nopen</groupId>
<artifactId>nopen-annotations</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
Expand Down Expand Up @@ -87,6 +105,11 @@
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<scope>test</scope>
</dependency>
</dependencies>

<build>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
package tech.picnic.errorprone.refaster.runner;

import static java.util.Comparator.comparingInt;

import com.google.auto.value.AutoValue;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSortedSet;
import com.google.common.collect.Maps;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Function;

/**
* A node in an immutable tree.
*
* <p>The tree's edges are string-labeled, while its leaves store values of type {@code T}.
*/
@AutoValue
abstract class Node<T> {
// XXX: Review: should this method accept a `SetMultimap<V, ? extends Set<String>>`, or should
// there be such an overload?
static <T> Node<T> create(
Set<T> values, Function<? super T, ? extends Set<? extends Set<String>>> pathExtractor) {
Builder<T> tree = Builder.create();
tree.register(values, pathExtractor);
return tree.build();
}

abstract ImmutableMap<String, Node<T>> children();

abstract ImmutableList<T> values();

// XXX: Consider having `RefasterRuleSelector` already collect the candidate edges into a
// `SortedSet`, as that would likely speed up `ImmutableSortedSet#copyOf`.
// XXX: If this ^ proves worthwhile, then the test code and benchmark should be updated
// accordingly.
void collectReachableValues(Set<String> candidateEdges, Consumer<T> sink) {
collectReachableValues(ImmutableSortedSet.copyOf(candidateEdges).asList(), sink);
}

private void collectReachableValues(ImmutableList<String> candidateEdges, Consumer<T> sink) {
values().forEach(sink);

if (candidateEdges.isEmpty() || children().isEmpty()) {

Check warning on line 49 in refaster-runner/src/main/java/tech/picnic/errorprone/refaster/runner/Node.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 49 without causing a test to fail

removed conditional - replaced equality check with false (covered by 308 tests RemoveConditionalMutator_EQUAL_ELSE)
return;
}

/*
* For performance reasons we iterate over the smallest set of edges. In case there are fewer
* children than candidate edges we iterate over the former, at the cost of not pruning the set
* of candidate edges if a transition is made.
*/
int candidateEdgeCount = candidateEdges.size();
if (children().size() < candidateEdgeCount) {

Check warning on line 59 in refaster-runner/src/main/java/tech/picnic/errorprone/refaster/runner/Node.java

View workflow job for this annotation

GitHub Actions / pitest

2 different changes can be made to line 59 without causing a test to fail

changed conditional boundary (covered by 308 tests ConditionalsBoundaryMutator) removed conditional - replaced comparison check with false (covered by 308 tests RemoveConditionalMutator_ORDER_ELSE)
for (Map.Entry<String, Node<T>> e : children().entrySet()) {
if (candidateEdges.contains(e.getKey())) {
e.getValue().collectReachableValues(candidateEdges, sink);
}
}
} else {
for (int i = 0; i < candidateEdgeCount; i++) {
Node<T> child = children().get(candidateEdges.get(i));
if (child != null) {
child.collectReachableValues(candidateEdges.subList(i + 1, candidateEdgeCount), sink);
}
}
}
}

@AutoValue
@SuppressWarnings("AutoValueImmutableFields" /* Type is used only during `Node` construction. */)
abstract static class Builder<T> {
private static <T> Builder<T> create() {
return new AutoValue_Node_Builder<>(new HashMap<>(), new ArrayList<>());
}

abstract Map<String, Builder<T>> children();

abstract List<T> values();

/**
* Registers all paths to each of the given values.
*
* <p>Shorter paths are registered first, so that longer paths can be skipped if a strict prefix
* leads to the same value.
*/
private void register(
Set<T> values, Function<? super T, ? extends Set<? extends Set<String>>> pathsExtractor) {
for (T value : values) {
List<? extends Set<String>> paths = new ArrayList<>(pathsExtractor.apply(value));
/*
* We sort paths by length ascending, so that in case of two paths where one is an initial
* prefix of the other, only the former is encoded (thus saving some space).
*/
paths.sort(comparingInt(Set::size));

Check warning on line 100 in refaster-runner/src/main/java/tech/picnic/errorprone/refaster/runner/Node.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 100 without causing a test to fail

removed call to java/util/List::sort (covered by 25 tests VoidMethodCallMutator)
paths.forEach(path -> registerPath(value, ImmutableList.sortedCopyOf(path)));
}
}

private void registerPath(T value, ImmutableList<String> path) {
if (values().contains(value)) {

Check warning on line 106 in refaster-runner/src/main/java/tech/picnic/errorprone/refaster/runner/Node.java

View workflow job for this annotation

GitHub Actions / pitest

A change can be made to line 106 without causing a test to fail

removed conditional - replaced equality check with false (covered by 25 tests RemoveConditionalMutator_EQUAL_ELSE)
/* Another (shorter) path already leads to this value. */
return;
}

if (path.isEmpty()) {
values().add(value);
} else {
children()
.computeIfAbsent(path.get(0), k -> create())
.registerPath(value, path.subList(1, path.size()));
}
}

private Node<T> build() {
return new AutoValue_Node<>(
ImmutableMap.copyOf(Maps.transformValues(children(), Builder::build)),
ImmutableList.copyOf(values()));
}
}
}
Loading
Loading