Skip to content

Commit f7cb46c

Browse files
authored
Merge pull request #86 from olafurpg/bench
Add benchmark results
2 parents 4aae7e5 + 22b33b4 commit f7cb46c

File tree

65 files changed

+1737
-1342
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

65 files changed

+1737
-1342
lines changed

README.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,9 @@ using SemanticDB as an intermediary representation for LSIF:
6363
LSIF because compiler plugins does not have access to a project-wide context,
6464
which is necessary to produce accurate definitions and hovers in multi-module
6565
projects with external library dependencies.
66-
- **Performance**: SemanticDB is fast to write and read. The compiler adds low
67-
overhead on compilation and the final conversion from SemanticDB to LSIF can
68-
be safely parallelized.
66+
- **Performance**: SemanticDB is fast to write and read. Each compilation unit
67+
can be processed independently to keep memory usage low. The final conversion
68+
from SemanticDB to LSIF can be safely parallelized.
6969
- **Cross-language**: SemanticDB has a
7070
[spec](https://scalameta.org/docs/semanticdb/specification.html) for Java and
7171
Scala enabling cross-language navigation in hybrid Java/Scala codebases.
@@ -149,3 +149,7 @@ write tests because:
149149
code (which is always multiline). Modern versions of Java support multiline
150150
string literals, but they're not supported in Java 8, which is supported by
151151
lsif-java.
152+
153+
## Benchmarks
154+
155+
See [docs/benchmarks.md] for benchmark results.

build.sbt

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,3 +138,13 @@ lazy val snapshots = project
138138
)
139139
.dependsOn(minimizedScala, unit)
140140
.enablePlugins(BuildInfoPlugin)
141+
142+
lazy val bench = project
143+
.in(file("tests/benchmarks"))
144+
.settings(
145+
moduleName := "lsif-java-bench",
146+
fork.in(run) := true,
147+
skip.in(publish) := true
148+
)
149+
.dependsOn(unit)
150+
.enablePlugins(JmhPlugin)

docs/benchmarks.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Benchmarks results
2+
3+
```
4+
sbt:root> bench/jmh:run -i 3 -wi 3 -f1 -t1
5+
...
6+
[info] Benchmark (lib) Mode Cnt Score Error Units
7+
[info] CompileBench.compile guava ss 10 2291.036 ± 243.428 ms/op 1x
8+
[info] CompileBench.compileSemanticdb guava ss 10 3444.978 ± 408.569 ms/op 1.5x
9+
[info] CompileBench.compile bytebuddy ss 10 1819.150 ± 191.530 ms/op 1x
10+
[info] CompileBench.compileSemanticdb bytebuddy ss 10 2641.590 ± 203.537 ms/op 1.45x
11+
```
12+
13+
- Date: Monday 15 Feb 2021.
14+
- Hardware: MacBook Pro (16-inch, 2019), 2,6 GHz 6-Core Intel Core i7, 32 GB
15+
2667 MHz DDR4.
16+
- Interpretation: enabling the SemanticDB compiler plugin slows down normal
17+
compilation by 45-50%.
18+
- Recommendation: do not enable the SemanticDB compiler plugin during local
19+
edit-and-test workflows. The compiler plugin is primarily intended to be
20+
enabled in custom CI jobs to upload LSIF indexes.

project/plugins.sbt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ addSbtPlugin("com.thesamet" % "sbt-protoc" % "1.0.0")
66
addSbtPlugin("ch.epfl.scala" % "sbt-bloop" % "1.4.6-21-464e4ec4")
77
addSbtPlugin("com.sourcegraph" % "sbt-sourcegraph" % "0.1.8")
88
addSbtPlugin("com.lightbend.sbt" % "sbt-java-formatter" % "0.6.0")
9+
addSbtPlugin("pl.project13.scala" % "sbt-jmh" % "0.4.0")
910

1011
// sbt-jdi-tools appears to fix an error related to this message:
1112
// [error] (plugin / Compile / compileIncremental) java.lang.NoClassDefFoundError: com/sun/tools/javac/code/Symbol
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package benchmarks
2+
3+
import java.nio.charset.StandardCharsets
4+
import java.nio.file.FileSystems
5+
import java.nio.file.Files
6+
import java.nio.file.Path
7+
import java.nio.file.PathMatcher
8+
import java.util.concurrent.TimeUnit
9+
10+
import scala.meta.inputs.Input
11+
import scala.meta.internal.io.FileIO
12+
13+
import org.openjdk.jmh.annotations._
14+
import tests.DeleteVisitor
15+
import tests.Dependencies
16+
import tests.TestCompiler
17+
18+
@State(Scope.Benchmark)
19+
class CompileBench {
20+
21+
var deps: Dependencies = _
22+
var tmp: Path = _
23+
var compiler: TestCompiler = _
24+
var javaPattern: PathMatcher = _
25+
@Param(Array("bytebuddy", "guava"))
26+
var lib: String = _
27+
28+
val libs = Map(
29+
"bytebuddy" -> "net.bytebuddy:byte-buddy:1.10.20",
30+
"guava" -> "com.google.guava:guava:30.1-jre"
31+
)
32+
33+
@Setup()
34+
def setup(): Unit = {
35+
javaPattern = FileSystems.getDefault.getPathMatcher("glob:**.java")
36+
tmp = Files.createTempDirectory("benchmarks")
37+
deps = Dependencies.resolveDependencies(List(libs(lib)), Nil)
38+
compiler = new TestCompiler(deps.classpathSyntax, List.empty[String], tmp)
39+
}
40+
41+
@TearDown()
42+
def teardown(): Unit = {
43+
Files.walkFileTree(tmp, new DeleteVisitor)
44+
}
45+
46+
def foreachSource(fn: Seq[Input.VirtualFile] => Int): Long = {
47+
var sum = 0L
48+
deps
49+
.sources
50+
.foreach { source =>
51+
FileIO.withJarFileSystem(source, create = false, close = true) { root =>
52+
val files =
53+
FileIO
54+
.listAllFilesRecursively(root)
55+
.iterator
56+
.filter(p => javaPattern.matches(p.toNIO))
57+
.toArray
58+
val inputs = files.map { source =>
59+
val text = FileIO.slurp(source, StandardCharsets.UTF_8)
60+
val relativePath = source.toString().stripPrefix("/")
61+
Input.VirtualFile(relativePath, text)
62+
}
63+
sum += fn(inputs)
64+
}
65+
}
66+
sum
67+
}
68+
69+
@Benchmark
70+
@BenchmarkMode(Array(Mode.SingleShotTime))
71+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
72+
def compile(): Long = {
73+
foreachSource { inputs =>
74+
compiler.compile(inputs).byteCode.length
75+
}
76+
}
77+
78+
@Benchmark
79+
@BenchmarkMode(Array(Mode.SingleShotTime))
80+
@OutputTimeUnit(TimeUnit.MILLISECONDS)
81+
def compileSemanticdb(): Long = {
82+
foreachSource { inputs =>
83+
compiler.compileSemanticdb(inputs).textDocument.getOccurrencesCount
84+
}
85+
}
86+
87+
}

tests/snapshots/src/main/generated/com/airbnb/epoxy/AsyncEpoxyController.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
*/
2525
public abstract class AsyncEpoxyController extends EpoxyController {
2626
// ^^^^^^^^^^^^^^^^^^^^ definition com/airbnb/epoxy/AsyncEpoxyController#
27-
// ^^^^^^^^^^^^^^^ reference _root_/
27+
// ^^^^^^^^^^^^^^^ reference com/airbnb/epoxy/EpoxyController#
2828

2929
/**
3030
* A new instance that does model building and diffing asynchronously.
@@ -56,6 +56,7 @@ public AsyncEpoxyController(boolean enableAsyncModelBuilding, boolean enableAsyn
5656
// ^^^^^^^^^^^^^^^^^^^^^^^^ definition local1
5757
// ^^^^^^^^^^^^^^^^^^ definition local2
5858
super(getHandler(enableAsyncModelBuilding), getHandler(enableAsyncDiffing));
59+
// ^^^^^ reference com/airbnb/epoxy/EpoxyController#`<init>`(+1).
5960
// ^^^^^^^^^^ reference com/airbnb/epoxy/AsyncEpoxyController#getHandler().
6061
// ^^^^^^^^^^^^^^^^^^^^^^^^ reference local1
6162
// ^^^^^^^^^^ reference com/airbnb/epoxy/AsyncEpoxyController#getHandler().
@@ -68,7 +69,7 @@ private static Handler getHandler(boolean enableAsync) {
6869
// ^^^^^^^^^^^ definition local3
6970
return enableAsync ? getAsyncBackgroundHandler() : MAIN_THREAD_HANDLER;
7071
// ^^^^^^^^^^^ reference local3
71-
// ^^^^^^^^^^^^^^^^^^^^^^^^^ reference com/airbnb/epoxy/AsyncEpoxyController#getAsyncBackgroundHandler#
72-
// ^^^^^^^^^^^^^^^^^^^ reference _root_/
72+
// ^^^^^^^^^^^^^^^^^^^^^^^^^ reference com/airbnb/epoxy/EpoxyAsyncUtil#getAsyncBackgroundHandler().
73+
// ^^^^^^^^^^^^^^^^^^^ reference com/airbnb/epoxy/EpoxyAsyncUtil#MAIN_THREAD_HANDLER.
7374
}
7475
}

0 commit comments

Comments
 (0)