From ca3c72c1439cc006adae7b7ed3b89dc93189c231 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 21 Feb 2020 19:23:55 +0700 Subject: [PATCH] IDE perf tests for Kotlin/Native projects Issue #MMPP-201 --- .../perf/AbstractPerformanceProjectsTest.kt | 86 ++----- .../perf/PerformanceNativeProjectsTest.kt | 229 ++++++++++++++++++ .../idea/perf/PerformanceProjectsTest.kt | 28 ++- .../idea/testFramework/ProjectOpenAction.kt | 79 ++++++ .../perfTest/native/CsvParser/.gitignore | 4 + .../native/CsvParser/build.gradle.kts | 15 ++ .../native/CsvParser/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../native/CsvParser/settings.gradle.kts | 7 + .../src/iosX64Main/kotlin/CsvParser.kt | 77 ++++++ .../src/iosX64Main/kotlin/CsvParser2.kt | 77 ++++++ .../src/iosX64Main/kotlin/CsvParser3.kt | 77 ++++++ .../perfTest/native/HelloWorld/.gitignore | 4 + .../native/HelloWorld/build.gradle.kts | 13 + .../native/HelloWorld/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../native/HelloWorld/settings.gradle.kts | 7 + .../src/iosX64Main/kotlin/HelloMain.kt | 4 + .../src/iosX64Main/kotlin/HelloMain2.kt | 4 + .../src/iosX64Main/kotlin/HelloMain3.kt | 4 + .../src/iosX64Test/kotlin/HelloTest.kt | 11 + .../src/iosX64Test/kotlin/HelloTest2.kt | 11 + .../src/iosX64Test/kotlin/HelloTest3.kt | 11 + .../perfTest/native/UIKitApp/.gitignore | 4 + .../perfTest/native/UIKitApp/build.gradle.kts | 13 + .../native/UIKitApp/gradle.properties | 2 + .../gradle/wrapper/gradle-wrapper.properties | 5 + .../native/UIKitApp/settings.gradle.kts | 7 + .../src/iosX64Main/kotlin/UIKitApp.kt | 140 +++++++++++ .../src/iosX64Main/kotlin/UIKitApp2.kt | 140 +++++++++++ .../src/iosX64Main/kotlin/UIKitApp3.kt | 140 +++++++++++ 31 files changed, 1143 insertions(+), 70 deletions(-) create mode 100644 idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceNativeProjectsTest.kt create mode 100644 idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/ProjectOpenAction.kt create mode 100644 idea/testData/perfTest/native/CsvParser/.gitignore create mode 100644 idea/testData/perfTest/native/CsvParser/build.gradle.kts create mode 100644 idea/testData/perfTest/native/CsvParser/gradle.properties create mode 100644 idea/testData/perfTest/native/CsvParser/gradle/wrapper/gradle-wrapper.properties create mode 100644 idea/testData/perfTest/native/CsvParser/settings.gradle.kts create mode 100644 idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser.kt create mode 100644 idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser2.kt create mode 100644 idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser3.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/.gitignore create mode 100644 idea/testData/perfTest/native/HelloWorld/build.gradle.kts create mode 100644 idea/testData/perfTest/native/HelloWorld/gradle.properties create mode 100644 idea/testData/perfTest/native/HelloWorld/gradle/wrapper/gradle-wrapper.properties create mode 100644 idea/testData/perfTest/native/HelloWorld/settings.gradle.kts create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain2.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain3.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest2.kt create mode 100644 idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest3.kt create mode 100644 idea/testData/perfTest/native/UIKitApp/.gitignore create mode 100644 idea/testData/perfTest/native/UIKitApp/build.gradle.kts create mode 100644 idea/testData/perfTest/native/UIKitApp/gradle.properties create mode 100644 idea/testData/perfTest/native/UIKitApp/gradle/wrapper/gradle-wrapper.properties create mode 100644 idea/testData/perfTest/native/UIKitApp/settings.gradle.kts create mode 100644 idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp.kt create mode 100644 idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp2.kt create mode 100644 idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp3.kt 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 26e2130673f..c8227c1e1f3 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/AbstractPerformanceProjectsTest.kt @@ -11,7 +11,6 @@ import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerImpl import com.intellij.codeInsight.daemon.impl.HighlightInfo import com.intellij.codeInsight.daemon.impl.IdentifierHighlighterPassFactory import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.ide.highlighter.ModuleFileType import com.intellij.ide.startup.impl.StartupManagerImpl import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.application.ApplicationManager @@ -20,26 +19,23 @@ import com.intellij.openapi.editor.EditorFactory import com.intellij.openapi.externalSystem.service.project.manage.ExternalProjectsManagerImpl import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.fileEditor.impl.FileEditorManagerImpl import com.intellij.openapi.module.ModuleManager -import com.intellij.openapi.module.ModuleTypeId import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project -import com.intellij.openapi.project.ex.ProjectManagerEx -import com.intellij.openapi.project.impl.ProjectImpl import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.Sdk import com.intellij.openapi.projectRoots.impl.JavaAwareProjectJdkTableImpl -import com.intellij.openapi.roots.ProjectRootManager import com.intellij.openapi.startup.StartupManager import com.intellij.openapi.vcs.changes.ChangeListManager import com.intellij.openapi.vcs.changes.ChangeListManagerImpl -import com.intellij.openapi.vfs.LocalFileSystem import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.psi.PsiDocumentManager import com.intellij.psi.PsiFile import com.intellij.psi.PsiManager -import com.intellij.testFramework.* +import com.intellij.testFramework.EditorTestUtil +import com.intellij.testFramework.RunAll +import com.intellij.testFramework.TestDataProvider +import com.intellij.testFramework.UsefulTestCase import com.intellij.testFramework.fixtures.impl.CodeInsightTestFixtureImpl import com.intellij.util.ArrayUtilRt import com.intellij.util.ThrowableRunnable @@ -51,7 +47,6 @@ import org.jetbrains.kotlin.idea.framework.KotlinSdkType import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP import org.jetbrains.kotlin.idea.perf.Stats.Companion.runAndMeasure import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies -import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil import org.jetbrains.kotlin.idea.test.invalidateLibraryCache import org.jetbrains.kotlin.idea.testFramework.* import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches @@ -98,11 +93,15 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } } - protected fun warmUpProject(stats: Stats) { - val project = perfOpenHelloWorld(stats, WARM_UP) + protected fun warmUpProject(stats: Stats, vararg filesToHighlight: String, openProject: () -> Project) { + assertTrue(filesToHighlight.isNotEmpty()) + + val project = openProject() try { - val perfHighlightFile = perfHighlightFile(project, "src/HelloMain.kt", stats, WARM_UP) - assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty()) + filesToHighlight.forEach { + val perfHighlightFile = perfHighlightFile(project, it, stats, WARM_UP) + assertTrue("kotlin project has been not imported properly", perfHighlightFile.isNotEmpty()) + } } finally { closeProject(project) myApplication.setDataProvider(null) @@ -130,22 +129,12 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { return if (lastIndexOf >= 0) fileName.substring(lastIndexOf + 1) else fileName } - protected fun perfOpenKotlinProjectFast(stats: Stats) = - perfOpenKotlinProject(stats, fast = true) - - protected fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) { - myProject = innerPerfOpenProject("kotlin", stats = stats, path = "../perfTestProject", note = "", fast = fast) - } - - protected fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project = - innerPerfOpenProject("helloKotlin", stats, note, path = "idea/testData/perfTest/helloKotlin", simpleModule = true) - - protected fun innerPerfOpenProject( + protected fun perfOpenProject( name: String, stats: Stats, note: String, path: String, - simpleModule: Boolean = false, + openAction: ProjectOpenAction, fast: Boolean = false ): Project { val projectPath = File(path).canonicalPath @@ -154,7 +143,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { val warmUpIterations = if (fast) 0 else 5 val iterations = if (fast) 1 else 5 - val projectManagerEx = ProjectManagerEx.getInstanceEx() var lastProject: Project? = null var counter = 0 @@ -166,27 +154,10 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { iterations(iterations) checkStability(!fast) test { - val project = if (!simpleModule) { - val project = loadProjectWithName(name = name, path = path) - assertNotNull("project $name at $path is not loaded", project) - val projectRootManager = ProjectRootManager.getInstance(project!!) - - runWriteAction { - with(projectRootManager) { - projectSdk = jdk18 - } - } - assertTrue("project $name at $path is not opened", projectManagerEx.openProject(project)) - project - } else { - val project = projectManagerEx.loadAndOpenProject(projectPath)!! - initKotlinProject(project, projectPath, name) - project - } - - (project as ProjectImpl).registerComponentImplementation( - FileEditorManager::class.java, - FileEditorManagerImpl::class.java + val project = openAction.openProject( + projectPath = path, + projectName = name, + jdk = jdk18 ) dispatchAllInvocationEvents() @@ -537,27 +508,6 @@ abstract class AbstractPerformanceProjectsTest : UsefulTestCase() { } } - private fun initKotlinProject( - project: Project, - projectPath: String, - name: String - ) { - val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}" - val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!! - val srcFile = projectFile.findChild("src")!! - val module = runWriteAction { - val projectRootManager = ProjectRootManager.getInstance(project) - with(projectRootManager) { - projectSdk = jdk18 - } - val moduleManager = ModuleManager.getInstance(project) - val module = moduleManager.newModule(modulePath, ModuleTypeId.JAVA_MODULE) - PsiTestUtil.addSourceRoot(module, srcFile) - module - } - ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk18) - } - protected fun perfHighlightFile(name: String, stats: Stats): List = perfHighlightFile(project(), name, stats) diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceNativeProjectsTest.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceNativeProjectsTest.kt new file mode 100644 index 00000000000..b331131d8f0 --- /dev/null +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceNativeProjectsTest.kt @@ -0,0 +1,229 @@ +/* + * 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.application.runReadAction +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.rootManager +import com.intellij.openapi.roots.LibraryOrderEntry +import com.intellij.openapi.roots.OrderRootType +import com.intellij.openapi.util.io.FileUtil +import org.jetbrains.kotlin.gradle.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME +import org.jetbrains.kotlin.ide.konan.NativeLibraryKind +import org.jetbrains.kotlin.idea.caches.project.isMPPModule +import org.jetbrains.kotlin.idea.configuration.klib.KotlinNativeLibraryNameUtil.parseIDELibraryName +import org.jetbrains.kotlin.idea.facet.KotlinFacet +import org.jetbrains.kotlin.idea.framework.CommonLibraryKind +import org.jetbrains.kotlin.idea.framework.detectLibraryKind +import org.jetbrains.kotlin.idea.perf.Stats.Companion.WARM_UP +import org.jetbrains.kotlin.idea.perf.Stats.Companion.tcSuite +import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.GRADLE_PROJECT +import org.jetbrains.kotlin.idea.testFramework.logMessage +import org.jetbrains.kotlin.idea.util.projectStructure.allModules +import org.jetbrains.kotlin.library.KOTLIN_STDLIB_NAME +import org.jetbrains.kotlin.platform.konan.isNative +import java.io.File + +class PerformanceNativeProjectsTest : AbstractPerformanceProjectsTest() { + + companion object { + private const val GRADLE_VERSION = "6.0.1" + private const val KOTLIN_PLUGIN_VERSION = "1.4.0-dev-3273" // TODO: use 1.4-M1 when it's published + + private var warmedUp: Boolean = false + } + + override fun setUp() { + super.setUp() + + // warm up: open simple small project + if (!warmedUp) { + val projectTemplate = "HelloWorld" + val enableCommonizer = true + + val projectName = "${projectName(projectTemplate, enableCommonizer)}-$WARM_UP" + + // don't share this stats instance with another one used in "Hello World" test + Stats(projectName).use { stats -> + warmUpProject(stats, "src/iosX64Main/kotlin/HelloMain.kt") { + perfOpenTemplateGradleProject(stats, projectTemplate, enableCommonizer, WARM_UP) + } + } + + warmedUp = true + } + } + + fun testHelloWorldProjectWithCommonizer() = doTestHighlighting( + "HelloWorld", + true, + "src/iosX64Main/kotlin/HelloMain.kt", + "src/iosX64Main/kotlin/HelloMain2.kt", + "src/iosX64Main/kotlin/HelloMain3.kt", + "src/iosX64Test/kotlin/HelloTest.kt", + "src/iosX64Test/kotlin/HelloTest2.kt", + "src/iosX64Test/kotlin/HelloTest3.kt" + ) + + fun testHelloWorldProjectWithoutCommonizer() = doTestHighlighting( + "HelloWorld", + false, + "src/iosX64Main/kotlin/HelloMain.kt", + "src/iosX64Main/kotlin/HelloMain2.kt", + "src/iosX64Main/kotlin/HelloMain3.kt", + "src/iosX64Test/kotlin/HelloTest.kt", + "src/iosX64Test/kotlin/HelloTest2.kt", + "src/iosX64Test/kotlin/HelloTest3.kt" + ) + + fun testCvsParserProjectWithCommonizer() = doTestHighlighting( + "CsvParser", + true, + "src/iosX64Main/kotlin/CsvParser.kt", + "src/iosX64Main/kotlin/CsvParser2.kt", + "src/iosX64Main/kotlin/CsvParser3.kt" + ) + + fun testCvsParserProjectWithoutCommonizer() = doTestHighlighting( + "CsvParser", + false, + "src/iosX64Main/kotlin/CsvParser.kt", + "src/iosX64Main/kotlin/CsvParser2.kt", + "src/iosX64Main/kotlin/CsvParser3.kt" + ) + + fun testUIKitAppProjectWithCommonizer() = doTestHighlighting( + "UIKitApp", + true, + "src/iosX64Main/kotlin/UIKitApp.kt", + "src/iosX64Main/kotlin/UIKitApp2.kt", + "src/iosX64Main/kotlin/UIKitApp3.kt" + ) + + fun testUIKitAppProjectWithoutCommonizer() = doTestHighlighting( + "UIKitApp", + false, + "src/iosX64Main/kotlin/UIKitApp.kt", + "src/iosX64Main/kotlin/UIKitApp2.kt", + "src/iosX64Main/kotlin/UIKitApp3.kt" + ) + + private fun doTestHighlighting( + templateName: String, + enableCommonizer: Boolean, + vararg filesToHighlight: String + ) { + assertTrue(filesToHighlight.isNotEmpty()) + + val projectName = projectName(templateName, enableCommonizer) + tcSuite(projectName) { + Stats(projectName).use { stats -> + myProject = perfOpenTemplateGradleProject(stats, templateName, enableCommonizer) + + // highlight + filesToHighlight.forEach { perfHighlightFile(it, stats) } + } + } + } + + private fun perfOpenTemplateGradleProject( + stats: Stats, + templateName: String, + enableCommonizer: Boolean, + note: String = "" + ): Project { + val templateRoot = File("idea/testData/perfTest/native/").resolve(templateName) + val projectRoot = FileUtil.createTempDirectory("project", "", false) + + templateRoot.walkTopDown() + .filter { it.isFile } + .forEach { source -> + val destination = projectRoot.resolve(source.relativeTo(templateRoot)) + + val filename = source.name + if (filename == "build.gradle.kts" || filename == "gradle-wrapper.properties" || filename == "gradle.properties") { + val text = source.readText() + .replace("{{kotlin_plugin_version}}", KOTLIN_PLUGIN_VERSION) + .replace("{{gradle_version}}", GRADLE_VERSION) + .replace("{{disable_commonizer}}", (!enableCommonizer).toString()) + + destination.parentFile.mkdirs() + destination.writeText(text) + } else { + source.copyTo(destination) + } + } + + val projectName = projectName(templateName, enableCommonizer, separator = '-') + + val project = perfOpenProject( + name = projectName, + stats = stats, + note = note, + path = projectRoot.absolutePath, + openAction = GRADLE_PROJECT + ) + runProjectSanityChecks(project) + + return project + } + + // goal: make sure that the project imported from Gradle is valid + private fun runProjectSanityChecks(project: Project) { + + val nativeModules: Map> = runReadAction { + project.allModules().mapNotNull { module -> + val facetSettings = KotlinFacet.get(module)?.configuration?.settings ?: return@mapNotNull null + if (!facetSettings.isMPPModule || !facetSettings.targetPlatform.isNative()) return@mapNotNull null + + // workaround to skip top-level common test module, which in fact does not get any Kotlin/Native KLIB libraries + // but accidentally gets Kotlin facet with Native platform + if (module.name == "${project.name}.$COMMON_TEST_SOURCE_SET_NAME") return@mapNotNull null + + val nativeLibraries = module.rootManager.orderEntries + .asSequence() + .filterIsInstance() + .mapNotNull { it.library } + .filter { library -> + val libraryKind = detectLibraryKind(library.getFiles(OrderRootType.CLASSES)) + libraryKind == NativeLibraryKind + // TODO: remove this check for CommonLibraryKind when detection of K/N KLIBs in + // org.jetbrains.kotlin.ide.konan.KotlinNativePluginUtilKt.isKonanLibraryRoot + // is correctly implemented + || libraryKind == CommonLibraryKind + } + .mapNotNull inner@{ library -> + val libraryNameParts = parseIDELibraryName(library.name.orEmpty()) ?: return@inner null + val (_, pureLibraryName, platformPart) = libraryNameParts + pureLibraryName + if (platformPart != null) " [$platformPart]" else "" + } + .toSet() + + module to nativeLibraries + }.toMap() + } + + assertTrue("No Native modules found in project $project", nativeModules.isNotEmpty()) + + nativeModules.forEach { (module, nativeLibraries) -> + assertTrue( + "$KOTLIN_STDLIB_NAME not found for for Native module $module in project $project", + KOTLIN_STDLIB_NAME in nativeLibraries + ) + + assertTrue( + "No Native libraries except for $KOTLIN_STDLIB_NAME for Native module $module in project $project", + (nativeLibraries - KOTLIN_STDLIB_NAME).isNotEmpty() + ) + + logMessage { "$module has ${nativeLibraries.size} native libraries" } + } + } + + private fun projectName(templateName: String, enableCommonizer: Boolean, separator: Char = ' ') = + "$templateName project ${if (enableCommonizer) "with" else "without"} commonizer".replace(' ', separator) +} 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 1cecf63c55e..c2794c19763 100644 --- a/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/perf/PerformanceProjectsTest.kt @@ -14,11 +14,14 @@ 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 import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.cleanupCaches import org.jetbrains.kotlin.idea.testFramework.Fixture.Companion.isAKotlinScriptFile +import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.EXISTING_IDEA_PROJECT +import org.jetbrains.kotlin.idea.testFramework.ProjectOpenAction.SIMPLE_JAVA_MODULE import java.util.concurrent.atomic.AtomicLong import kotlin.test.assertNotEquals @@ -53,8 +56,7 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { super.setUp() // warm up: open simple small project if (!warmedUp) { - warmUpProject(hwStats) - + warmUpProject(hwStats, "src/HelloMain.kt") { perfOpenHelloWorld(hwStats, WARM_UP) } warmedUp = true } } @@ -207,6 +209,28 @@ class PerformanceProjectsTest : AbstractPerformanceProjectsTest() { } } + private fun perfOpenKotlinProjectFast(stats: Stats) = perfOpenKotlinProject(stats, fast = true) + + private fun perfOpenKotlinProject(stats: Stats, fast: Boolean = false) { + myProject = perfOpenProject( + name = "kotlin", + stats = stats, + note = "", + path = "../perfTestProject", + openAction = EXISTING_IDEA_PROJECT, + fast = fast + ) + } + + private fun perfOpenHelloWorld(stats: Stats, note: String = ""): Project = + perfOpenProject( + name = "helloKotlin", + stats = stats, + note = note, + path = "idea/testData/perfTest/helloKotlin", + openAction = SIMPLE_JAVA_MODULE + ) + private fun perfScriptDependenciesBuildGradleKts(it: Stats) { perfScriptDependencies("build.gradle.kts", stats = it) } diff --git a/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/ProjectOpenAction.kt b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/ProjectOpenAction.kt new file mode 100644 index 00000000000..15e8a245af3 --- /dev/null +++ b/idea/performanceTests/test/org/jetbrains/kotlin/idea/testFramework/ProjectOpenAction.kt @@ -0,0 +1,79 @@ +/* + * 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.testFramework + +import com.intellij.ide.highlighter.ModuleFileType +import com.intellij.openapi.application.runWriteAction +import com.intellij.openapi.module.ModuleManager +import com.intellij.openapi.module.ModuleTypeId +import com.intellij.openapi.project.Project +import com.intellij.openapi.project.ex.ProjectManagerEx +import com.intellij.openapi.projectRoots.Sdk +import com.intellij.openapi.roots.ProjectRootManager +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.testFramework.PsiTestUtil +import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil +import java.io.File +import kotlin.test.assertNotNull +import kotlin.test.assertTrue + +enum class ProjectOpenAction { + SIMPLE_JAVA_MODULE { + override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project { + val project = ProjectManagerEx.getInstanceEx().loadAndOpenProject(projectPath)!! + + val modulePath = "$projectPath/$name${ModuleFileType.DOT_DEFAULT_EXTENSION}" + val projectFile = LocalFileSystem.getInstance().refreshAndFindFileByIoFile(File(projectPath))!! + val srcFile = projectFile.findChild("src")!! + + val module = runWriteAction { + ProjectRootManager.getInstance(project).projectSdk = jdk + + val module = ModuleManager.getInstance(project).newModule(modulePath, ModuleTypeId.JAVA_MODULE) + PsiTestUtil.addSourceRoot(module, srcFile) + + module + } + + ConfigLibraryUtil.configureKotlinRuntimeAndSdk(module, jdk) + + return project + } + }, + + EXISTING_IDEA_PROJECT { + override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project { + val projectManagerEx = ProjectManagerEx.getInstanceEx() + + val project = loadProjectWithName(projectPath, projectName) + assertNotNull(project, "project $projectName at $projectPath is not loaded") + + runWriteAction { + ProjectRootManager.getInstance(project).projectSdk = jdk + } + + assertTrue(projectManagerEx.openProject(project), "project $projectName at $projectPath is not opened") + + return project + } + }, + + GRADLE_PROJECT { + override fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project { + val project = ProjectManagerEx.getInstanceEx().loadAndOpenProject(projectPath)!! + + runWriteAction { + ProjectRootManager.getInstance(project).projectSdk = jdk + } + + refreshGradleProject(projectPath, project) + + return project + } + }; + + abstract fun openProject(projectPath: String, projectName: String, jdk: Sdk): Project +} \ No newline at end of file diff --git a/idea/testData/perfTest/native/CsvParser/.gitignore b/idea/testData/perfTest/native/CsvParser/.gitignore new file mode 100644 index 00000000000..2f00c62a3bc --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/.gitignore @@ -0,0 +1,4 @@ +build +.idea +.gradle +gradlew* diff --git a/idea/testData/perfTest/native/CsvParser/build.gradle.kts b/idea/testData/perfTest/native/CsvParser/build.gradle.kts new file mode 100644 index 00000000000..4b7f2363a53 --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/build.gradle.kts @@ -0,0 +1,15 @@ +plugins { + kotlin("multiplatform") version "{{kotlin_plugin_version}}" +} + +repositories { + mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") +} + +kotlin { + ios() { + compilations["main"].enableEndorsedLibs = true + } +} diff --git a/idea/testData/perfTest/native/CsvParser/gradle.properties b/idea/testData/perfTest/native/CsvParser/gradle.properties new file mode 100644 index 00000000000..e5dadd15633 --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/gradle.properties @@ -0,0 +1,2 @@ +kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.native.enableDependencyPropagation={{disable_commonizer}} diff --git a/idea/testData/perfTest/native/CsvParser/gradle/wrapper/gradle-wrapper.properties b/idea/testData/perfTest/native/CsvParser/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..819137c561c --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/idea/testData/perfTest/native/CsvParser/settings.gradle.kts b/idea/testData/perfTest/native/CsvParser/settings.gradle.kts new file mode 100644 index 00000000000..392a06e2437 --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/settings.gradle.kts @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") + } +} diff --git a/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser.kt b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser.kt new file mode 100644 index 00000000000..9ad29895b8d --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser.kt @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import kotlinx.cinterop.ByteVar +import kotlinx.cinterop.allocArray +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toKString +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.required +import platform.posix.fclose +import platform.posix.fgets +import platform.posix.fopen +import platform.posix.perror +import kotlin.collections.set + +private fun parseLine(line: String, separator: Char) : List { + val result = mutableListOf() + val builder = StringBuilder() + var quotes = 0 + for (ch in line) { + when { + ch == '\"' -> { + quotes++ + builder.append(ch) + } + (ch == '\n') || (ch == '\r') -> {} + (ch == separator) && (quotes % 2 == 0) -> { + result.add(builder.toString()) + builder.setLength(0) + } + else -> builder.append(ch) + } + } + return result +} + +fun main(args: Array) { + val argParser = ArgParser("csvparser") + val fileName by argParser.argument(ArgType.String, description = "CSV file") + val column by argParser.option(ArgType.Int, description = "Column to parse").required() + val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required() + argParser.parse(args) + + val file = fopen(fileName, "r") + if (file == null) { + perror("cannot open input file $fileName") + return + } + + val keyValue = mutableMapOf() + + try { + memScoped { + val bufferLength = 64 * 1024 + val buffer = allocArray(bufferLength) + + for (i in 1..count) { + val nextLine = fgets(buffer, bufferLength, file)?.toKString() + if (nextLine == null || nextLine.isEmpty()) break + + val records = parseLine(nextLine, ',') + val key = records[column] + val current = keyValue[key] ?: 0 + keyValue[key] = current + 1 + } + } + } finally { + fclose(file) + } + + keyValue.forEach { + println("${it.key} -> ${it.value}") + } +} diff --git a/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser2.kt b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser2.kt new file mode 100644 index 00000000000..9ad29895b8d --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser2.kt @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import kotlinx.cinterop.ByteVar +import kotlinx.cinterop.allocArray +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toKString +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.required +import platform.posix.fclose +import platform.posix.fgets +import platform.posix.fopen +import platform.posix.perror +import kotlin.collections.set + +private fun parseLine(line: String, separator: Char) : List { + val result = mutableListOf() + val builder = StringBuilder() + var quotes = 0 + for (ch in line) { + when { + ch == '\"' -> { + quotes++ + builder.append(ch) + } + (ch == '\n') || (ch == '\r') -> {} + (ch == separator) && (quotes % 2 == 0) -> { + result.add(builder.toString()) + builder.setLength(0) + } + else -> builder.append(ch) + } + } + return result +} + +fun main(args: Array) { + val argParser = ArgParser("csvparser") + val fileName by argParser.argument(ArgType.String, description = "CSV file") + val column by argParser.option(ArgType.Int, description = "Column to parse").required() + val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required() + argParser.parse(args) + + val file = fopen(fileName, "r") + if (file == null) { + perror("cannot open input file $fileName") + return + } + + val keyValue = mutableMapOf() + + try { + memScoped { + val bufferLength = 64 * 1024 + val buffer = allocArray(bufferLength) + + for (i in 1..count) { + val nextLine = fgets(buffer, bufferLength, file)?.toKString() + if (nextLine == null || nextLine.isEmpty()) break + + val records = parseLine(nextLine, ',') + val key = records[column] + val current = keyValue[key] ?: 0 + keyValue[key] = current + 1 + } + } + } finally { + fclose(file) + } + + keyValue.forEach { + println("${it.key} -> ${it.value}") + } +} diff --git a/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser3.kt b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser3.kt new file mode 100644 index 00000000000..9ad29895b8d --- /dev/null +++ b/idea/testData/perfTest/native/CsvParser/src/iosX64Main/kotlin/CsvParser3.kt @@ -0,0 +1,77 @@ +/* + * 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. + */ + +import kotlinx.cinterop.ByteVar +import kotlinx.cinterop.allocArray +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toKString +import kotlinx.cli.ArgParser +import kotlinx.cli.ArgType +import kotlinx.cli.required +import platform.posix.fclose +import platform.posix.fgets +import platform.posix.fopen +import platform.posix.perror +import kotlin.collections.set + +private fun parseLine(line: String, separator: Char) : List { + val result = mutableListOf() + val builder = StringBuilder() + var quotes = 0 + for (ch in line) { + when { + ch == '\"' -> { + quotes++ + builder.append(ch) + } + (ch == '\n') || (ch == '\r') -> {} + (ch == separator) && (quotes % 2 == 0) -> { + result.add(builder.toString()) + builder.setLength(0) + } + else -> builder.append(ch) + } + } + return result +} + +fun main(args: Array) { + val argParser = ArgParser("csvparser") + val fileName by argParser.argument(ArgType.String, description = "CSV file") + val column by argParser.option(ArgType.Int, description = "Column to parse").required() + val count by argParser.option(ArgType.Int, description = "Count of lines to parse").required() + argParser.parse(args) + + val file = fopen(fileName, "r") + if (file == null) { + perror("cannot open input file $fileName") + return + } + + val keyValue = mutableMapOf() + + try { + memScoped { + val bufferLength = 64 * 1024 + val buffer = allocArray(bufferLength) + + for (i in 1..count) { + val nextLine = fgets(buffer, bufferLength, file)?.toKString() + if (nextLine == null || nextLine.isEmpty()) break + + val records = parseLine(nextLine, ',') + val key = records[column] + val current = keyValue[key] ?: 0 + keyValue[key] = current + 1 + } + } + } finally { + fclose(file) + } + + keyValue.forEach { + println("${it.key} -> ${it.value}") + } +} diff --git a/idea/testData/perfTest/native/HelloWorld/.gitignore b/idea/testData/perfTest/native/HelloWorld/.gitignore new file mode 100644 index 00000000000..2f00c62a3bc --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/.gitignore @@ -0,0 +1,4 @@ +build +.idea +.gradle +gradlew* diff --git a/idea/testData/perfTest/native/HelloWorld/build.gradle.kts b/idea/testData/perfTest/native/HelloWorld/build.gradle.kts new file mode 100644 index 00000000000..7ca0aee4853 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + kotlin("multiplatform") version "{{kotlin_plugin_version}}" +} + +repositories { + mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") +} + +kotlin { + ios() +} diff --git a/idea/testData/perfTest/native/HelloWorld/gradle.properties b/idea/testData/perfTest/native/HelloWorld/gradle.properties new file mode 100644 index 00000000000..e5dadd15633 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/gradle.properties @@ -0,0 +1,2 @@ +kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.native.enableDependencyPropagation={{disable_commonizer}} diff --git a/idea/testData/perfTest/native/HelloWorld/gradle/wrapper/gradle-wrapper.properties b/idea/testData/perfTest/native/HelloWorld/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..819137c561c --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/idea/testData/perfTest/native/HelloWorld/settings.gradle.kts b/idea/testData/perfTest/native/HelloWorld/settings.gradle.kts new file mode 100644 index 00000000000..392a06e2437 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/settings.gradle.kts @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") + } +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain.kt new file mode 100644 index 00000000000..012bdca2831 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain.kt @@ -0,0 +1,4 @@ + +fun main(args: Array) { + println("Hello World!") +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain2.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain2.kt new file mode 100644 index 00000000000..012bdca2831 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain2.kt @@ -0,0 +1,4 @@ + +fun main(args: Array) { + println("Hello World!") +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain3.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain3.kt new file mode 100644 index 00000000000..012bdca2831 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Main/kotlin/HelloMain3.kt @@ -0,0 +1,4 @@ + +fun main(args: Array) { + println("Hello World!") +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest.kt new file mode 100644 index 00000000000..b8f77b1bbb7 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest.kt @@ -0,0 +1,11 @@ +import kotlin.test.Test +import kotlin.test.assertTrue + +private const val GREETING = "Hello, Kotlin/Native!" + +class HelloTest { + @Test + fun testHello() { + assertTrue("Kotlin/Native" in GREETING) + } +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest2.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest2.kt new file mode 100644 index 00000000000..4050eb73389 --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest2.kt @@ -0,0 +1,11 @@ +import kotlin.test.Test +import kotlin.test.assertTrue + +private const val GREETING = "Hello, Kotlin/Native!" + +class HelloTest2 { + @Test + fun testHello() { + assertTrue("Kotlin/Native" in GREETING) + } +} diff --git a/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest3.kt b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest3.kt new file mode 100644 index 00000000000..1a6a74e5d6f --- /dev/null +++ b/idea/testData/perfTest/native/HelloWorld/src/iosX64Test/kotlin/HelloTest3.kt @@ -0,0 +1,11 @@ +import kotlin.test.Test +import kotlin.test.assertTrue + +private const val GREETING = "Hello, Kotlin/Native!" + +class HelloTest3 { + @Test + fun testHello() { + assertTrue("Kotlin/Native" in GREETING) + } +} diff --git a/idea/testData/perfTest/native/UIKitApp/.gitignore b/idea/testData/perfTest/native/UIKitApp/.gitignore new file mode 100644 index 00000000000..2f00c62a3bc --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/.gitignore @@ -0,0 +1,4 @@ +build +.idea +.gradle +gradlew* diff --git a/idea/testData/perfTest/native/UIKitApp/build.gradle.kts b/idea/testData/perfTest/native/UIKitApp/build.gradle.kts new file mode 100644 index 00000000000..7ca0aee4853 --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + kotlin("multiplatform") version "{{kotlin_plugin_version}}" +} + +repositories { + mavenCentral() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") +} + +kotlin { + ios() +} diff --git a/idea/testData/perfTest/native/UIKitApp/gradle.properties b/idea/testData/perfTest/native/UIKitApp/gradle.properties new file mode 100644 index 00000000000..e5dadd15633 --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/gradle.properties @@ -0,0 +1,2 @@ +kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.native.enableDependencyPropagation={{disable_commonizer}} diff --git a/idea/testData/perfTest/native/UIKitApp/gradle/wrapper/gradle-wrapper.properties b/idea/testData/perfTest/native/UIKitApp/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000000..819137c561c --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-{{gradle_version}}-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/idea/testData/perfTest/native/UIKitApp/settings.gradle.kts b/idea/testData/perfTest/native/UIKitApp/settings.gradle.kts new file mode 100644 index 00000000000..392a06e2437 --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/settings.gradle.kts @@ -0,0 +1,7 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven("https://dl.bintray.com/kotlin/kotlin-dev") + maven("https://dl.bintray.com/kotlin/kotlin-eap") + } +} diff --git a/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp.kt b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp.kt new file mode 100644 index 00000000000..d2a5270261c --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2019 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. + */ + +import kotlinx.cinterop.ExportObjCClass +import kotlinx.cinterop.ObjCAction +import kotlinx.cinterop.ObjCOutlet +import kotlinx.cinterop.autoreleasepool +import kotlinx.cinterop.cstr +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toCValues +import kotlinx.cinterop.useContents +import platform.CoreGraphics.CGPointMake +import platform.CoreGraphics.CGRectMake +import platform.Foundation.NSCoder +import platform.Foundation.NSSelectorFromString +import platform.Foundation.NSStringFromClass +import platform.UIKit.NSTextAlignmentCenter +import platform.UIKit.UIApplication +import platform.UIKit.UIApplicationDelegateProtocol +import platform.UIKit.UIApplicationDelegateProtocolMeta +import platform.UIKit.UIApplicationMain +import platform.UIKit.UIButton +import platform.UIKit.UIColor +import platform.UIKit.UIControlEventTouchUpInside +import platform.UIKit.UIControlStateNormal +import platform.UIKit.UIFont +import platform.UIKit.UILabel +import platform.UIKit.UIResponder +import platform.UIKit.UIResponderMeta +import platform.UIKit.UIScreen +import platform.UIKit.UIView +import platform.UIKit.UIViewController +import platform.UIKit.UIWindow +import platform.UIKit.addSubview +import platform.UIKit.backgroundColor +import platform.UIKit.font +import platform.UIKit.heightAnchor +import platform.UIKit.leadingAnchor +import platform.UIKit.setFrame +import platform.UIKit.topAnchor +import platform.UIKit.translatesAutoresizingMaskIntoConstraints +import platform.UIKit.widthAnchor + +fun main(args: Array) { + memScoped { + val argc = args.size + 1 + val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues() + + autoreleasepool { + UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate)) + } + } +} + +private class AppDelegate : UIResponder, UIApplicationDelegateProtocol { + companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {} + + @OverrideInit + constructor() : super() + + private var _window: UIWindow? = null + override fun window() = _window + override fun setWindow(window: UIWindow?) { + _window = window + } + + override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { + window = UIWindow(frame = UIScreen.mainScreen.bounds) + window!!.rootViewController = ViewController() + window!!.makeKeyAndVisible() + return true + } +} + +@ExportObjCClass +private class ViewController : UIViewController { + + @OverrideInit + constructor() : super(nibName = null, bundle = null) + + @OverrideInit + constructor(coder: NSCoder) : super(coder) + + @ObjCOutlet + lateinit var label: UILabel + + @ObjCOutlet + lateinit var button: UIButton + + var pressed = 0 + + @ObjCAction + fun buttonPressed() { + label.text = "Hello #${pressed++} from Konan!" + println("Button pressed") + } + + override fun viewDidLoad() { + super.viewDidLoad() + + val (width, height) = UIScreen.mainScreen.bounds.useContents { + this.size.width to this.size.height + } + + val header = UIView().apply { + backgroundColor = UIColor.lightGrayColor + view.addSubview(this) + translatesAutoresizingMaskIntoConstraints = false + leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true + topAnchor.constraintEqualToAnchor(view.topAnchor).active = true + widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true + heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true + } + + label = UILabel().apply { + setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = 40.0 ) + textAlignment = NSTextAlignmentCenter + text = "Press OK" + header.addSubview(this) + } + + button = UIButton().apply { + setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = height / 2) + backgroundColor = UIColor.blueColor + setTitle("OK", forState = UIControlStateNormal) + font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!! + layer.borderWidth = 1.0 + layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor + layer.masksToBounds = true + addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"), + forControlEvents = UIControlEventTouchUpInside) + header.addSubview(this) + } + + } +} diff --git a/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp2.kt b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp2.kt new file mode 100644 index 00000000000..d2a5270261c --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp2.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2019 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. + */ + +import kotlinx.cinterop.ExportObjCClass +import kotlinx.cinterop.ObjCAction +import kotlinx.cinterop.ObjCOutlet +import kotlinx.cinterop.autoreleasepool +import kotlinx.cinterop.cstr +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toCValues +import kotlinx.cinterop.useContents +import platform.CoreGraphics.CGPointMake +import platform.CoreGraphics.CGRectMake +import platform.Foundation.NSCoder +import platform.Foundation.NSSelectorFromString +import platform.Foundation.NSStringFromClass +import platform.UIKit.NSTextAlignmentCenter +import platform.UIKit.UIApplication +import platform.UIKit.UIApplicationDelegateProtocol +import platform.UIKit.UIApplicationDelegateProtocolMeta +import platform.UIKit.UIApplicationMain +import platform.UIKit.UIButton +import platform.UIKit.UIColor +import platform.UIKit.UIControlEventTouchUpInside +import platform.UIKit.UIControlStateNormal +import platform.UIKit.UIFont +import platform.UIKit.UILabel +import platform.UIKit.UIResponder +import platform.UIKit.UIResponderMeta +import platform.UIKit.UIScreen +import platform.UIKit.UIView +import platform.UIKit.UIViewController +import platform.UIKit.UIWindow +import platform.UIKit.addSubview +import platform.UIKit.backgroundColor +import platform.UIKit.font +import platform.UIKit.heightAnchor +import platform.UIKit.leadingAnchor +import platform.UIKit.setFrame +import platform.UIKit.topAnchor +import platform.UIKit.translatesAutoresizingMaskIntoConstraints +import platform.UIKit.widthAnchor + +fun main(args: Array) { + memScoped { + val argc = args.size + 1 + val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues() + + autoreleasepool { + UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate)) + } + } +} + +private class AppDelegate : UIResponder, UIApplicationDelegateProtocol { + companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {} + + @OverrideInit + constructor() : super() + + private var _window: UIWindow? = null + override fun window() = _window + override fun setWindow(window: UIWindow?) { + _window = window + } + + override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { + window = UIWindow(frame = UIScreen.mainScreen.bounds) + window!!.rootViewController = ViewController() + window!!.makeKeyAndVisible() + return true + } +} + +@ExportObjCClass +private class ViewController : UIViewController { + + @OverrideInit + constructor() : super(nibName = null, bundle = null) + + @OverrideInit + constructor(coder: NSCoder) : super(coder) + + @ObjCOutlet + lateinit var label: UILabel + + @ObjCOutlet + lateinit var button: UIButton + + var pressed = 0 + + @ObjCAction + fun buttonPressed() { + label.text = "Hello #${pressed++} from Konan!" + println("Button pressed") + } + + override fun viewDidLoad() { + super.viewDidLoad() + + val (width, height) = UIScreen.mainScreen.bounds.useContents { + this.size.width to this.size.height + } + + val header = UIView().apply { + backgroundColor = UIColor.lightGrayColor + view.addSubview(this) + translatesAutoresizingMaskIntoConstraints = false + leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true + topAnchor.constraintEqualToAnchor(view.topAnchor).active = true + widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true + heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true + } + + label = UILabel().apply { + setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = 40.0 ) + textAlignment = NSTextAlignmentCenter + text = "Press OK" + header.addSubview(this) + } + + button = UIButton().apply { + setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = height / 2) + backgroundColor = UIColor.blueColor + setTitle("OK", forState = UIControlStateNormal) + font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!! + layer.borderWidth = 1.0 + layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor + layer.masksToBounds = true + addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"), + forControlEvents = UIControlEventTouchUpInside) + header.addSubview(this) + } + + } +} diff --git a/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp3.kt b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp3.kt new file mode 100644 index 00000000000..d2a5270261c --- /dev/null +++ b/idea/testData/perfTest/native/UIKitApp/src/iosX64Main/kotlin/UIKitApp3.kt @@ -0,0 +1,140 @@ +/* + * Copyright 2010-2019 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. + */ + +import kotlinx.cinterop.ExportObjCClass +import kotlinx.cinterop.ObjCAction +import kotlinx.cinterop.ObjCOutlet +import kotlinx.cinterop.autoreleasepool +import kotlinx.cinterop.cstr +import kotlinx.cinterop.memScoped +import kotlinx.cinterop.toCValues +import kotlinx.cinterop.useContents +import platform.CoreGraphics.CGPointMake +import platform.CoreGraphics.CGRectMake +import platform.Foundation.NSCoder +import platform.Foundation.NSSelectorFromString +import platform.Foundation.NSStringFromClass +import platform.UIKit.NSTextAlignmentCenter +import platform.UIKit.UIApplication +import platform.UIKit.UIApplicationDelegateProtocol +import platform.UIKit.UIApplicationDelegateProtocolMeta +import platform.UIKit.UIApplicationMain +import platform.UIKit.UIButton +import platform.UIKit.UIColor +import platform.UIKit.UIControlEventTouchUpInside +import platform.UIKit.UIControlStateNormal +import platform.UIKit.UIFont +import platform.UIKit.UILabel +import platform.UIKit.UIResponder +import platform.UIKit.UIResponderMeta +import platform.UIKit.UIScreen +import platform.UIKit.UIView +import platform.UIKit.UIViewController +import platform.UIKit.UIWindow +import platform.UIKit.addSubview +import platform.UIKit.backgroundColor +import platform.UIKit.font +import platform.UIKit.heightAnchor +import platform.UIKit.leadingAnchor +import platform.UIKit.setFrame +import platform.UIKit.topAnchor +import platform.UIKit.translatesAutoresizingMaskIntoConstraints +import platform.UIKit.widthAnchor + +fun main(args: Array) { + memScoped { + val argc = args.size + 1 + val argv = (arrayOf("konan") + args).map { it.cstr.ptr }.toCValues() + + autoreleasepool { + UIApplicationMain(argc, argv, null, NSStringFromClass(AppDelegate)) + } + } +} + +private class AppDelegate : UIResponder, UIApplicationDelegateProtocol { + companion object : UIResponderMeta(), UIApplicationDelegateProtocolMeta {} + + @OverrideInit + constructor() : super() + + private var _window: UIWindow? = null + override fun window() = _window + override fun setWindow(window: UIWindow?) { + _window = window + } + + override fun application(application: UIApplication, didFinishLaunchingWithOptions: Map?): Boolean { + window = UIWindow(frame = UIScreen.mainScreen.bounds) + window!!.rootViewController = ViewController() + window!!.makeKeyAndVisible() + return true + } +} + +@ExportObjCClass +private class ViewController : UIViewController { + + @OverrideInit + constructor() : super(nibName = null, bundle = null) + + @OverrideInit + constructor(coder: NSCoder) : super(coder) + + @ObjCOutlet + lateinit var label: UILabel + + @ObjCOutlet + lateinit var button: UIButton + + var pressed = 0 + + @ObjCAction + fun buttonPressed() { + label.text = "Hello #${pressed++} from Konan!" + println("Button pressed") + } + + override fun viewDidLoad() { + super.viewDidLoad() + + val (width, height) = UIScreen.mainScreen.bounds.useContents { + this.size.width to this.size.height + } + + val header = UIView().apply { + backgroundColor = UIColor.lightGrayColor + view.addSubview(this) + translatesAutoresizingMaskIntoConstraints = false + leadingAnchor.constraintEqualToAnchor(view.leadingAnchor).active = true + topAnchor.constraintEqualToAnchor(view.topAnchor).active = true + widthAnchor.constraintEqualToAnchor(view.widthAnchor).active = true + heightAnchor.constraintEqualToAnchor(view.heightAnchor).active = true + } + + label = UILabel().apply { + setFrame(CGRectMake(x = 10.0, y = 10.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = 40.0 ) + textAlignment = NSTextAlignmentCenter + text = "Press OK" + header.addSubview(this) + } + + button = UIButton().apply { + setFrame(CGRectMake(x = 10.0, y = height - 100.0, width = width - 100.0, height = 40.0)) + center = CGPointMake(x = width / 2, y = height / 2) + backgroundColor = UIColor.blueColor + setTitle("OK", forState = UIControlStateNormal) + font = UIFont.fontWithName(fontName = font.fontName, size = 28.0)!! + layer.borderWidth = 1.0 + layer.borderColor = UIColor.colorWithRed(0x47 / 255.0, 0x43 / 255.0, 0x70 / 255.0, 1.0).CGColor + layer.masksToBounds = true + addTarget(target = this@ViewController, action = NSSelectorFromString("buttonPressed"), + forControlEvents = UIControlEventTouchUpInside) + header.addSubview(this) + } + + } +}