(UnusedSymbolInspection) Added support for typing per inspection tests

relates to #KT-38653
This commit is contained in:
Vladimir Ilmov
2020-05-17 16:31:46 +02:00
parent 1f1790d60e
commit de790a3e3b
9 changed files with 111 additions and 25 deletions
@@ -0,0 +1,55 @@
/*
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
* 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.impl.HighlightInfo
import com.intellij.testFramework.UsefulTestCase
import org.jetbrains.kotlin.idea.perf.util.ExternalProject
import org.jetbrains.kotlin.idea.perf.util.lastPathSegment
import org.jetbrains.kotlin.idea.perf.util.suite
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
import org.junit.runner.RunWith
/**
* Run the only specified exceptions on the selected files in Kotling project.
* Used for 'The Kotlin sources: kt files heavy inspections' graph.
* @TODO Should be run before typing tests as the testing project becomes unusable afterwards.
*/
@RunWith(JUnit3RunnerWithInners::class)
class AHeavyInspectionsPerformanceTest : UsefulTestCase() {
val listOfFiles = arrayOf(
"libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt",
"idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/PsiPrecedences.kt",
"compiler/psi/src/org/jetbrains/kotlin/psi/KtElement.kt",
"compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt",
"compiler/psi/src/org/jetbrains/kotlin/psi/KtImportInfo.kt"
)
val listOfInspections = arrayOf(
"UnusedSymbol",
"MemberVisibilityCanBePrivate"
)
fun testLocalInspection() {
suite {
app {
project(ExternalProject.KOTLIN_GRADLE) {
for (inspection in listOfInspections) {
enableSingleInspection(inspection)
for (file in listOfFiles) {
val editorFile = editor(file)
measure<List<HighlightInfo>>(inspection, file.lastPathSegment()) {
test = {
highlight(editorFile)
}
}
}
}
}
}
}
}
}
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.idea.perf package org.jetbrains.kotlin.idea.perf
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerConfig
class PerfTestBuilder<SV, TV> { class PerfTestBuilder<SV, TV> {
private lateinit var stats: Stats private lateinit var stats: Stats
private lateinit var name: String private lateinit var name: String
@@ -15,6 +17,7 @@ class PerfTestBuilder<SV, TV> {
private var tearDown: (TestData<SV, TV>) -> Unit = { } private var tearDown: (TestData<SV, TV>) -> Unit = { }
private var profilerEnabled: Boolean = false private var profilerEnabled: Boolean = false
private var checkStability: Boolean = true private var checkStability: Boolean = true
private var profilerConfig: ProfilerConfig = ProfilerConfig()
internal fun run() { internal fun run() {
stats.perfTest( stats.perfTest(
@@ -61,6 +64,10 @@ class PerfTestBuilder<SV, TV> {
this.profilerEnabled = profilerEnabled this.profilerEnabled = profilerEnabled
} }
fun profilerConfig(profilerConfig: ProfilerConfig) {
this.profilerConfig = profilerConfig
}
fun checkStability(checkStability: Boolean) { fun checkStability(checkStability: Boolean) {
this.checkStability = checkStability this.checkStability = checkStability
} }
@@ -22,6 +22,7 @@ typealias StatInfos = Map<String, Any>?
class Stats( class Stats(
val name: String = "", val name: String = "",
private val profilerConfig: ProfilerConfig = ProfilerConfig(),
private val header: Array<String> = arrayOf("Name", "ValueMS", "StdDev"), private val header: Array<String> = arrayOf("Name", "ValueMS", "StdDev"),
private val acceptanceStabilityLevel: Int = 25 private val acceptanceStabilityLevel: Int = 25
) : Closeable { ) : Closeable {
@@ -266,7 +267,7 @@ class Stats(
testData.reset() testData.reset()
triggerGC(attempt) triggerGC(attempt)
val phaseProfiler = createPhaseProfiler(phaseData, phaseName, attempt) val phaseProfiler = createPhaseProfiler(phaseData, phaseName, attempt, profilerConfig)
val setUpMillis = measureTimeMillis { phaseData.setUp(testData) } val setUpMillis = measureTimeMillis { phaseData.setUp(testData) }
val attemptName = "${phaseData.testName} #$attempt" val attemptName = "${phaseData.testName} #$attempt"
@@ -316,7 +317,8 @@ class Stats(
private fun <K, T> createPhaseProfiler( private fun <K, T> createPhaseProfiler(
phaseData: PhaseData<K, T>, phaseData: PhaseData<K, T>,
phaseName: String, phaseName: String,
attempt: Int attempt: Int,
profilerConfig: ProfilerConfig
): PhaseProfiler { ): PhaseProfiler {
val profilerHandler = if (phaseData.profilerEnabled) ProfilerHandler.getInstance() else DummyProfilerHandler val profilerHandler = if (phaseData.profilerEnabled) ProfilerHandler.getInstance() else DummyProfilerHandler
@@ -325,7 +327,7 @@ class Stats(
check(with(File(profilerPath)) { exists() || mkdirs() }) { "unable to mkdirs $profilerPath for ${phaseData.testName}" } check(with(File(profilerPath)) { exists() || mkdirs() }) { "unable to mkdirs $profilerPath for ${phaseData.testName}" }
val activityName = "${phaseData.testName}-${if (phaseName.isEmpty()) "" else "$phaseName-"}$attempt" val activityName = "${phaseData.testName}-${if (phaseName.isEmpty()) "" else "$phaseName-"}$attempt"
ActualPhaseProfiler(activityName, profilerPath, profilerHandler) ActualPhaseProfiler(activityName, profilerPath, profilerHandler, profilerConfig)
} else { } else {
DummyPhaseProfiler DummyPhaseProfiler
} }
@@ -19,14 +19,17 @@ object DummyPhaseProfiler : PhaseProfiler {
class ActualPhaseProfiler( class ActualPhaseProfiler(
private val activityName: String, private val activityName: String,
private val profilerPath: String, private val profilerPath: String,
private val profilerHandler: ProfilerHandler private val profilerHandler: ProfilerHandler,
private val config: ProfilerConfig = ProfilerConfig()
) : ) :
PhaseProfiler { PhaseProfiler {
override fun start() { override fun start() {
profilerHandler.startProfiling(activityName) profilerHandler.startProfiling(activityName, config)
} }
override fun stop() { override fun stop() {
profilerHandler.stopProfiling(profilerPath, activityName) profilerHandler.stopProfiling(profilerPath, activityName, config)
} }
} }
data class ProfilerConfig(var tracing: Boolean = false, var options: List<String> = emptyList())
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.idea.perf.profilers.yk.YKProfilerHandler
import org.jetbrains.kotlin.idea.perf.util.logMessage import org.jetbrains.kotlin.idea.perf.util.logMessage
interface ProfilerHandler { interface ProfilerHandler {
fun startProfiling(activityName: String, options: List<String> = emptyList()) fun startProfiling(activityName: String, config: ProfilerConfig)
fun stopProfiling(snapshotsPath: String, activityName: String, options: List<String> = emptyList()) fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig)
companion object { companion object {
private var instance: ProfilerHandler? = null private var instance: ProfilerHandler? = null
@@ -32,9 +32,9 @@ interface ProfilerHandler {
} }
object DummyProfilerHandler : ProfilerHandler { object DummyProfilerHandler : ProfilerHandler {
override fun startProfiling(activityName: String, options: List<String>) {} override fun startProfiling(activityName: String, config: ProfilerConfig) {}
override fun stopProfiling(snapshotsPath: String, activityName: String, options: List<String>) {} override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) {}
} }
internal fun <T> doOrLog(message: String, block: () -> T?): T? { internal fun <T> doOrLog(message: String, block: () -> T?): T? {
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.perf.profilers.async
import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.containers.ContainerUtil import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerConfig
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
import org.jetbrains.kotlin.idea.perf.util.logMessage import org.jetbrains.kotlin.idea.perf.util.logMessage
@@ -47,18 +48,18 @@ internal class AsyncProfilerHandler : ProfilerHandler {
executeMethod.invoke(asyncProfiler, command) executeMethod.invoke(asyncProfiler, command)
} }
override fun startProfiling(activityName: String, options: List<String>) { override fun startProfiling(activityName: String, config: ProfilerConfig) {
try { try {
profilingOptions = options profilingOptions = config.options
execute(AsyncProfilerCommandBuilder.buildStartCommand(options)) execute(AsyncProfilerCommandBuilder.buildStartCommand(config.options))
profilingStarted = true profilingStarted = true
} catch (e: Exception) { } catch (e: Exception) {
throw RuntimeException(e) throw RuntimeException(e)
} }
} }
override fun stopProfiling(snapshotsPath: String, activityName: String, options: List<String>) { override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) {
val combinedOptions = ArrayList(options) val combinedOptions = ArrayList(config.options)
val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath) val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath)
val name = activityName.replace(' ', '_').replace('/', '_') val name = activityName.replace(' ', '_').replace('/', '_')
val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions) val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.perf.profilers.yk package org.jetbrains.kotlin.idea.perf.profilers.yk
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerConfig
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler import org.jetbrains.kotlin.idea.perf.profilers.ProfilerHandler
import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow
import org.jetbrains.kotlin.idea.perf.util.logMessage import org.jetbrains.kotlin.idea.perf.util.logMessage
@@ -32,15 +33,18 @@ class YKProfilerHandler : ProfilerHandler {
} }
} }
override fun startProfiling(activityName: String, options: List<String>) { override fun startProfiling(activityName: String, config: ProfilerConfig) {
startCPUSamplingMethod.invoke(controller, null) if (config.tracing)
startTracingMethod.invoke(controller, null)
else
startCPUSamplingMethod.invoke(controller, null)
} }
override fun stopProfiling(snapshotsPath: String, activityName: String, options: List<String>) { override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) {
val dumpPath = captureSnapshotMethod.invoke(controller, SNAPSHOT_WITHOUT_HEAP) as String val dumpPath = captureSnapshotMethod.invoke(controller, SNAPSHOT_WITHOUT_HEAP) as String
stopCPUProfilingMethod.invoke(controller) stopCPUProfilingMethod.invoke(controller)
val path = Paths.get(dumpPath) val path = Paths.get(dumpPath)
val target = path.parent.resolve(snapshotsPath) val target = path.parent.resolve(snapshotsPath).resolve(activityName)
logMessage { "dump is moved to $target" } logMessage { "dump is moved to $target" }
Files.move(path, target) Files.move(path, target)
} }
@@ -57,6 +61,12 @@ class YKProfilerHandler : ProfilerHandler {
String::class.java String::class.java
) )
} }
private val startTracingMethod: Method = doOrThrow("com.yourkit.api.Controller#startTracing(String) not found") {
ykLibClass.getMethod(
"startTracing",
String::class.java
)
}
private val captureSnapshotMethod: Method = doOrThrow("com.yourkit.api.Controller#captureSnapshot(long) not found") { private val captureSnapshotMethod: Method = doOrThrow("com.yourkit.api.Controller#captureSnapshot(long) not found") {
ykLibClass.getMethod( ykLibClass.getMethod(
"captureSnapshot", "captureSnapshot",
@@ -64,6 +74,10 @@ class YKProfilerHandler : ProfilerHandler {
) )
} }
private val capturePerformanceSnapshotMethod: Method = doOrThrow("com.yourkit.api.Controller#capturePerformanceSnapshot() not found") {
ykLibClass.getMethod("capturePerformanceSnapshot")
}
private val stopCPUProfilingMethod: Method = doOrThrow("com.yourkit.api.Controller#stopCPUProfiling() not found") { private val stopCPUProfilingMethod: Method = doOrThrow("com.yourkit.api.Controller#stopCPUProfiling() not found") {
ykLibClass.getMethod("stopCPUProfiling") ykLibClass.getMethod("stopCPUProfiling")
} }
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.idea.perf.ProjectBuilder
import org.jetbrains.kotlin.idea.perf.Stats import org.jetbrains.kotlin.idea.perf.Stats
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
import org.jetbrains.kotlin.idea.perf.performanceTest import org.jetbrains.kotlin.idea.perf.performanceTest
import org.jetbrains.kotlin.idea.perf.profilers.ProfilerConfig
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.disableAllInspections import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.disableAllInspections
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableAllInspections import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableAllInspections
import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableInspections import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableInspections
@@ -139,6 +140,7 @@ class PerformanceSuite {
after?.invoke() after?.invoke()
} }
profilerEnabled(config.profile) profilerEnabled(config.profile)
profilerConfig(config.profilerConfig)
} }
return value return value
} }
@@ -178,7 +180,7 @@ class PerformanceSuite {
} }
override fun close() { override fun close() {
application?.setDataProvider(null) application.setDataProvider(null)
} }
companion object { companion object {
@@ -214,7 +216,7 @@ class PerformanceSuite {
} }
class StatsScopeConfig(var name: String? = null, var warmup: Int = 2, var iterations: Int = 5, var profile: Boolean = false) class StatsScopeConfig(var name: String? = null, var warmup: Int = 2, var iterations: Int = 5, var profile: Boolean = false, var profilerConfig: ProfilerConfig = ProfilerConfig())
class ProjectScopeConfig(val path: String, val openWith: ProjectOpenAction, val refresh: Boolean = false) { class ProjectScopeConfig(val path: String, val openWith: ProjectOpenAction, val refresh: Boolean = false) {
val name: String = path.lastPathSegment() val name: String = path.lastPathSegment()
@@ -329,8 +331,8 @@ class PerformanceSuite {
override fun close() { override fun close() {
RunAll( RunAll(
ThrowableRunnable { ThrowableRunnable {
project?.let { prj -> project.let { prj ->
app.application?.closeProject(prj) app.application.closeProject(prj)
} }
}).run() }).run()
} }
@@ -407,7 +409,7 @@ fun UsefulTestCase.suite(
) { ) {
PerformanceSuite.suite( PerformanceSuite.suite(
suiteName ?: this.javaClass.name, suiteName ?: this.javaClass.name,
PerformanceSuite.StatsScope(config, Stats(config.name ?: suiteName ?: name), testRootDisposable), PerformanceSuite.StatsScope(config, Stats(config.name ?: suiteName ?: name, config.profilerConfig), testRootDisposable),
block block
) )
} }
@@ -13,6 +13,8 @@ class ExternalProject(val path: String, val openWith: ProjectOpenAction) {
val KOTLIN_GRADLE = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.GRADLE_PROJECT) val KOTLIN_GRADLE = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.GRADLE_PROJECT)
val KOTLIN_JPS = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.EXISTING_IDEA_PROJECT) val KOTLIN_JPS = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.EXISTING_IDEA_PROJECT)
// not intended for using in unit tests, only for local verification
val KOTLIN_AUTO = ExternalProject(KOTLIN_PROJECT_PATH, autoOpenAction(KOTLIN_PROJECT_PATH)) val KOTLIN_AUTO = ExternalProject(KOTLIN_PROJECT_PATH, autoOpenAction(KOTLIN_PROJECT_PATH))
fun autoOpenAction(path: String): ProjectOpenAction { fun autoOpenAction(path: String): ProjectOpenAction {