Add JMH for benchmark
This commit is contained in:
committed by
Mikhail Glukhikh
parent
0e8bbab925
commit
c47a8e2025
@@ -4,6 +4,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "org.jetbrains.kotlin.fir"
|
group = "org.jetbrains.kotlin.fir"
|
||||||
|
val jmhVersion = "1.21"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -20,6 +21,10 @@ dependencies {
|
|||||||
|
|
||||||
compile("junit", "junit", "4.4")
|
compile("junit", "junit", "4.4")
|
||||||
compile(projectTests(":compiler:fir:psi2fir"))
|
compile(projectTests(":compiler:fir:psi2fir"))
|
||||||
|
|
||||||
|
compile("org.openjdk.jmh", "jmh-core", jmhVersion)
|
||||||
|
compile("org.openjdk.jmh", "jmh-generator-bytecode", jmhVersion)
|
||||||
|
compile("org.openjdk.jmh", "jmh-generator-annprocess", jmhVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -30,3 +35,60 @@ sourceSets {
|
|||||||
projectTest {
|
projectTest {
|
||||||
workingDir = rootDir
|
workingDir = rootDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val compactClasspath by tasks.creating(Jar::class) {
|
||||||
|
archiveAppendix.set("classpath")
|
||||||
|
inputs.files(sourceSets["main"].runtimeClasspath + sourceSets["test"].runtimeClasspath)
|
||||||
|
doFirst {
|
||||||
|
manifest {
|
||||||
|
attributes["Class-Path"] = (sourceSets["main"].runtimeClasspath + sourceSets["test"].runtimeClasspath).files
|
||||||
|
.joinToString(separator = " ", transform = { it.toURI().toURL().toString() })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jmhBytecode by tasks.creating(JavaExec::class) {
|
||||||
|
tasks["classes"].mustRunAfter(tasks["clean"])
|
||||||
|
tasks["compactClasspath"].mustRunAfter(tasks["classes"])
|
||||||
|
dependsOn(tasks["clean"])
|
||||||
|
dependsOn(tasks["classes"])
|
||||||
|
dependsOn(tasks["compactClasspath"])
|
||||||
|
|
||||||
|
classpath = files(tasks["compactClasspath"].outputs.files.singleFile.absolutePath)
|
||||||
|
main = "org.openjdk.jmh.generators.bytecode.JmhBytecodeGenerator"
|
||||||
|
args(
|
||||||
|
"${project.buildDir}/classes/kotlin/test", "${project.buildDir}/generated-sources/jmh/",
|
||||||
|
"${project.buildDir}/classes/kotlin/test", "default"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
compileTestJava {
|
||||||
|
source(fileTree("${project.buildDir}/generated-sources/jmh/"))
|
||||||
|
destinationDir = file("${project.buildDir}/generated-classes/jmh/")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val jmhCompile by tasks.creating(JavaCompile::class) {
|
||||||
|
/*classpath = sourceSets["test"].runtimeClasspath + files("${project.buildDir}/generated-sources/jmh/")
|
||||||
|
|
||||||
|
source(fileTree("${project.buildDir}/generated-sources/jmh/"))
|
||||||
|
destinationDir = file("${project.buildDir}/generated-classes/jmh/")*/
|
||||||
|
}
|
||||||
|
|
||||||
|
val jmhExec by tasks.creating(JavaExec::class) {
|
||||||
|
dependsOn(tasks["compileTestJava"])
|
||||||
|
doFirst {
|
||||||
|
classpath = files(
|
||||||
|
tasks["compactClasspath"].outputs.files.singleFile.absolutePath,
|
||||||
|
"${project.buildDir}/generated-classes/jmh/",
|
||||||
|
"${project.buildDir}/classes/kotlin/test"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
main = "org.openjdk.jmh.Main"
|
||||||
|
|
||||||
|
workingDir = rootDir
|
||||||
|
systemProperty("idea.home.path", project.intellij.localPath)
|
||||||
|
configurations.plusAssign(project.configurations["compile"])
|
||||||
|
}
|
||||||
+1
-2
@@ -3,7 +3,7 @@
|
|||||||
* that can be found in the license/LICENSE.txt file.
|
* that can be found in the license/LICENSE.txt file.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.jetbrains.kotlin.fir.lightTree.totalKotlin
|
package org.jetbrains.kotlin.fir.lightTree
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
@@ -12,7 +12,6 @@ import com.intellij.testFramework.TestDataPath
|
|||||||
import com.intellij.util.PathUtil
|
import com.intellij.util.PathUtil
|
||||||
import org.jetbrains.kotlin.fir.FirRenderer
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.lightTree.benchmark
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.openapi.vfs.CharsetToolkit
|
||||||
|
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||||
|
import org.openjdk.jmh.annotations.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@BenchmarkMode(Mode.SingleShotTime)
|
||||||
|
@Warmup(iterations = 5, batchSize = 1)
|
||||||
|
@Measurement(iterations = 5, batchSize = 1)
|
||||||
|
@Fork(1)
|
||||||
|
open class AbstractBenchmark {
|
||||||
|
private val files = mutableMapOf<String, Pair<File, String>>()
|
||||||
|
|
||||||
|
protected fun readFiles(ignoreTestData: Boolean, path: String) {
|
||||||
|
val root = File(path)
|
||||||
|
|
||||||
|
println("BASE PATH: $path")
|
||||||
|
for (file in root.walkTopDown()) {
|
||||||
|
if (file.isDirectory) continue
|
||||||
|
if (ignoreTestData && (file.path.contains("testData") || file.path.contains("resources"))) continue
|
||||||
|
if (file.extension != "kt") continue
|
||||||
|
|
||||||
|
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
||||||
|
files[file.name] = Pair(file, text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO null check
|
||||||
|
protected fun getFileByName(fileName: String): Pair<File, String> {
|
||||||
|
return files[fileName]!!
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun forEachFile(f: (String, File) -> Unit) {
|
||||||
|
for ((file, text) in files.values) {
|
||||||
|
f(text, file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.lightTree.benchmark
|
||||||
|
|
||||||
|
import com.intellij.psi.impl.DebugUtil
|
||||||
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
|
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||||
|
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
||||||
|
import org.openjdk.jmh.annotations.Scope
|
||||||
|
import org.openjdk.jmh.annotations.State
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
open class LightTree2FirGenerator : TreeGenerator, AbstractRawFirBuilderTestCase() {
|
||||||
|
private var lightTreeConverter: LightTree2Fir? = null
|
||||||
|
|
||||||
|
override fun generateBaseTree(text: String, file: File) {
|
||||||
|
val lightTree = lightTreeConverter!!.buildLightTree(text)
|
||||||
|
DebugUtil.lightTreeToString(lightTree, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateFir(text: String, file: File) {
|
||||||
|
val firFile = lightTreeConverter!!.buildFirFile(text, file.name)
|
||||||
|
StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createConverter() {
|
||||||
|
val parserDefinition = KotlinParserDefinition()
|
||||||
|
val lexer = parserDefinition.createLexer(project)
|
||||||
|
lightTreeConverter = LightTree2Fir(true, parserDefinition, lexer)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
createConverter()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
+38
@@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.lightTree.benchmark
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.io.FileUtil
|
||||||
|
import com.intellij.psi.impl.DebugUtil
|
||||||
|
import com.intellij.util.PathUtil
|
||||||
|
import org.jetbrains.kotlin.fir.FirRenderer
|
||||||
|
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.openjdk.jmh.annotations.Scope
|
||||||
|
import org.openjdk.jmh.annotations.State
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
open class Psi2FirGenerator : TreeGenerator, AbstractRawFirBuilderTestCase() {
|
||||||
|
override fun generateBaseTree(text: String, file: File) {
|
||||||
|
val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile
|
||||||
|
DebugUtil.psiTreeToString(ktFile, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun generateFir(text: String, file: File) {
|
||||||
|
val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile
|
||||||
|
val firFile = ktFile.toFirFile(stubMode = true)
|
||||||
|
StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setUp() {
|
||||||
|
super.setUp()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun tearDown() {
|
||||||
|
super.tearDown()
|
||||||
|
}
|
||||||
|
}
|
||||||
+15
@@ -0,0 +1,15 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.lightTree.benchmark
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
interface TreeGenerator {
|
||||||
|
fun generateBaseTree(text: String, file: File)
|
||||||
|
fun generateFir(text: String, file: File)
|
||||||
|
fun setUp()
|
||||||
|
fun tearDown()
|
||||||
|
}
|
||||||
+41
@@ -0,0 +1,41 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||||
|
* that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.lightTree.benchmark.totalKotlin
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.lightTree.benchmark.*
|
||||||
|
import org.openjdk.jmh.annotations.*
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
abstract class AbstractTotalKotlinBenchmark : AbstractBenchmark() {
|
||||||
|
abstract val generator: TreeGenerator
|
||||||
|
|
||||||
|
@Setup
|
||||||
|
fun setUp() {
|
||||||
|
generator.setUp()
|
||||||
|
readFiles(true, System.getProperty("user.dir"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@TearDown
|
||||||
|
fun tearDown() {
|
||||||
|
generator.tearDown()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun testTotalKotlinOnlyBaseTree() {
|
||||||
|
forEachFile { text, file -> generator.generateBaseTree(text, file) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Benchmark
|
||||||
|
fun testTotalKotlinFir() {
|
||||||
|
forEachFile { text, file -> generator.generateFir(text, file) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class LightTree2FirTotalKotlinBenchmark(override val generator: TreeGenerator = LightTree2FirGenerator()) :
|
||||||
|
AbstractTotalKotlinBenchmark()
|
||||||
|
|
||||||
|
open class Psi2FirTotalKotlinBenchmark(override val generator: TreeGenerator = Psi2FirGenerator()) :
|
||||||
|
AbstractTotalKotlinBenchmark()
|
||||||
-46
@@ -1,46 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
|
||||||
* that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.fir.lightTree.totalKotlin
|
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
|
||||||
import com.intellij.openapi.vfs.CharsetToolkit
|
|
||||||
import com.intellij.testFramework.TestDataPath
|
|
||||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import java.io.File
|
|
||||||
import kotlin.system.measureNanoTime
|
|
||||||
|
|
||||||
@TestDataPath("/")
|
|
||||||
@RunWith(JUnit3RunnerWithInners::class)
|
|
||||||
abstract class AbstractTotalKotlinTest(private val treeName: String) : AbstractRawFirBuilderTestCase() {
|
|
||||||
protected abstract fun generateTree(onlyBaseTree: Boolean, text: String, file: File)
|
|
||||||
|
|
||||||
fun totalKotlinTest(onlyBaseTree: Boolean) {
|
|
||||||
val path = System.getProperty("user.dir")
|
|
||||||
val root = File(path)
|
|
||||||
var counter = 0
|
|
||||||
var time = 0L
|
|
||||||
|
|
||||||
if (onlyBaseTree) println("$treeName generation") else println("Fir from $treeName converter")
|
|
||||||
println("BASE PATH: $path")
|
|
||||||
for (file in root.walkTopDown()) {
|
|
||||||
if (file.isDirectory) continue
|
|
||||||
if (file.path.contains("testData") || file.path.contains("resources")) continue
|
|
||||||
if (file.extension != "kt") continue
|
|
||||||
|
|
||||||
val text = FileUtil.loadFile(file, CharsetToolkit.UTF8, true).trim()
|
|
||||||
time += measureNanoTime {
|
|
||||||
generateTree(onlyBaseTree, text, file)
|
|
||||||
}
|
|
||||||
|
|
||||||
counter++
|
|
||||||
}
|
|
||||||
println("SUCCESS!")
|
|
||||||
println("TIME PER FILE: ${(time / counter) * 1e-6} ms, COUNTER: $counter")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-48
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
|
||||||
* that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.fir.lightTree.totalKotlin
|
|
||||||
|
|
||||||
import com.intellij.psi.impl.DebugUtil
|
|
||||||
import com.intellij.testFramework.TestDataPath
|
|
||||||
import org.jetbrains.kotlin.fir.FirRenderer
|
|
||||||
import org.jetbrains.kotlin.fir.builder.AbstractRawFirBuilderTestCase
|
|
||||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
|
||||||
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
@TestDataPath("/")
|
|
||||||
@RunWith(JUnit3RunnerWithInners::class)
|
|
||||||
class LightTree2FirConverterTotalTest : AbstractTotalKotlinTest("LightTree") {
|
|
||||||
private var lightTreeConverter: LightTree2Fir? = null
|
|
||||||
|
|
||||||
override fun generateTree(onlyBaseTree: Boolean, text: String, file: File) {
|
|
||||||
if (onlyBaseTree) {
|
|
||||||
val lightTree = lightTreeConverter!!.buildLightTree(text)
|
|
||||||
DebugUtil.lightTreeToString(lightTree, false)
|
|
||||||
} else {
|
|
||||||
val firFile = lightTreeConverter!!.buildFirFile(text, file.name)
|
|
||||||
StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun createConverter() {
|
|
||||||
val parserDefinition = KotlinParserDefinition()
|
|
||||||
val lexer = parserDefinition.createLexer(myProject)
|
|
||||||
lightTreeConverter = LightTree2Fir(true, parserDefinition, lexer)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testTotalKotlinOnlyLightTree() {
|
|
||||||
createConverter()
|
|
||||||
totalKotlinTest(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testTotalKotlinFirFromLightTree() {
|
|
||||||
createConverter()
|
|
||||||
totalKotlinTest(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
-38
@@ -1,38 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
|
||||||
* that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.fir.lightTree.totalKotlin
|
|
||||||
|
|
||||||
import com.intellij.openapi.util.io.FileUtil
|
|
||||||
import com.intellij.psi.impl.DebugUtil
|
|
||||||
import com.intellij.testFramework.TestDataPath
|
|
||||||
import com.intellij.util.PathUtil
|
|
||||||
import org.jetbrains.kotlin.fir.FirRenderer
|
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import java.io.File
|
|
||||||
|
|
||||||
@TestDataPath("/")
|
|
||||||
@RunWith(JUnit3RunnerWithInners::class)
|
|
||||||
class Psi2FirConverterTotalTest : AbstractTotalKotlinTest("Psi") {
|
|
||||||
override fun generateTree(onlyBaseTree: Boolean, text: String, file: File) {
|
|
||||||
val ktFile = createPsiFile(FileUtil.getNameWithoutExtension(PathUtil.getFileName(file.path)), text) as KtFile
|
|
||||||
if (onlyBaseTree) {
|
|
||||||
DebugUtil.psiTreeToString(ktFile, false)
|
|
||||||
} else {
|
|
||||||
val firFile = ktFile.toFirFile(stubMode = true)
|
|
||||||
StringBuilder().also { FirRenderer(it).visitFile(firFile) }.toString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testTotalKotlinOnlyPsi() {
|
|
||||||
totalKotlinTest(true)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testTotalKotlinFirFromPsi() {
|
|
||||||
totalKotlinTest(false)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user