cds+ij - cleanup automatic AppCDS enable, cleanup code, prepare for perfTests

GitOrigin-RevId: 6e08233fb3aec173af1d3b1ec1d5d423593316d0
This commit is contained in:
Eugene Petrenko
2019-10-13 07:39:55 +00:00
committed by intellij-monorepo-bot
parent 3ecb2cc895
commit 3564675e9c
5 changed files with 70 additions and 33 deletions
@@ -104,6 +104,7 @@ public class VMOptions {
writeGeneralOptions(
Function.<String>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?"), ""))
);
}
@@ -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()
}
})
@@ -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<Any?> =
try {
if (enableCDS) {
val paths = installCDS(null)
if (paths == null) rejectedPromise("Failed to install AppCDS, see log for errors")
else resolvedPromise<Any?>("ok")
}
else {
removeCDS()
resolvedPromise("ok")
}
}
catch (t: Throwable) {
rejectedPromise(t)
}
private operator fun File.div(s: String) = File(this, s)
}
@@ -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(
@@ -823,5 +823,6 @@
<virtualFileManagerListener implementation="com.intellij.configurationStore.StoreReloadManagerImpl$MyVirtualFileManagerListener"/>
<postStartupActivity implementation="com.intellij.ide.cds.CDSStartupActivity" order="last"/>
<registryKey key="appcds.enabled" defaultValue="false" restartRequired="true" description="Whether IDE should use AppCDS (JRP 310) for faster startup"/>
</extensions>
</idea-plugin>