diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt new file mode 100644 index 00000000000..e48ae1ccda6 --- /dev/null +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt @@ -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>(inspection, file.lastPathSegment()) { + test = { + highlight(editorFile) + } + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt index 2a291c2cb7e..fe28f75ce42 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.idea.perf +import org.jetbrains.kotlin.idea.perf.profilers.ProfilerConfig + class PerfTestBuilder { private lateinit var stats: Stats private lateinit var name: String @@ -15,6 +17,7 @@ class PerfTestBuilder { private var tearDown: (TestData) -> Unit = { } private var profilerEnabled: Boolean = false private var checkStability: Boolean = true + private var profilerConfig: ProfilerConfig = ProfilerConfig() internal fun run() { stats.perfTest( @@ -61,6 +64,10 @@ class PerfTestBuilder { this.profilerEnabled = profilerEnabled } + fun profilerConfig(profilerConfig: ProfilerConfig) { + this.profilerConfig = profilerConfig + } + fun checkStability(checkStability: Boolean) { this.checkStability = checkStability } diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt index ec086346928..3b9d31ff5ad 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt @@ -22,6 +22,7 @@ typealias StatInfos = Map? class Stats( val name: String = "", + private val profilerConfig: ProfilerConfig = ProfilerConfig(), private val header: Array = arrayOf("Name", "ValueMS", "StdDev"), private val acceptanceStabilityLevel: Int = 25 ) : Closeable { @@ -266,7 +267,7 @@ class Stats( testData.reset() triggerGC(attempt) - val phaseProfiler = createPhaseProfiler(phaseData, phaseName, attempt) + val phaseProfiler = createPhaseProfiler(phaseData, phaseName, attempt, profilerConfig) val setUpMillis = measureTimeMillis { phaseData.setUp(testData) } val attemptName = "${phaseData.testName} #$attempt" @@ -316,7 +317,8 @@ class Stats( private fun createPhaseProfiler( phaseData: PhaseData, phaseName: String, - attempt: Int + attempt: Int, + profilerConfig: ProfilerConfig ): PhaseProfiler { 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}" } val activityName = "${phaseData.testName}-${if (phaseName.isEmpty()) "" else "$phaseName-"}$attempt" - ActualPhaseProfiler(activityName, profilerPath, profilerHandler) + ActualPhaseProfiler(activityName, profilerPath, profilerHandler, profilerConfig) } else { DummyPhaseProfiler } diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt index c3bbeb1918d..e924c101494 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/PhaseProfiler.kt @@ -19,14 +19,17 @@ object DummyPhaseProfiler : PhaseProfiler { class ActualPhaseProfiler( private val activityName: String, private val profilerPath: String, - private val profilerHandler: ProfilerHandler + private val profilerHandler: ProfilerHandler, + private val config: ProfilerConfig = ProfilerConfig() ) : PhaseProfiler { override fun start() { - profilerHandler.startProfiling(activityName) + profilerHandler.startProfiling(activityName, config) } override fun stop() { - profilerHandler.stopProfiling(profilerPath, activityName) + profilerHandler.stopProfiling(profilerPath, activityName, config) } -} \ No newline at end of file +} + +data class ProfilerConfig(var tracing: Boolean = false, var options: List = emptyList()) \ No newline at end of file diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt index cc899413983..bebd9ea4d17 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/ProfilerHandler.kt @@ -10,9 +10,9 @@ import org.jetbrains.kotlin.idea.perf.profilers.yk.YKProfilerHandler import org.jetbrains.kotlin.idea.perf.util.logMessage interface ProfilerHandler { - fun startProfiling(activityName: String, options: List = emptyList()) + fun startProfiling(activityName: String, config: ProfilerConfig) - fun stopProfiling(snapshotsPath: String, activityName: String, options: List = emptyList()) + fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) companion object { private var instance: ProfilerHandler? = null @@ -32,9 +32,9 @@ interface ProfilerHandler { } object DummyProfilerHandler : ProfilerHandler { - override fun startProfiling(activityName: String, options: List) {} + override fun startProfiling(activityName: String, config: ProfilerConfig) {} - override fun stopProfiling(snapshotsPath: String, activityName: String, options: List) {} + override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) {} } internal fun doOrLog(message: String, block: () -> T?): T? { diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt index 0b994753fdb..34188e1a4cb 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/async/AsyncProfilerHandler.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.idea.perf.profilers.async import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil 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.doOrThrow import org.jetbrains.kotlin.idea.perf.util.logMessage @@ -47,18 +48,18 @@ internal class AsyncProfilerHandler : ProfilerHandler { executeMethod.invoke(asyncProfiler, command) } - override fun startProfiling(activityName: String, options: List) { + override fun startProfiling(activityName: String, config: ProfilerConfig) { try { - profilingOptions = options - execute(AsyncProfilerCommandBuilder.buildStartCommand(options)) + profilingOptions = config.options + execute(AsyncProfilerCommandBuilder.buildStartCommand(config.options)) profilingStarted = true } catch (e: Exception) { throw RuntimeException(e) } } - override fun stopProfiling(snapshotsPath: String, activityName: String, options: List) { - val combinedOptions = ArrayList(options) + override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) { + val combinedOptions = ArrayList(config.options) val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath) val name = activityName.replace(' ', '_').replace('/', '_') val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions) diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/yk/YKProfilerHandler.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/yk/YKProfilerHandler.kt index 1061509d6aa..e489effc50e 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/yk/YKProfilerHandler.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/profilers/yk/YKProfilerHandler.kt @@ -5,6 +5,7 @@ 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.doOrThrow import org.jetbrains.kotlin.idea.perf.util.logMessage @@ -32,15 +33,18 @@ class YKProfilerHandler : ProfilerHandler { } } - override fun startProfiling(activityName: String, options: List) { - startCPUSamplingMethod.invoke(controller, null) + override fun startProfiling(activityName: String, config: ProfilerConfig) { + if (config.tracing) + startTracingMethod.invoke(controller, null) + else + startCPUSamplingMethod.invoke(controller, null) } - override fun stopProfiling(snapshotsPath: String, activityName: String, options: List) { + override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) { val dumpPath = captureSnapshotMethod.invoke(controller, SNAPSHOT_WITHOUT_HEAP) as String stopCPUProfilingMethod.invoke(controller) 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" } Files.move(path, target) } @@ -57,6 +61,12 @@ class YKProfilerHandler : ProfilerHandler { 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") { ykLibClass.getMethod( "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") { ykLibClass.getMethod("stopCPUProfiling") } diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/performanceSuite.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/performanceSuite.kt index b89ec2b48bb..422d5b575ba 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/performanceSuite.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/performanceSuite.kt @@ -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.Companion.runAndMeasure 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.enableAllInspections import org.jetbrains.kotlin.idea.perf.util.ProfileTools.Companion.enableInspections @@ -139,6 +140,7 @@ class PerformanceSuite { after?.invoke() } profilerEnabled(config.profile) + profilerConfig(config.profilerConfig) } return value } @@ -178,7 +180,7 @@ class PerformanceSuite { } override fun close() { - application?.setDataProvider(null) + application.setDataProvider(null) } 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) { val name: String = path.lastPathSegment() @@ -329,8 +331,8 @@ class PerformanceSuite { override fun close() { RunAll( ThrowableRunnable { - project?.let { prj -> - app.application?.closeProject(prj) + project.let { prj -> + app.application.closeProject(prj) } }).run() } @@ -407,7 +409,7 @@ fun UsefulTestCase.suite( ) { PerformanceSuite.suite( 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 ) } \ No newline at end of file diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/testProject.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/testProject.kt index 76f5067ad2e..4e793fa6fc3 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/testProject.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/util/testProject.kt @@ -13,6 +13,8 @@ class ExternalProject(val path: String, val openWith: ProjectOpenAction) { val KOTLIN_GRADLE = ExternalProject(KOTLIN_PROJECT_PATH, ProjectOpenAction.GRADLE_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)) fun autoOpenAction(path: String): ProjectOpenAction {