From 740e6fde35f1486be4bc1e34b0fd4d61ee2e3da6 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Wed, 28 Mar 2018 19:08:25 +0200 Subject: [PATCH] Create performance test for all inspections --- idea/build.gradle.kts | 48 ++++++- .../idea/perf/AllKotlinInspectionTest.kt | 123 ++++++++++++++++++ 2 files changed, 166 insertions(+), 5 deletions(-) create mode 100644 idea/performanceTests/org/jetbrains/kotlin/idea/perf/AllKotlinInspectionTest.kt diff --git a/idea/build.gradle.kts b/idea/build.gradle.kts index faaa648c8c1..ac791d82b7b 100644 --- a/idea/build.gradle.kts +++ b/idea/build.gradle.kts @@ -42,6 +42,7 @@ dependencies { compileOnly(project(":kotlin-daemon-client")) + compileOnly(intellijDep()) compileOnly(commonDep("com.google.code.findbugs", "jsr305")) compileOnly(intellijPluginDep("IntelliLang")) @@ -102,24 +103,61 @@ dependencies { sourceSets { "main" { projectDefault() - java.srcDirs("idea-completion/src", - "idea-live-templates/src", - "idea-repl/src") + java.srcDirs( + "idea-completion/src", + "idea-live-templates/src", + "idea-repl/src" + ) resources.srcDirs("idea-repl/src").apply { include("META-INF/**") } } "test" { projectDefault() java.srcDirs( - "idea-completion/tests", - "idea-live-templates/tests") + "idea-completion/tests", + "idea-live-templates/tests" + ) + } + +} + +val performanceTestCompile by configurations.creating { + extendsFrom(configurations["testCompile"]) +} + +val performanceTestRuntime by configurations.creating { + extendsFrom(configurations["testRuntime"]) +} + +val performanceTest by run { + val sourceSets = the().sourceSets + sourceSets.creating { + compileClasspath += sourceSets["test"].output + compileClasspath += sourceSets["main"].output + runtimeClasspath += sourceSets["test"].output + runtimeClasspath += sourceSets["main"].output + java.srcDirs("performanceTests") } } projectTest { dependsOn(":dist") + dependsOn("performanceTest") workingDir = rootDir } + +projectTest(taskName = "performanceTest") { + dependsOn(":dist") + dependsOn(performanceTest.output) + testClassesDirs = performanceTest.output.classesDirs + classpath = performanceTest.runtimeClasspath + workingDir = rootDir + + doFirst { + systemProperty("idea.home.path", intellijRootDir().canonicalPath) + } +} + testsJar {} classesDirsArtifact() diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AllKotlinInspectionTest.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AllKotlinInspectionTest.kt new file mode 100644 index 00000000000..599fd50e955 --- /dev/null +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/AllKotlinInspectionTest.kt @@ -0,0 +1,123 @@ +/* + * Copyright 2010-2018 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.idea.perf + +import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase +import com.intellij.codeInspection.* +import com.intellij.codeInspection.ex.InspectionToolRegistrar +import com.intellij.codeInspection.ex.Tools +import com.intellij.ide.impl.ProjectUtil +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.ex.ApplicationEx +import com.intellij.openapi.vfs.VfsUtil +import com.intellij.profile.codeInspection.ProjectInspectionProfileManager +import com.intellij.psi.PsiElement +import com.intellij.psi.PsiElementVisitor +import com.intellij.psi.PsiFile +import com.intellij.psi.PsiManager +import java.io.File +import kotlin.system.measureNanoTime + +class AllKotlinInspectionTest : DaemonAnalyzerTestCase() { + + + companion object { + private val rootProjectFile = File(".").absoluteFile + + } + + private val tmp by lazy { createTempDirectory() } + + override fun setUpProject() { + + println("Copying project to $tmp") + + rootProjectFile.copyRecursively(tmp) + tmp.resolve(".idea").deleteRecursively() + + val inspectionProfilesDir = File(".idea/inspectionProfiles") + rootProjectFile.resolve(inspectionProfilesDir).copyRecursively( + tmp.resolve(inspectionProfilesDir).also { it.parentFile.mkdirs() } + ) + + (ApplicationManager.getApplication() as ApplicationEx).doNotSave() + myProject = ProjectUtil.openOrImport(tmp.path, null, false) + } + + + lateinit var profileTools: List + + + override fun setUp() { + + super.setUp() + + val wrappers = InspectionToolRegistrar.getInstance().createTools().map { it.tool } + + enableInspectionTools(*wrappers.toTypedArray()) + + profileTools = ProjectInspectionProfileManager.getInstance(project).currentProfile.getAllEnabledInspectionTools(project) + } + + fun doTest(file: File): Map { + + val results = mutableMapOf() + val vFile = VfsUtil.findFileByIoFile(file, false) ?: return results + + val psi = PsiManager.getInstance(project) + val psiFile = psi.findFile(vFile) ?: return results + + + profileTools.forEach { + val tool = it.tool.tool as? LocalInspectionTool ?: return@forEach + if (it.tool.language != null && it.tool.language!! !in setOf("kotlin", "UAST")) return@forEach + println("##teamcity[testStarted name='${it.tool.id}' captureStandardOutput='true']") + val result = measureNanoTime { + tool.analyze(psiFile) + } + results[it.tool.id] = result + println("##teamcity[testFinished name='${it.tool.id}' duration='${(result * 1e-6).toLong()}']") + } + + return results + } + + private fun PsiElement.acceptRecursively(visitor: PsiElementVisitor) { + this.accept(visitor) + for (child in this.children) { + child.acceptRecursively(visitor) + } + } + + fun LocalInspectionTool.analyze(file: PsiFile) { + if (file.textRange == null) return + + val holder = ProblemsHolder(InspectionManager.getInstance(file.project), file, false) + val session = LocalInspectionToolSession(file, file.textRange.startOffset, file.textRange.endOffset) + val visitor = this.buildVisitor(holder, false, session) + file.acceptRecursively(visitor) + } + + + fun testWholeProjectPerformance() { + + val totals = mutableMapOf() + + tmp.walkTopDown().filter { + it.extension == "kt" && "testData" !in it.path && "resources" !in it.path + }.forEach { + println("##teamcity[testSuiteStarted name='${it.relativeTo(tmp)}']") + doTest(it).forEach { (k, v) -> totals.merge(k, v) { a, b -> a + b } } + println("##teamcity[testSuiteFinished name='${it.relativeTo(tmp)}']") + } + + totals.forEach { (k, v) -> + println("##teamcity[testStarted name='total_$k' captureStandardOutput='true']") + println("##teamcity[testFinished name='total_$k' duration='${(v * 1e-6).toLong()}']") + } + } + +} \ No newline at end of file