Compare commits

...

2 Commits

Author SHA1 Message Date
Vladimir Dolzhenko
9704a56344 No ResolveModulePerSourceSet 2020-05-19 17:38:54 +02:00
Vladimir Dolzhenko
081b9d6d13 Projects HL perf test 2020-05-18 23:07:23 +02:00
15 changed files with 361 additions and 82 deletions

View File

@@ -67,6 +67,8 @@ javadocJar()
apply(from = "$rootDir/gradle/kotlinPluginPublication.gradle.kts")
projectTest(taskName = "performanceTest") {
exclude("**/*WholeProjectPerformanceTest*")
val currentOs = org.gradle.internal.os.OperatingSystem.current()
if (!currentOs.isWindows) {
@@ -109,4 +111,36 @@ projectTest(taskName = "performanceTest") {
}
}
projectTest(taskName = "wholeProjectsPerformanceTest") {
exclude(
"**/*Generated*",
"**/*PerformanceProjectsTest*",
"**/*PerformanceStressTest*",
"**/*PerformanceNativeProjectsTest*"
)
include("**/*WholeProjectPerformanceTest*")
workingDir = rootDir
jvmArgs?.removeAll { it.startsWith("-Xmx") }
maxHeapSize = "3g"
jvmArgs("-DperformanceProjects=${System.getProperty("performanceProjects")}")
jvmArgs("-Didea.debug.mode=true")
jvmArgs("-XX:SoftRefLRUPolicyMSPerMB=50")
jvmArgs(
"-XX:ReservedCodeCacheSize=240m",
"-XX:+UseCompressedOops",
"-XX:+UseConcMarkSweepGC"
)
doFirst {
systemProperty("idea.home.path", intellijRootDir().canonicalPath)
project.findProperty("cacheRedirectorEnabled")?.let {
systemProperty("kotlin.test.gradle.import.arguments", "-PcacheRedirectorEnabled=$it")
}
}
}
testsJar()

View File

@@ -45,7 +45,6 @@ import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.close
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFileInEditor
import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.openFixture
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.SIMPLE_JAVA_MODULE
import org.jetbrains.kotlin.idea.util.getProjectJdkTableSafe
import java.io.File
@@ -75,17 +74,20 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
val javaSdk = JavaSdk.getInstance()
jdk18 = javaSdk.createJdk("1.8", homePath)
val internal = javaSdk.createJdk("IDEA jdk", homePath)
val gradle = javaSdk.createJdk(GRADLE_JDK_NAME, homePath)
val jdkTable = getProjectJdkTableSafe()
jdkTable.addJdk(jdk18, testRootDisposable)
jdkTable.addJdk(internal, testRootDisposable)
jdkTable.addJdk(gradle, testRootDisposable)
KotlinSdkType.setUpIfNeeded()
}
GradleProcessOutputInterceptor.install(testRootDisposable)
}
protected fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) {
internal fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) {
assertTrue(filesToHighlight.isNotEmpty())
val project = openProject()
@@ -123,14 +125,73 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() {
return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName
}
protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project =
perfOpenProject(
name = "helloKotlin",
stats = stats,
note = note,
path = "idea/testData/perfTest/helloKotlin",
openAction = SIMPLE_JAVA_MODULE
)
protected fun perfOpenProject(
stats: Stats,
note: String = "",
fast: Boolean = false,
initializer: ProjectBuilder.() -> Unit,
): Project {
val projectBuilder = ProjectBuilder().apply(initializer)
val name = projectBuilder.name
val openProjectOperation = projectBuilder.openProjectOperation()
val warmUpIterations = if (fast) 0 else 5
val iterations = if (fast) 1 else 5
var lastProject: Project? = null
var counter = 0
performanceTest<Unit, Project> {
name("open project $name${if (note.isNotEmpty()) " $note" else ""}")
stats(stats)
warmUpIterations(warmUpIterations)
iterations(iterations)
checkStability(!fast)
test {
it.value = openProjectOperation.openProject()
}
tearDown {
it.value?.let { project ->
lastProject = project
openProjectOperation.postOpenProject(project)
logMessage { "project '$name' successfully opened" }
// close all project but last - we're going to return and use it further
if (counter < warmUpIterations + iterations - 1) {
myApplication.setDataProvider(null)
logMessage { "project '$name' is about to be closed" }
closeProject(project)
logMessage { "project '$name' successfully closed" }
}
counter++
}
}
}
// indexing
lastProject?.let { project ->
invalidateLibraryCache(project)
CodeInsightTestFixtureImpl.ensureIndexesUpToDate(project)
dispatchAllInvocationEvents()
logMessage { "project $name is ${if (project.isInitialized) "initialized" else "not initialized"}" }
with(DumbService.getInstance(project)) {
queueTask(UnindexedFilesUpdater(project))
completeJustSubmittedTasks()
}
dispatchAllInvocationEvents()
Fixture.enableAnnotatorsAndLoadDefinitions(project)
myApplication.setDataProvider(TestDataProvider(project))
}
return lastProject ?: error("unable to open project $name")
}
protected fun perfOpenProject(
name: String,

View File

@@ -5,10 +5,14 @@
package org.jetbrains.kotlin.idea.perf
import java.io.File
import java.nio.file.*
fun Path.copyRecursively(targetDirectory: Path) {
val src = this
Files.walk(src)
.forEach { source -> Files.copy(source, targetDirectory.resolve(src.relativize(source)), StandardCopyOption.REPLACE_EXISTING) }
}
}
fun File.allFilesWithExtension(ext: String): Iterable<File> =
walk().filter { it.isFile && it.extension.equals(ext, ignoreCase = true) }.toList()

View File

@@ -0,0 +1,118 @@
/*
* 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.openapi.module.impl.ProjectLoadingErrorsHeadlessNotifier
import org.jetbrains.kotlin.idea.perf.Stats.Companion.printStatValue
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction
import org.jetbrains.kotlin.idea.testFramework.logMessage
import java.io.File
class HighlightWholeProjectPerformanceTest : AbstractPerformanceProjectsTest() {
companion object {
@JvmStatic
val hwStats: Stats = Stats("helloWorld project")
@JvmStatic
val warmUp = WarmUpProject(hwStats)
init {
// there is no @AfterClass for junit3.8
Runtime.getRuntime().addShutdownHook(Thread { hwStats.close() })
}
}
override fun setUp() {
super.setUp()
warmUp.warmUp(this)
val allowedErrorDescription = setOf(
"Unknown artifact type: war",
"Unknown artifact type: exploded-war"
)
ProjectLoadingErrorsHeadlessNotifier.setErrorHandler(
{ errorDescription ->
val description = errorDescription.description
if (description !in allowedErrorDescription) {
throw RuntimeException(description)
} else {
logMessage { "project loading error: '$description' at '${errorDescription.elementName}'" }
}
}, testRootDisposable
)
}
fun testHighlightAllKtFilesInProject() {
val projectSpecs = projectSpecs()
for (projectSpec in projectSpecs) {
val projectName = projectSpec.name
val projectPath = projectSpec.path
logMessage { "going to open project '$projectName' at $projectPath" }
val suiteName = "$projectName project"
tcSuite(suiteName) {
val stats = Stats(suiteName)
stats.use { stat ->
perfGradleBasedProject(projectName, projectPath, stat)
//perfJpsBasedProject(projectName, stat)
val project = myProject!!
project.projectFilePath
val projectDir = File(projectPath)
val ktFiles = projectDir.allFilesWithExtension("kt").toList()
printStatValue("$suiteName: number of kt files", ktFiles.size)
ktFiles.forEach { file ->
val path = file.path
val localPath = path.substring(path.indexOf(projectPath) + projectPath.length + 1)
logMessage { "going to highlight $localPath" }
perfHighlightFile(localPath, stats = stat)
}
}
}
}
}
private fun perfGradleBasedProject(name: String, path: String, stats: Stats) {
myProject = perfOpenProject(
name = name,
stats = stats,
note = "",
path = path,
openAction = ProjectOpenAction.GRADLE_PROJECT,
fast = true
)
}
private fun perfJpsBasedProject(name: String, stats: Stats) {
myProject = perfOpenProject(
name = name,
stats = stats,
note = "",
path = "../$name",
openAction = ProjectOpenAction.EXISTING_IDEA_PROJECT,
fast = true
)
}
private fun projectSpecs(): List<ProjectSpec> {
val projects = System.getProperty("performanceProjects") ?: return emptyList()
return projects.split(",").map {
val idx = it.indexOf("=")
if (idx <= 0) ProjectSpec(it, "../$it") else ProjectSpec(it.substring(0, idx), it.substring(idx + 1))
}.filter {
val path = File(it.path)
path.exists() && path.isDirectory
}
}
private data class ProjectSpec(val name: String, val path: String)
}

View File

@@ -8,13 +8,11 @@ package org.jetbrains.kotlin.idea.perf
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.lang.annotation.AnnotationHolder
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Disposer
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiChecker
import org.jetbrains.kotlin.idea.highlighter.KotlinPsiCheckerAndHighlightingUpdater
import org.jetbrains.kotlin.idea.perf.Stats.Companion.TEST_KEY
import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP
import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure
import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite
import org.jetbrains.kotlin.idea.testFramework.Fixture
@@ -29,10 +27,10 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
companion object {
@JvmStatic
var warmedUp: Boolean = false
val hwStats: Stats = Stats("helloWorld project")
@JvmStatic
val hwStats: Stats = Stats("helloWorld project")
val warmUp = WarmUpProject(hwStats)
@JvmStatic
val timer: AtomicLong = AtomicLong()
@@ -53,17 +51,28 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() {
override fun setUp() {
super.setUp()
// warm up: open simple small project
if (!warmedUp) {
warmUpProject(hwStats, "src/HelloMain.kt") { perfOpenHelloWorld(hwStats, WARM_UP) }
warmedUp = true
}
warmUp.warmUp(this)
}
fun testHelloWorldProject() {
tcSuite("Hello world project") {
myProject = perfOpenHelloWorld(hwStats)
myProject = perfOpenProject(stats = hwStats) {
name("helloKotlin")
kotlinFile("HelloMain") {
topFunction("main") {
param("args", "Array<String>")
body("""println("Hello World!")""")
}
}
kotlinFile("HelloMain2") {
topFunction("main") {
param("args", "Array<String>")
body("""println("Hello World!")""")
}
}
}
// highlight
perfHighlightFile("src/HelloMain.kt", hwStats)

View File

@@ -12,10 +12,10 @@ class PerformanceStressTest : AbstractPerformanceProjectsTest() {
companion object {
@JvmStatic
var warmedUp: Boolean = false
val hwStats: Stats = Stats("helloWorld project")
@JvmStatic
val hwStats: Stats = Stats("helloWorld project")
val warmUp = WarmUpProject(hwStats)
init {
// there is no @AfterClass for junit3.8
@@ -26,22 +26,7 @@ class PerformanceStressTest : AbstractPerformanceProjectsTest() {
override fun setUp() {
super.setUp()
// warm up: open simple small project
if (!warmedUp) {
warmUpProject(hwStats, "src/HelloMain.kt") {
openProject {
name("helloWorld")
kotlinFile("HelloMain") {
topFunction("main") {
param("args", "Array<String>")
body("""println("Hello World!")""")
}
}
}
}
warmedUp = true
}
warmUp.warmUp(this)
}
fun testLotsOfOverloadedMethods() {

View File

@@ -209,31 +209,53 @@ class ProjectBuilder {
//
return targetDirectory.toAbsolutePath().toFile().absolutePath
}
fun openProjectOperation(): OpenProjectOperation {
val builder = this
val projectPath = generateFiles()
val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx()
val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") {
jdkTableImpl.internalJdk.homeDirectory!!.parent.path
} else {
jdkTableImpl.internalJdk.homePath!!
}
val javaSdk = JavaSdk.getInstance()
val jdk18 = javaSdk.createJdk("1.8", homePath)
val openAction = if (buildGradle != null) ProjectOpenAction.GRADLE_PROJECT else ProjectOpenAction.SIMPLE_JAVA_MODULE
val openProject = OpenProject(
projectPath = projectPath,
projectName = name,
jdk = jdk18,
projectOpenAction = openAction
)
return object : OpenProjectOperation {
override fun openProject() = ProjectOpenAction.openProject(openProject)
override fun postOpenProject(project: Project) {
openAction.postOpenProject(project = project, openProject = openProject)
if (builder.initDefaultProfile) {
openAction.initDefaultProfile(project)
}
}
}
}
}
interface OpenProjectOperation {
fun openProject(): Project
fun postOpenProject(project: Project)
}
fun openProject(initializer: ProjectBuilder.() -> Unit): Project {
val projectBuilder = ProjectBuilder().apply(initializer)
val projectPath = projectBuilder.generateFiles()
val openProject = projectBuilder.openProjectOperation()
val jdkTableImpl = JavaAwareProjectJdkTableImpl.getInstanceEx()
val homePath = if (jdkTableImpl.internalJdk.homeDirectory!!.name == "jre") {
jdkTableImpl.internalJdk.homeDirectory!!.parent.path
} else {
jdkTableImpl.internalJdk.homePath!!
return openProject.openProject().also {
openProject.postOpenProject(it)
}
val javaSdk = JavaSdk.getInstance()
val jdk18 = javaSdk.createJdk("1.8", homePath)
val openAction = if (projectBuilder.buildGradle != null) ProjectOpenAction.GRADLE_PROJECT else ProjectOpenAction.SIMPLE_JAVA_MODULE
val openProject = OpenProject(
projectPath = projectPath,
projectName = projectBuilder.name,
jdk = jdk18,
projectOpenAction = openAction
)
val project = ProjectOpenAction.openProject(openProject)
openAction.postOpenProject(project = project, openProject = openProject)
if (projectBuilder.initDefaultProfile) {
openAction.initDefaultProfile(project)
}
return project
}

View File

@@ -0,0 +1,30 @@
/*
* 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
/**
* warm up: open simple `hello world` project
*/
class WarmUpProject(private val stats: Stats) {
private var warmedUp: Boolean = false
fun warmUp(test: AbstractPerformanceProjectsTest) {
if (warmedUp) return
test.warmUpProject(stats, "src/HelloMain.kt") {
openProject {
name("helloWorld")
kotlinFile("HelloMain") {
topFunction("main") {
param("args", "Array<String>")
body("""println("Hello World!")""")
}
}
}
}
warmedUp = true
}
}

View File

@@ -16,6 +16,7 @@ import com.intellij.lang.LanguageAnnotators
import com.intellij.lang.StdLanguages
import com.intellij.lang.injection.InjectedLanguageManager
import com.intellij.lang.java.JavaLanguage
import com.intellij.lang.xml.XMLLanguage
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
@@ -43,7 +44,6 @@ import junit.framework.TestCase.*
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.idea.core.script.ScriptConfigurationManager
import org.jetbrains.kotlin.idea.core.script.ScriptDefinitionsManager
import org.jetbrains.kotlin.idea.core.script.settings.KotlinScriptingSettings
import org.jetbrains.kotlin.idea.core.util.toPsiFile
import org.jetbrains.kotlin.parsing.KotlinParserDefinition
import java.io.Closeable
@@ -128,7 +128,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
InjectedLanguageManager.getInstance(project) // zillion of Dom Sem classes
with(LanguageAnnotators.INSTANCE) {
allForLanguage(JavaLanguage.INSTANCE) // pile of annotator classes loads
allForLanguage(StdLanguages.XML)
allForLanguage(XMLLanguage.INSTANCE)
allForLanguage(KotlinLanguage.INSTANCE)
}
DaemonAnalyzerTestCase.assertTrue(
@@ -147,7 +147,7 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
dispatchAllInvocationEvents()
assertTrue(scriptDefinitionsManager.isReady())
assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
//assertFalse(KotlinScriptingSettings.getInstance(project).isAutoReloadEnabled)
}
@@ -177,10 +177,10 @@ class Fixture(val project: Project, val editor: Editor, val psiFile: PsiFile, va
val projectBaseName = baseName(project.name)
val virtualFiles = FilenameIndex.getVirtualFilesByName(
project,
baseFileName, true,
GlobalSearchScope.projectScope(project)
)
project,
baseFileName, true,
GlobalSearchScope.projectScope(project)
)
.filter { it.canonicalPath?.contains("/$projectBaseName/$name") ?: false }.toList()
assertEquals(

View File

@@ -44,8 +44,10 @@ private class GradleProcessOutputInterceptorImpl : GradleProcessOutputIntercepto
private val buffer = StringBuilder()
override fun onTaskOutput(id: ExternalSystemTaskId, text: String, stdOut: Boolean) {
if (id.projectSystemId == GRADLE_SYSTEM_ID && text.isNotEmpty())
if (id.projectSystemId == GRADLE_SYSTEM_ID && text.isNotEmpty()) {
print("#gradle $text")
buffer.append(text)
}
}
override fun reset() = buffer.setLength(0)

View File

@@ -89,11 +89,6 @@ enum class ProjectOpenAction {
refreshGradleProject(projectPath, project)
assertTrue(
ModuleManager.getInstance(project).modules.isNotEmpty(),
"Gradle project $projectName at $projectPath has to have at least one module"
)
return project
}

View File

@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.jetbrains.plugins.gradle.util.GradleLog
import java.io.File
@@ -26,6 +27,8 @@ fun refreshGradleProject(projectPath: String, project: Project) {
dispatchAllInvocationEvents()
}
const val GRADLE_JDK_NAME = "Gradle JDK"
/**
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
*/
@@ -34,7 +37,19 @@ private fun _importProject(projectPath: String, project: Project) {
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
val gradleProjectSettings = GradleProjectSettings()
GradleSettings.getInstance(project).gradleVmOptions =
"-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
// TODO: [VD] temporary !
gradleProjectSettings.isResolveModulePerSourceSet = false
GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
linkedProjectSettings.gradleJvm = GRADLE_JDK_NAME
linkedProjectSettings.isResolveModulePerSourceSet = false
}
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
}

View File

@@ -15,6 +15,7 @@ import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ProjectRootManager
import org.jetbrains.plugins.gradle.service.project.open.setupGradleSettings
import org.jetbrains.plugins.gradle.settings.GradleProjectSettings
import org.jetbrains.plugins.gradle.settings.GradleSettings
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.jetbrains.plugins.gradle.util.GradleLog
import java.io.File
@@ -26,6 +27,8 @@ fun refreshGradleProject(projectPath: String, project: Project) {
dispatchAllInvocationEvents()
}
const val GRADLE_JDK_NAME = "Gradle JDK"
/**
* inspired by org.jetbrains.plugins.gradle.service.project.open.importProject(projectDirectory, project)
*/
@@ -34,7 +37,16 @@ private fun _importProject(projectPath: String, project: Project) {
val projectSdk = ProjectRootManager.getInstance(project).projectSdk
assertNotNull(projectSdk, "project SDK not found for ${project.name} at $projectPath")
val gradleProjectSettings = GradleProjectSettings()
GradleSettings.getInstance(project).gradleVmOptions =
"-Xmx2048m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=${System.getProperty("user.dir")}"
setupGradleSettings(gradleProjectSettings, projectPath, project, projectSdk)
gradleProjectSettings.gradleJvm = GRADLE_JDK_NAME
GradleSettings.getInstance(project).getLinkedProjectSettings(projectPath)?.let { linkedProjectSettings ->
linkedProjectSettings.gradleJvm = GRADLE_JDK_NAME
}
_attachGradleProjectAndRefresh(gradleProjectSettings, project)
}

View File

@@ -1,4 +0,0 @@
fun main(args: Array<String>) {
println("Hello World!")
}

View File

@@ -1,4 +0,0 @@
fun main(args: Array<String>) {
println("Hello World!")
}