From 3564675e9cb403fcd1e699eb9de3859ccf42b36c Mon Sep 17 00:00:00 2001 From: Eugene Petrenko Date: Tue, 8 Oct 2019 17:12:17 +0200 Subject: [PATCH] cds+ij - cleanup automatic AppCDS enable, cleanup code, prepare for perfTests GitOrigin-RevId: 6e08233fb3aec173af1d3b1ec1d5d423593316d0 --- .../com/intellij/diagnostic/VMOptions.java | 1 + .../src/com/intellij/ide/cds/CDSActions.kt | 6 +- .../src/com/intellij/ide/cds/CDSManager.kt | 85 ++++++++++++------- .../intellij/ide/cds/CDSStartupActivity.kt | 10 ++- .../src/META-INF/PlatformExtensions.xml | 1 + 5 files changed, 70 insertions(+), 33 deletions(-) diff --git a/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java b/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java index 1d447b61ae83..5f43fe2c1bcf 100644 --- a/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java +++ b/platform/platform-impl/src/com/intellij/diagnostic/VMOptions.java @@ -104,6 +104,7 @@ public class VMOptions { writeGeneralOptions( Function.identity() .andThen(replaceOrAddOption(Pattern.compile("-Xshare:.*\\r?\\n?"), "")) + // we cannot remove "-XX:+UnlockDiagnosticVMOptions", we do not know the reason it was included .andThen(replaceOrAddOption(Pattern.compile("-XX:SharedArchiveFile=.*\\r?\\n?"), "")) ); } diff --git a/platform/platform-impl/src/com/intellij/ide/cds/CDSActions.kt b/platform/platform-impl/src/com/intellij/ide/cds/CDSActions.kt index fa748abfbac6..0de3557424e4 100644 --- a/platform/platform-impl/src/com/intellij/ide/cds/CDSActions.kt +++ b/platform/platform-impl/src/com/intellij/ide/cds/CDSActions.kt @@ -21,11 +21,12 @@ class CDSEnableAction : AnAction("Enable Class Data Sharing") { AppExecutorUtil.getAppExecutorService().execute { ProgressManager.getInstance().run(object : Task.Backgroundable( null, - "Configuring Class Data Sharing", + "Enable Class Data Sharing (AppCDS)", true, PerformInBackgroundOption.ALWAYS_BACKGROUND ) { override fun run(indicator: ProgressIndicator) { + indicator.isIndeterminate = true CDSManager.installCDS(indicator) } }) @@ -42,11 +43,12 @@ class CDSDisableAction : AnAction("Disable Class Data Sharing") { AppExecutorUtil.getAppExecutorService().execute { ProgressManager.getInstance().run(object : Task.Backgroundable( null, - "Uninstalling Class Data Sharing", + "Disable Class Data Sharing (AppCDS)", true, PerformInBackgroundOption.ALWAYS_BACKGROUND ) { override fun run(indicator: ProgressIndicator) { + indicator.isIndeterminate = true CDSManager.removeCDS() } }) diff --git a/platform/platform-impl/src/com/intellij/ide/cds/CDSManager.kt b/platform/platform-impl/src/com/intellij/ide/cds/CDSManager.kt index 6fcddefffb86..fb280fa25bf1 100644 --- a/platform/platform-impl/src/com/intellij/ide/cds/CDSManager.kt +++ b/platform/platform-impl/src/com/intellij/ide/cds/CDSManager.kt @@ -1,21 +1,21 @@ // Copyright 2000-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 file. package com.intellij.ide.cds -import com.google.common.hash.Hashing import com.intellij.diagnostic.VMOptions import com.intellij.execution.process.OSProcessUtil -import com.intellij.ide.plugins.PluginManager -import com.intellij.openapi.application.ApplicationInfo import com.intellij.openapi.application.PathManager import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.progress.ProgressIndicator +import com.intellij.openapi.ui.playback.PlaybackContext import com.intellij.openapi.util.SystemInfo import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.text.StringUtil import com.sun.tools.attach.VirtualMachine +import org.jetbrains.concurrency.Promise +import org.jetbrains.concurrency.rejectedPromise +import org.jetbrains.concurrency.resolvedPromise import java.io.File import java.lang.management.ManagementFactory -import java.nio.file.Files import java.util.concurrent.TimeUnit import kotlin.system.measureTimeMillis @@ -41,6 +41,11 @@ object CDSManager { return true } + val isRunningWithCDS: Boolean + get() { + return isValidEnv && currentCDSArchive != null + } + val canBuildOrUpdateCDS: Boolean get() { if (!isValidEnv) return false @@ -49,20 +54,6 @@ object CDSManager { return !paths.isSame(currentCDSArchive) } - private val agentPath: File - get() { - val libPath = File(PathManager.getLibPath()) / "cds" / "classesLogAgent.jar" - if (libPath.isFile) return libPath - - LOG.warn("Failed to find bundled CDS classes agent in $libPath") - - //consider local debug IDE case - val probe = File(PathManager.getHomePath()) / "out" / "classes" / "artifacts" / "classesLogAgent_jar" / "classesLogAgent.jar" - if (probe.isFile) return probe - - error("Failed to resolve path to the CDS agent") - } - private val currentCDSArchive: File? get() { val arguments = ManagementFactory.getRuntimeMXBean().inputArguments @@ -91,20 +82,33 @@ object CDSManager { } } - fun installCDS(indicator: ProgressIndicator) { + fun installCDS(indicator: ProgressIndicator?): CDSPaths? { val paths = CDSPaths.current() if (paths.isSame(currentCDSArchive)) { LOG.info("CDS archive is already generated. Nothing to do") - return + return null } LOG.info("Starting generation of CDS archive to the ${paths.classesArchiveFile} and ${paths.classesArchiveFile} files") - indicator.text2 = "Collecting classes list..." - indicator.checkCanceled() + indicator?.text2 = "Collecting classes list..." + indicator?.checkCanceled() val durationList = measureTimeMillis { try { + val agentPath = run { + val libPath = File(PathManager.getLibPath()) / "cds" / "classesLogAgent.jar" + if (libPath.isFile) return@run libPath + + LOG.warn("Failed to find bundled CDS classes agent in $libPath") + + //consider local debug IDE case + val probe = File(PathManager.getHomePath()) / "out" / "classes" / "artifacts" / "classesLogAgent_jar" / "classesLogAgent.jar" + if (probe.isFile) return@run probe + + error("Failed to resolve path to the CDS agent") + } + val vm = VirtualMachine.attach(OSProcessUtil.getApplicationPid()) try { vm.loadAgent(agentPath.path, "${paths.classesListFile},${paths.classesPathFile}") @@ -115,14 +119,14 @@ object CDSManager { } catch (t: Throwable) { LOG.warn("Failed to attach CDS Java Agent to the running IDE instance. ${t.message}", t) - return + return null } } LOG.info("CDS classes file is generated in ${StringUtil.formatDuration(durationList)}") - indicator.text2 = "Generating classes archive..." - indicator.checkCanceled() + indicator?.text2 = "Generating classes archive..." + indicator?.checkCanceled() val durationLink = measureTimeMillis { val ext = if (SystemInfo.isWindows) ".exe" else "" @@ -140,12 +144,12 @@ object CDSManager { val cwd = File(".").canonicalFile LOG.info("Running CDS generation process: $args in $cwd") - indicator.checkCanceled() + indicator?.checkCanceled() val process = ProcessBuilder().command(args).inheritIO().directory(cwd).start() if (!process.waitFor(10, TimeUnit.MINUTES)) { LOG.warn("Failed to generate CDS archive, the process took too long and will be killed") process.destroyForcibly() - return + return null } } @@ -154,12 +158,35 @@ object CDSManager { "in ${StringUtil.formatDuration(durationLink)}") VMOptions.writeEnableCDSArchiveOption(paths.classesArchiveFile.absolutePath) + + return paths } fun removeCDS() { LOG.warn("CDS archive is disabled") VMOptions.writeDisableCDSArchiveOption() } -} -private operator fun File.div(s: String) = File(this, s) + /** + * See com.intellij.openapi.ui.playback.commands.CallCommand + */ + @JvmStatic + @Suppress("unused") + fun toggleCDSForPerfTests(@Suppress("UNUSED_PARAMETER") context: PlaybackContext, enableCDS: Boolean): Promise = + try { + if (enableCDS) { + val paths = installCDS(null) + if (paths == null) rejectedPromise("Failed to install AppCDS, see log for errors") + else resolvedPromise("ok") + } + else { + removeCDS() + resolvedPromise("ok") + } + } + catch (t: Throwable) { + rejectedPromise(t) + } + + private operator fun File.div(s: String) = File(this, s) +} diff --git a/platform/platform-impl/src/com/intellij/ide/cds/CDSStartupActivity.kt b/platform/platform-impl/src/com/intellij/ide/cds/CDSStartupActivity.kt index 67ea0acd590b..be28873825c3 100644 --- a/platform/platform-impl/src/com/intellij/ide/cds/CDSStartupActivity.kt +++ b/platform/platform-impl/src/com/intellij/ide/cds/CDSStartupActivity.kt @@ -18,8 +18,14 @@ class CDSStartupActivity : StartupActivity { if (!isExecuted.compareAndSet(false, true)) return if (!CDSManager.canBuildOrUpdateCDS) return - val cdsKey = "intellij.cds.enabled" - val cdsEnabled = (System.getProperty(cdsKey, "true")?.toBoolean() == true || Registry.`is`(cdsKey, true)) + // 1. allow to toggle the feature via -DintelliJ.appCDS.enabled + // 2. if not set, use Registry to enable the feature + // 3. and finally, fallback to see if we already run with AppCDS + val cdsKey = "appcds.enabled" + val cdsEnabled = System.getProperty("intellij.$cdsKey")?.toBoolean() + ?: runCatching { + Registry.`is`(cdsKey) + }.getOrElse { CDSManager.isRunningWithCDS } AppExecutorUtil.getAppExecutorService().execute { ProgressManager.getInstance().run(object : Task.Backgroundable( diff --git a/platform/platform-resources/src/META-INF/PlatformExtensions.xml b/platform/platform-resources/src/META-INF/PlatformExtensions.xml index 368c4b4aa049..ba805a3d457a 100644 --- a/platform/platform-resources/src/META-INF/PlatformExtensions.xml +++ b/platform/platform-resources/src/META-INF/PlatformExtensions.xml @@ -823,5 +823,6 @@ +