From 9719391c82cc03762f8ad1fd28e31e1e8d329a56 Mon Sep 17 00:00:00 2001 From: Vladimir Ilmov Date: Sat, 30 May 2020 01:33:15 +0200 Subject: [PATCH] (PerformanceTest) improvements in profiler snapshots support for typing per inspection tests gradle arguments fixed to allow running tracing from cli Profiler disabled for warmup phases. relates to #KT-38653 --- buildSrc/src/main/kotlin/tasks.kt | 17 +++-- idea/performanceTests/README.md | 4 ++ idea/performanceTests/build.gradle.kts | 6 +- .../perf/AHeavyInspectionsPerformanceTest.kt | 62 +++++++++++++++++++ .../perf/AbstractPerformanceProjectsTest.kt | 10 +-- .../kotlin/idea/perf/PerfTestBuilder.kt | 8 +-- .../idea/perf/PerformanceProjectsTest.kt | 2 +- .../org/jetbrains/kotlin/idea/perf/Stats.kt | 38 +++++------- .../idea/perf/profilers/PhaseProfiler.kt | 17 +++-- .../idea/perf/profilers/ProfilerHandler.kt | 27 +++++--- .../profilers/async/AsyncProfilerHandler.kt | 16 ++--- .../perf/profilers/yk/YKProfilerHandler.kt | 54 ++++++++++------ .../kotlin/idea/perf/util/performanceSuite.kt | 15 ++--- 13 files changed, 176 insertions(+), 100 deletions(-) diff --git a/buildSrc/src/main/kotlin/tasks.kt b/buildSrc/src/main/kotlin/tasks.kt index 26b1c148e6a..62bd3d51882 100644 --- a/buildSrc/src/main/kotlin/tasks.kt +++ b/buildSrc/src/main/kotlin/tasks.kt @@ -79,21 +79,20 @@ fun Project.projectTest( } } - doFirst { - val agent = tasks.findByPath(":test-instrumenter:jar")!!.outputs.files.singleFile - - val args = project.findProperty("kotlin.test.instrumentation.args")?.let { "=$it" }.orEmpty() - - jvmArgs("-javaagent:$agent$args") + if (project.findProperty("kotlin.test.instrumentation.disable")?.toString()?.toBoolean() != true) { + doFirst { + val agent = tasks.findByPath(":test-instrumenter:jar")!!.outputs.files.singleFile + val args = project.findProperty("kotlin.test.instrumentation.args")?.let { "=$it" }.orEmpty() + jvmArgs("-javaagent:$agent$args") + } + dependsOn(":test-instrumenter:jar") } - dependsOn(":test-instrumenter:jar") - jvmArgs( "-ea", "-XX:+HeapDumpOnOutOfMemoryError", "-XX:+UseCodeCacheFlushing", - "-XX:ReservedCodeCacheSize=128m", + "-XX:ReservedCodeCacheSize=256m", "-Djna.nosys=true" ) diff --git a/idea/performanceTests/README.md b/idea/performanceTests/README.md index 0b6a8511994..aece4eed012 100644 --- a/idea/performanceTests/README.md +++ b/idea/performanceTests/README.md @@ -14,6 +14,10 @@ Run all Kotlin IDE plugin performance tests with `$ gradle idea-plugin-performance-tests` +## Run with profiler + +`YOURKIT_PROFILER_HOME=/Applications/YourKit-Java-Profiler-2019.8.app ./gradlew -Pkotlin.test.instrumentation.disable=true :idea:performanceTests:performanceTest --tests ""` + ## Performance test Output is provided to console in TeamCity format like diff --git a/idea/performanceTests/build.gradle.kts b/idea/performanceTests/build.gradle.kts index edbd6e88db3..b2f043bdb55 100644 --- a/idea/performanceTests/build.gradle.kts +++ b/idea/performanceTests/build.gradle.kts @@ -84,9 +84,10 @@ projectTest(taskName = "performanceTest") { maxHeapSize = "3g" jvmArgs("-Didea.debug.mode=true") jvmArgs("-XX:SoftRefLRUPolicyMSPerMB=50") + jvmArgs( - "-XX:ReservedCodeCacheSize=240m", "-XX:+UseCompressedOops", + "-Didea.ProcessCanceledException=disabled", "-XX:+UseConcMarkSweepGC" ) @@ -97,7 +98,7 @@ projectTest(taskName = "performanceTest") { classpath += files("$yourKitHome/lib/yjp-controller-api-redist.jar") } currentOs.isMacOsX -> { - jvmArgs("-agentpath:$yourKitHome/Contents/Resources/bin/mac/libyjpagent.dylib") + jvmArgs("-agentpath:$yourKitHome/Contents/Resources/bin/mac/libyjpagent.dylib=delay=5000,_socket_timeout_ms=120000,disablealloc,disable_async_sampling,disablenatives") classpath += files("$yourKitHome/Contents/Resources/lib/yjp-controller-api-redist.jar") } } @@ -130,7 +131,6 @@ projectTest(taskName = "wholeProjectsPerformanceTest") { jvmArgs("-DemptyProfile=${System.getProperty("emptyProfile")}") jvmArgs("-XX:SoftRefLRUPolicyMSPerMB=50") jvmArgs( - "-XX:ReservedCodeCacheSize=240m", "-XX:+UseCompressedOops", "-XX:+UseConcMarkSweepGC" ) diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt index e48ae1ccda6..1321dc7cb9a 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AHeavyInspectionsPerformanceTest.kt @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.idea.perf +import com.intellij.codeHighlighting.Pass 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.Ignore import org.junit.runner.RunWith /** @@ -31,6 +33,7 @@ class AHeavyInspectionsPerformanceTest : UsefulTestCase() { "UnusedSymbol", "MemberVisibilityCanBePrivate" ) + val passesToIgnore = ((1 until 100) - Pass.LOCAL_INSPECTIONS - Pass.WHOLE_FILE_LOCAL_INSPECTIONS).toIntArray() fun testLocalInspection() { suite { @@ -41,6 +44,65 @@ class AHeavyInspectionsPerformanceTest : UsefulTestCase() { for (file in listOfFiles) { val editorFile = editor(file) + measure>(inspection, file.lastPathSegment()) { + test = { + highlight(editorFile, passesToIgnore) + } + } + } + } + } + } + } + } + + @Ignore + fun testUnusedSymbolLocalInspection() { + suite { + config.warmup = 1 + config.iterations = 2 + config.profilerConfig.enabled = true + config.profilerConfig.tracing = true + app { + project(ExternalProject.KOTLIN_AUTO) { + for (inspection in listOfInspections.sliceArray(0 until 1)) { + enableSingleInspection(inspection) + for (file in listOfFiles.sliceArray(0 until 1)) { + val editorFile = editor(file) + + measure>(inspection, file.lastPathSegment()) { + test = { + highlight(editorFile, passesToIgnore) + } + } + } + } + } + } + } + } + + // used locally to test + val UNUSED_AUTO = ExternalProject( + "../unused", + ExternalProject.autoOpenAction("../unused") + ) + + @Ignore + fun testSingleInspection1() { + suite { + config.warmup = 0 + config.iterations = 1 + config.profilerConfig.enabled = true + config.profilerConfig.tracing = true + app { + project(UNUSED_AUTO) { + for (inspection in listOfInspections.sliceArray(0..1)) { + enableSingleInspection(inspection) + val listOfFiles = listOf("src/main/kotlin/org/test/test.kt") + for (file in listOfFiles) { + val editorFile = editor(file) + measure>(inspection, file.lastPathSegment()) { test = { highlight(editorFile) diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt index 1a6816c1872..216c3c89a93 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt @@ -350,7 +350,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { stats(stats) warmUpIterations(8) iterations(15) - profilerEnabled(true) + profilerConfig.enabled = true setUp { val markerOffset = editor.document.text.indexOf(marker) assertTrue("marker '$marker' not found in $fileName", markerOffset > 0) @@ -468,7 +468,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } commitAllDocuments() } - profilerEnabled(true) + profilerConfig.enabled = true } } @@ -543,7 +543,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { commitAllDocuments() } } - profilerEnabled(true) + profilerConfig.enabled = true } } @@ -610,7 +610,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } PsiManager.getInstance(project).dropPsiCaches() } - profilerEnabled(!isWarmUp) + profilerConfig.enabled = true } highlightInfos } @@ -663,7 +663,7 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } it.value?.let { v -> assertNotNull(v) } } - profilerEnabled(true) + profilerConfig.enabled = true checkStability(false) } } 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 fe28f75ce42..0002c0aa866 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerfTestBuilder.kt @@ -15,9 +15,8 @@ class PerfTestBuilder { private var setUp: (TestData) -> Unit = { } private lateinit var test: (TestData) -> Unit private var tearDown: (TestData) -> Unit = { } - private var profilerEnabled: Boolean = false private var checkStability: Boolean = true - private var profilerConfig: ProfilerConfig = ProfilerConfig() + internal var profilerConfig: ProfilerConfig = ProfilerConfig() internal fun run() { stats.perfTest( @@ -27,7 +26,6 @@ class PerfTestBuilder { setUp = setUp, test = test, tearDown = tearDown, - profilerEnabled = profilerEnabled, checkStability = checkStability ) } @@ -60,10 +58,6 @@ class PerfTestBuilder { this.tearDown = tearDown } - fun profilerEnabled(profilerEnabled: Boolean) { - this.profilerEnabled = profilerEnabled - } - fun profilerConfig(profilerConfig: ProfilerConfig) { this.profilerConfig = profilerConfig } diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt index 653d1035b18..2a5c0c9d9b2 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -294,7 +294,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { setUp(perfKtsFileAnalysisSetUp(project, fileName)) test(perfKtsFileAnalysisTest()) tearDown(perfKtsFileAnalysisTearDown(extraTimingsNs, project)) - profilerEnabled(true) + profilerConfig.enabled = true } extraStats.printWarmUpTimings( 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 0d84f94556b..8fda74788b7 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/Stats.kt @@ -127,7 +127,6 @@ class Stats( setUp: (TestData) -> Unit = { }, test: (TestData) -> Unit, tearDown: (TestData) -> Unit = { }, - profilerEnabled: Boolean = false, checkStability: Boolean = true ) { @@ -137,15 +136,13 @@ class Stats( setUp = setUp, test = test, tearDown = tearDown, - profilerEnabled = profilerEnabled ) val mainPhaseData = PhaseData( iterations = iterations, testName = testName, setUp = setUp, test = test, - tearDown = tearDown, - profilerEnabled = profilerEnabled + tearDown = tearDown ) val block = { warmUpPhase(warmPhaseData) @@ -228,7 +225,7 @@ class Stats( } private fun warmUpPhase(phaseData: PhaseData) { - val warmUpStatInfosArray = phase(phaseData, WARM_UP) + val warmUpStatInfosArray = phase(phaseData, WARM_UP, true) if (phaseData.testName != WARM_UP) { printWarmUpTimings(phaseData.testName, warmUpStatInfosArray) @@ -256,17 +253,18 @@ class Stats( return statInfosArray } - private fun phase(phaseData: PhaseData, phaseName: String): Array { + private fun phase(phaseData: PhaseData, phaseName: String, warmup: Boolean = false): Array { val statInfosArray = Array(phaseData.iterations) { null } val testData = TestData(null, null) try { + val phaseProfiler = + createPhaseProfiler(phaseData.testName, phaseName, profilerConfig.copy(warmup = warmup)) + for (attempt in 0 until phaseData.iterations) { testData.reset() triggerGC(attempt) - val phaseProfiler = createPhaseProfiler(phaseData, phaseName, attempt, profilerConfig) - val setUpMillis = measureTimeMillis { phaseData.setUp(testData) } val attemptName = "${phaseData.testName} #$attempt" logMessage { "$attemptName setup took $setUpMillis ms" } @@ -274,12 +272,10 @@ class Stats( val valueMap = HashMap(2 * PerformanceCounter.numberOfCounters + 1) statInfosArray[attempt] = valueMap try { - phaseProfiler.start() valueMap[TEST_KEY] = measureNanoTime { phaseData.test(testData) } - phaseProfiler.stop() PerformanceCounter.report { name, counter, nanos -> valueMap["counter \"$name\": count"] = counter.toLong() @@ -291,6 +287,7 @@ class Stats( valueMap[ERROR_KEY] = t break } finally { + phaseProfiler.stop() try { val tearDownMillis = measureTimeMillis { phaseData.tearDown(testData) @@ -312,20 +309,20 @@ class Stats( return statInfosArray } - private fun createPhaseProfiler( - phaseData: PhaseData, + private fun createPhaseProfiler( + testName: String, phaseName: String, - attempt: Int, profilerConfig: ProfilerConfig ): PhaseProfiler { - val profilerHandler = if (phaseData.profilerEnabled) ProfilerHandler.getInstance() else DummyProfilerHandler + profilerConfig.name = "$testName${if (phaseName.isEmpty()) "" else "-"+phaseName}" + profilerConfig.path = pathToResource("profile/${plainname()}") + val profilerHandler = if (profilerConfig.enabled && !profilerConfig.warmup) + ProfilerHandler.getInstance(profilerConfig) + else + DummyProfilerHandler return if (profilerHandler != DummyProfilerHandler) { - val profilerPath = pathToResource("profile/${plainname()}") - 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, profilerConfig) + ActualPhaseProfiler(profilerHandler) } else { DummyPhaseProfiler } @@ -374,8 +371,7 @@ data class PhaseData( val testName: String, val setUp: (TestData) -> Unit, val test: (TestData) -> Unit, - val tearDown: (TestData) -> Unit, - val profilerEnabled: Boolean = false + val tearDown: (TestData) -> Unit ) data class TestData(var setUpValue: SV?, var value: TV?) { 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 e924c101494..c2d20632265 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 @@ -17,19 +17,18 @@ object DummyPhaseProfiler : PhaseProfiler { } class ActualPhaseProfiler( - private val activityName: String, - private val profilerPath: String, - private val profilerHandler: ProfilerHandler, - private val config: ProfilerConfig = ProfilerConfig() -) : - PhaseProfiler { + private val profilerHandler: ProfilerHandler +) : PhaseProfiler { + private var attempt: Int = 1 + override fun start() { - profilerHandler.startProfiling(activityName, config) + profilerHandler.startProfiling() } override fun stop() { - profilerHandler.stopProfiling(profilerPath, activityName, config) + profilerHandler.stopProfiling(attempt) + attempt++ } } -data class ProfilerConfig(var tracing: Boolean = false, var options: List = emptyList()) \ No newline at end of file +data class ProfilerConfig(var enabled: Boolean = false, var path: String = "", var name: String = "", var tracing: Boolean = false, var options: List = emptyList(), var warmup: Boolean = false) 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 bebd9ea4d17..1252870120c 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 @@ -8,33 +8,44 @@ package org.jetbrains.kotlin.idea.perf.profilers import org.jetbrains.kotlin.idea.perf.profilers.async.AsyncProfilerHandler import org.jetbrains.kotlin.idea.perf.profilers.yk.YKProfilerHandler import org.jetbrains.kotlin.idea.perf.util.logMessage +import java.nio.file.Path interface ProfilerHandler { - fun startProfiling(activityName: String, config: ProfilerConfig) + fun startProfiling() - fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) + fun stopProfiling(attempt: Int) companion object { private var instance: ProfilerHandler? = null @Synchronized - fun getInstance(): ProfilerHandler { + fun getInstance(profilerConfig: ProfilerConfig): ProfilerHandler { return instance ?: run { val handler = - doOrLog("asyncProfiler not found") { AsyncProfilerHandler() } - ?: doOrLog("yourKit not found") { YKProfilerHandler() } ?: DummyProfilerHandler + doOrLog("asyncProfiler not found") { AsyncProfilerHandler(profilerConfig) } + ?: doOrLog("yourKit not found") { YKProfilerHandler(profilerConfig) } ?: DummyProfilerHandler instance = handler return handler } } - } + fun determinePhasePath(dumpPath: Path, profilerConfig: ProfilerConfig): Path { + val activityPath = dumpPath.parent.resolve(profilerConfig.path) + val runNumber = + (activityPath.toFile().listFiles()?.maxBy { it.name.toIntOrNull() ?: 0 }?.name?.toIntOrNull() + ?: 0) + 1 + val runPath = activityPath.resolve("$runNumber") + runPath.toFile().mkdirs() + logMessage { "profiler's run path found $runPath" } + return runPath + } + } } object DummyProfilerHandler : ProfilerHandler { - override fun startProfiling(activityName: String, config: ProfilerConfig) {} + override fun startProfiling() {} - override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) {} + override fun stopProfiling(attempt: Int) {} } 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 34188e1a4cb..5303bb5d32c 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 @@ -26,7 +26,7 @@ import java.util.* * * AsyncProfiler could be downloaded from https://github.com/jvm-profiling-tools/async-profiler/releases/ */ -internal class AsyncProfilerHandler : ProfilerHandler { +internal class AsyncProfilerHandler(val profilerConfig: ProfilerConfig) : ProfilerHandler { private val asyncProfiler: Any @@ -48,20 +48,20 @@ internal class AsyncProfilerHandler : ProfilerHandler { executeMethod.invoke(asyncProfiler, command) } - override fun startProfiling(activityName: String, config: ProfilerConfig) { + override fun startProfiling() { try { - profilingOptions = config.options - execute(AsyncProfilerCommandBuilder.buildStartCommand(config.options)) + profilingOptions = profilerConfig.options + execute(AsyncProfilerCommandBuilder.buildStartCommand(profilerConfig.options)) profilingStarted = true } catch (e: Exception) { throw RuntimeException(e) } } - override fun stopProfiling(snapshotsPath: String, activityName: String, config: ProfilerConfig) { - val combinedOptions = ArrayList(config.options) - val commandBuilder = AsyncProfilerCommandBuilder(snapshotsPath) - val name = activityName.replace(' ', '_').replace('/', '_') + override fun stopProfiling(attempt: Int) { + val combinedOptions = ArrayList(profilerConfig.options) + val commandBuilder = AsyncProfilerCommandBuilder(profilerConfig.path) + val name = "${profilerConfig.name}-$attempt".replace(' ', '_').replace('/', '_') val stopAndDumpCommands = commandBuilder.buildStopAndDumpCommands(name, combinedOptions) for (stopCommand in stopAndDumpCommands) { execute(stopCommand) 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 e489effc50e..aeca01165a8 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 @@ -7,11 +7,15 @@ 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.Companion.determinePhasePath import org.jetbrains.kotlin.idea.perf.profilers.doOrThrow import org.jetbrains.kotlin.idea.perf.util.logMessage +import java.io.PrintWriter +import java.io.StringWriter import java.lang.management.ManagementFactory import java.lang.reflect.Method import java.nio.file.Files +import java.nio.file.Path import java.nio.file.Paths /** @@ -19,9 +23,10 @@ import java.nio.file.Paths * - ${YOURKIT_PROFILER_HOME}/lib/yjp-controller-api-redist.jar has to be in a classpath * - add agentpath vm paramter like `-agentpath:${YOURKIT_PROFILER_HOME}/Resources/bin/mac/libyjpagent.dylib` */ -class YKProfilerHandler : ProfilerHandler { +class YKProfilerHandler(val profilerConfig: ProfilerConfig) : ProfilerHandler { private var controller: Any + lateinit var phasePath: Path init { check(ManagementFactory.getRuntimeMXBean().inputArguments.any { it.contains("yjpagent") }) { @@ -33,20 +38,28 @@ class YKProfilerHandler : ProfilerHandler { } } - override fun startProfiling(activityName: String, config: ProfilerConfig) { - if (config.tracing) - startTracingMethod.invoke(controller, null) - else - startCPUSamplingMethod.invoke(controller, null) + override fun startProfiling() { + try { + if (profilerConfig.tracing) { + startTracingMethod.invoke(controller, null) + } else { + startSamplingMethod.invoke(controller, null) + } + } catch (e: Exception) { + val stringWriter = StringWriter().also { e.printStackTrace(PrintWriter(it)) } + logMessage { "exception while starting profile ${e.localizedMessage} $stringWriter" } + } } - 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).resolve(activityName) - logMessage { "dump is moved to $target" } - Files.move(path, target) + override fun stopProfiling(attempt: Int) { + val pathToSnapshot = captureSnapshotMethod.invoke(controller, SNAPSHOT_WITHOUT_HEAP) as String + stopCpuProfilingMethod.invoke(controller) + val dumpPath = Paths.get(pathToSnapshot) + if (!this::phasePath.isInitialized) + phasePath = determinePhasePath(dumpPath, profilerConfig) + val targetFile = phasePath.resolve("$attempt-${profilerConfig.name}.snapshot") + logMessage { "dump is moved to $targetFile" } + Files.move(dumpPath, targetFile) } companion object { @@ -55,9 +68,9 @@ class YKProfilerHandler : ProfilerHandler { private val ykLibClass: Class<*> = doOrThrow("yjp-controller-api-redist.jar is not in a classpath") { Class.forName("com.yourkit.api.Controller") } - private val startCPUSamplingMethod: Method = doOrThrow("com.yourkit.api.Controller#startCPUSampling(String) not found") { + private val startSamplingMethod: Method = doOrThrow("com.yourkit.api.Controller#startSampling(String) not found") { ykLibClass.getMethod( - "startCPUSampling", + "startSampling", String::class.java ) } @@ -74,12 +87,13 @@ class YKProfilerHandler : ProfilerHandler { ) } - private val capturePerformanceSnapshotMethod: Method = doOrThrow("com.yourkit.api.Controller#capturePerformanceSnapshot() not found") { - ykLibClass.getMethod("capturePerformanceSnapshot") - } + 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") + private val stopCpuProfilingMethod: Method = doOrThrow("com.yourkit.api.Controller#stopCPUProfiling() not found") { + ykLibClass.getMethod("stopCpuProfiling") } } } \ No newline at end of file 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 422d5b575ba..af10f214ae7 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 @@ -61,11 +61,11 @@ class PerformanceSuite { } } - private fun PsiFile.highlightFile(): List { + private fun PsiFile.highlightFile(toIgnore: IntArray = ArrayUtilRt.EMPTY_INT_ARRAY): List { val document = FileDocumentManager.getInstance().getDocument(virtualFile)!! val editor = EditorFactory.getInstance().getEditors(document).first() PsiDocumentManager.getInstance(project).commitAllDocuments() - return CodeInsightTestFixtureImpl.instantiateAndRun(this, editor, ArrayUtilRt.EMPTY_INT_ARRAY, true) + return CodeInsightTestFixtureImpl.instantiateAndRun(this, editor, toIgnore, true) } fun rollbackChanges(vararg file: VirtualFile) { @@ -139,7 +139,6 @@ class PerformanceSuite { tearDown { after?.invoke() } - profilerEnabled(config.profile) profilerConfig(config.profilerConfig) } return value @@ -216,7 +215,7 @@ class PerformanceSuite { } - class StatsScopeConfig(var name: String? = null, var warmup: Int = 2, var iterations: Int = 5, var profile: Boolean = false, var profilerConfig: ProfilerConfig = ProfilerConfig()) + class StatsScopeConfig(var name: String? = null, var warmup: Int = 2, var iterations: Int = 5, var profilerConfig: ProfilerConfig = ProfilerConfig()) class ProjectScopeConfig(val path: String, val openWith: ProjectOpenAction, val refresh: Boolean = false) { val name: String = path.lastPathSegment() @@ -239,10 +238,8 @@ class PerformanceSuite { fun highlight(fixture: Fixture) = highlight(fixture.psiFile) - fun highlight(editorFile: PsiFile?) = - editorFile?.let { - it.highlightFile() - } ?: error("editor isn't ready for highlight") + fun highlight(editorFile: PsiFile?, toIgnore: IntArray = ArrayUtilRt.EMPTY_INT_ARRAY) = + editorFile?.highlightFile(toIgnore) ?: error("editor isn't ready for highlight") fun moveCursor(config: TypingConfig) { val fixture = config.fixture @@ -322,7 +319,7 @@ class PerformanceSuite { fun measure(vararg name: String, f: MeasurementScope.() -> Unit): List { val after = { PsiManager.getInstance(project).dropPsiCaches() } - return app.stats.measure("${name.joinToString("-")}", f, after) + return app.stats.measure(name.joinToString("-"), f, after) } fun measure(vararg name: String, fixture: Fixture, f: MeasurementScope.() -> Unit): List =