use fork join pool for start-up activities

GitOrigin-RevId: e1c07b7221c79274953ee1be563688f546eadd7d
This commit is contained in:
Vladimir Krivosheev
2021-03-29 17:20:14 +02:00
committed by intellij-monorepo-bot
parent ec9a504893
commit cbd5f7be22
17 changed files with 176 additions and 217 deletions

View File

@@ -54,8 +54,4 @@ final class DescriptorLoadingContext implements AutoCloseable {
}
}
}
public @NotNull DescriptorLoadingContext copy(boolean isEssential) {
return new DescriptorLoadingContext(parentContext, isBundled, isEssential);
}
}

View File

@@ -275,6 +275,7 @@ public final class PluginDescriptorLoader {
private static @Nullable IdeaPluginDescriptorImpl loadDescriptorFromResource(@NotNull URL resource,
@NotNull String pathName,
@NotNull DescriptorLoadingContext loadingContext,
boolean isEssential,
@NotNull PathResolver pathResolver) {
try {
Path file;
@@ -302,7 +303,7 @@ public final class PluginDescriptorLoader {
}
}
catch (Throwable e) {
if (loadingContext.isEssential) {
if (isEssential) {
ExceptionUtilRt.rethrowUnchecked(e);
throw new RuntimeException(e);
}
@@ -391,38 +392,22 @@ public final class PluginDescriptorLoader {
Map<URL, String> urlsFromClassPath = new LinkedHashMap<>();
URL platformPluginURL = computePlatformPluginUrlAndCollectPluginUrls(classLoader, urlsFromClassPath);
ClassPathXmlPathResolver pathResolver = new ClassPathXmlPathResolver(classLoader);
try (DescriptorLoadingContext loadingContext = new DescriptorLoadingContext(context, /* isBundled = */ true, /* isEssential, doesn't matter = */ true)) {
loadDescriptorsFromClassPath(urlsFromClassPath, loadingContext, platformPluginURL, pathResolver);
}
loadDescriptorsFromClassPath(urlsFromClassPath, context, platformPluginURL, pathResolver);
ForkJoinPool.commonPool().invoke(new LoadDescriptorsFromDirAction(customPluginDir, context, false));
if (bundledPluginDir != null) {
ForkJoinPool.commonPool().invoke(new LoadDescriptorsFromDirAction(bundledPluginDir, context, true));
}
}
static void loadDescriptorsFromClassPath(@NotNull Map<URL, String> urls,
@NotNull DescriptorLoadingContext context,
@NotNull DescriptorListLoadingContext context,
@Nullable URL platformPluginURL,
@NotNull PathResolver pathResolver) {
if (urls.isEmpty()) {
return;
}
if (urls.size() == 1) {
Map.Entry<URL, String> entry = urls.entrySet().iterator().next();
IdeaPluginDescriptorImpl descriptor =
loadDescriptorFromResource(entry.getKey(), entry.getValue(), context.copy(entry.getKey().equals(platformPluginURL)), pathResolver);
if (descriptor != null) {
if (!PluginManagerCore.usePluginClassLoader) {
descriptor.setUseCoreClassLoader();
}
context.parentContext.result.add(descriptor, /* overrideUseIfCompatible = */ false);
}
return;
}
ForkJoinPool.commonPool().invoke(new RecursiveAction() {
@Override
protected void compute() {
@@ -432,12 +417,13 @@ public final class PluginDescriptorLoader {
@Override
protected IdeaPluginDescriptorImpl compute() {
URL url = entry.getKey();
return loadDescriptorFromResource(url, entry.getValue(), context.copy(url.equals(platformPluginURL)), pathResolver);
boolean isEssential = url.equals(platformPluginURL);
return loadDescriptorFromResource(url, entry.getValue(), new DescriptorLoadingContext(context, true, isEssential), isEssential, pathResolver);
}
});
}
PluginLoadingResult result = context.parentContext.result;
PluginLoadingResult result = context.result;
ForkJoinTask.invokeAll(tasks);
for (RecursiveTask<IdeaPluginDescriptorImpl> task : tasks) {
IdeaPluginDescriptorImpl descriptor = task.getRawResult();

View File

@@ -29,7 +29,6 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.PlatformUtils;
import com.intellij.util.ReflectionUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.execution.ParametersListUtil;
import com.intellij.util.graph.DFSTBuilder;
@@ -48,6 +47,7 @@ import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -784,9 +784,7 @@ public final class PluginManagerCore {
PluginDescriptorLoader.collectPluginFilesInClassPath(loader, urlsFromClassPath);
BuildNumber buildNumber = BuildNumber.fromString("2042.42");
DescriptorListLoadingContext context = new DescriptorListLoadingContext(0, Collections.emptySet(), new PluginLoadingResult(Collections.emptyMap(), () -> buildNumber, false));
try (DescriptorLoadingContext loadingContext = new DescriptorLoadingContext(context, true, true)) {
PluginDescriptorLoader.loadDescriptorsFromClassPath(urlsFromClassPath, loadingContext, null, new ClassPathXmlPathResolver(loader));
}
PluginDescriptorLoader.loadDescriptorsFromClassPath(urlsFromClassPath, context, null, new ClassPathXmlPathResolver(loader));
context.result.finishLoading();
return context.result.getEnabledPlugins();
@@ -807,7 +805,7 @@ public final class PluginManagerCore {
DescriptorListLoadingContext context = PluginDescriptorLoader.loadDescriptors();
activity.end();
return context;
}, AppExecutorUtil.getAppExecutorService());
}, ForkJoinPool.commonPool());
descriptorListFuture = future;
return future;
}
@@ -817,6 +815,7 @@ public final class PluginManagerCore {
*/
@ApiStatus.Internal
public static @NotNull List<IdeaPluginDescriptorImpl> getEnabledPluginRawList() {
//noinspection resource
return getOrScheduleLoading().join().result.getEnabledPlugins();
}

View File

@@ -1,10 +1,12 @@
// Copyright 2000-2020 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.
// Copyright 2000-2021 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.diagnostic.startUpPerformanceReporter
import com.intellij.diagnostic.ActivityImpl
import com.intellij.diagnostic.ThreadNameManager
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap
private const val pooledPrefix = "ApplicationImpl pooled thread "
internal class IdeThreadNameManager : ThreadNameManager {
// ConcurrencyUtil.runUnderThreadName is used in our code (to make thread dumps more clear) and changes thread name,
// so, use first thread name that associated with thread and not subsequent one
@@ -16,10 +18,8 @@ internal class IdeThreadNameManager : ThreadNameManager {
return result
}
val pooledPrefix = "ApplicationImpl pooled thread "
var name = event.threadName
if (name.endsWith("]") && name.contains(pooledPrefix)) {
if (name.endsWith(']') && name.contains(pooledPrefix)) {
val lastOpen = name.lastIndexOf('[')
if (lastOpen > 0) {
name = name.substring(lastOpen + 1, name.length - 1)
@@ -27,6 +27,7 @@ internal class IdeThreadNameManager : ThreadNameManager {
}
result = when {
name.startsWith("JobScheduler FJ pool ") -> name.replace("JobScheduler FJ pool ", "fj ")
name.startsWith("AWT-EventQueue-") -> "edt"
name.startsWith("Idea Main Thread") -> "idea main"
name.startsWith(pooledPrefix) -> name.replace(pooledPrefix, "pooled ")

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 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.
// Copyright 2000-2021 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.ui;
import com.intellij.diagnostic.StartUpMeasurer;
@@ -19,12 +19,12 @@ import com.intellij.openapi.project.Project;
import com.intellij.openapi.startup.StartupActivity;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.codeStyle.WordPrefixMatcher;
import com.intellij.util.concurrency.NonUrgentExecutor;
import com.intellij.util.text.Matcher;
import org.jetbrains.annotations.*;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.ForkJoinPool;
import java.util.function.Consumer;
public abstract class OptionsTopHitProvider implements OptionsSearchTopHitProvider, SearchTopHitProvider {
@@ -163,7 +163,7 @@ public abstract class OptionsTopHitProvider implements OptionsSearchTopHitProvid
static final class Activity extends PreloadingActivity implements StartupActivity.DumbAware {
Activity() {
if (ApplicationManager.getApplication().isUnitTestMode() ||
if (ApplicationManager.getApplication().isUnitTestMode() ||
ApplicationManager.getApplication().isHeadlessEnvironment()) {
throw ExtensionNotApplicableException.INSTANCE;
}
@@ -171,13 +171,14 @@ public abstract class OptionsTopHitProvider implements OptionsSearchTopHitProvid
@Override
public void preload(@NotNull ProgressIndicator indicator) {
cacheAll(indicator, null); // for application
// for application
cacheAll(indicator, null);
}
@Override
public void runActivity(@NotNull Project project) {
// for given project
NonUrgentExecutor.getInstance().execute(() -> {
ForkJoinPool.commonPool().execute(() -> {
if (project.isDisposed()) {
return;
}

View File

@@ -12,7 +12,6 @@ import com.intellij.openapi.application.ex.ApplicationEx
import com.intellij.openapi.application.impl.ApplicationImpl
import com.intellij.openapi.components.stateStore
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.diagnostic.runAndLogException
import com.intellij.openapi.extensions.ExtensionNotApplicableException
import com.intellij.openapi.extensions.impl.ExtensionsAreaImpl
import com.intellij.openapi.progress.EmptyProgressIndicator
@@ -30,9 +29,7 @@ import com.intellij.ui.AppIcon
import com.intellij.ui.mac.MacOSApplicationProvider
import com.intellij.ui.mac.foundation.Foundation
import com.intellij.ui.mac.touchbar.TouchBarsManager
import com.intellij.util.concurrency.AppExecutorUtil
import com.intellij.util.concurrency.NonUrgentExecutor
import com.intellij.util.io.write
import com.intellij.util.io.createDirectories
import com.intellij.util.lang.ZipFilePool
import com.intellij.util.ui.AsyncProcessIcon
import net.miginfocom.layout.PlatformDefaults
@@ -42,10 +39,9 @@ import java.awt.Font
import java.awt.GraphicsEnvironment
import java.awt.dnd.DragSource
import java.io.IOException
import java.nio.file.Paths
import java.util.concurrent.CompletableFuture
import java.util.concurrent.CompletionStage
import java.util.concurrent.Executor
import java.nio.file.Files
import java.nio.file.Path
import java.util.concurrent.*
import java.util.function.BiFunction
import java.util.function.Function
import kotlin.system.exitProcess
@@ -132,18 +128,18 @@ private fun startApp(app: ApplicationImpl,
}
val nonEdtExecutor = Executor {
when {
app.isDispatchThread -> AppExecutorUtil.getAppExecutorService().execute(it)
else -> it.run()
if (app.isDispatchThread) {
ForkJoinPool.commonPool().execute(it)
}
else {
it.run()
}
}
val boundedExecutor = createExecutorToPreloadServices()
// preload services only after icon activation
val preloadSyncServiceFuture = registerRegistryAndInitStoreFuture
.thenComposeAsync<Void?>(Function {
preloadServices(it, app, activityPrefix = "", executor = boundedExecutor)
preloadServices(it, app, activityPrefix = "")
}, nonEdtExecutor)
if (!headless) {
@@ -166,18 +162,19 @@ private fun startApp(app: ApplicationImpl,
}
TouchBarsManager.initialize()
}
}, NonUrgentExecutor.getInstance())
}, ForkJoinPool.commonPool())
}
WeakFocusStackManager.getInstance()
NonUrgentExecutor.getInstance().execute {
ForkJoinPool.commonPool().execute {
runActivity("migLayout") {
PlatformDefaults.setLogicalPixelBase(PlatformDefaults.BASE_FONT_SIZE) // IDEA-170295
// IDEA-170295
PlatformDefaults.setLogicalPixelBase(PlatformDefaults.BASE_FONT_SIZE)
}
}
NonUrgentExecutor.getInstance().execute {
ForkJoinPool.commonPool().execute {
runActivity("icons preloading") {
AsyncProcessIcon("")
AnimatedIcon.Blinking(AllIcons.Ide.FatalError)
@@ -209,13 +206,13 @@ private fun startApp(app: ApplicationImpl,
CompletableFuture.allOf(loadComponentInEdtFuture, preloadSyncServiceFuture)
}
.thenComposeAsync<Void?>(Function {
.thenRunAsync({
val activity = initAppActivity.startChild("app initialized callback")
val future = callAppInitialized(app, boundedExecutor)
val tasks = callAppInitialized(app)
// should be after scheduling all app initialized listeners (because this activity is not important)
if (!Main.isLightEdit()) {
NonUrgentExecutor.getInstance().execute {
ForkJoinPool.commonPool().execute {
// execute in parallel to component loading - this functionality should be used only by plugin functionality that is used after start-up
runActivity("system properties setting") {
SystemPropertyBean.initSystemProperties()
@@ -223,17 +220,16 @@ private fun startApp(app: ApplicationImpl,
}
}
future.thenRun {
activity.end()
if (!headless) {
addActivateAndWindowsCliListeners()
}
ForkJoinTask.invokeAll(tasks)
initAppActivity.end()
activity.end()
if (!headless) {
addActivateAndWindowsCliListeners()
}
},
// if `loadComponentInEdtFuture` is completed after `preloadSyncServiceFuture`, then this task will be executed in EDT, so force execution out of EDT
nonEdtExecutor)
initAppActivity.end()
}, nonEdtExecutor /* if `loadComponentInEdtFuture` is completed after `preloadSyncServiceFuture`,
then this task will be executed in EDT, so force execution out of EDT */)
.thenRun {
if (starter.requiredModality == ApplicationStarter.NOT_IN_EDT) {
starter.main(args)
@@ -255,35 +251,25 @@ private fun startApp(app: ApplicationImpl,
}
}
@ApiStatus.Internal
fun createExecutorToPreloadServices(): Executor {
return AppExecutorUtil.createBoundedApplicationPoolExecutor("Preload Services", Runtime.getRuntime().availableProcessors(), false)
}
@ApiStatus.Internal
@JvmOverloads
fun preloadServices(plugins: List<IdeaPluginDescriptorImpl>,
container: ComponentManagerImpl,
activityPrefix: String,
onlyIfAwait: Boolean = false,
executor: Executor = createExecutorToPreloadServices()): CompletableFuture<Void?> {
val syncActivity = StartUpMeasurer.startActivity("${activityPrefix}service sync preloading")
val asyncActivity = StartUpMeasurer.startActivity("${activityPrefix}service async preloading")
onlyIfAwait: Boolean = false): CompletableFuture<Void?> {
val result = container.preloadServices(plugins, activityPrefix, onlyIfAwait)
val result = container.preloadServices(plugins, executor, onlyIfAwait)
fun endActivityAndLogError(future: CompletableFuture<Void?>, activity: Activity): CompletableFuture<Void?> {
fun logError(future: CompletableFuture<Void?>): CompletableFuture<Void?> {
return future
.whenComplete { _, error ->
activity.end()
if (error != null && error !is ProcessCanceledException) {
StartupAbortedException.processException(error)
}
}
}
endActivityAndLogError(result.asyncPreloadedServices, asyncActivity)
return endActivityAndLogError(result.syncPreloadedServices, syncActivity)
logError(result.asyncPreloadedServices)
return logError(result.syncPreloadedServices)
}
@ApiStatus.Internal
@@ -294,7 +280,7 @@ fun registerRegistryAndInitStore(registerFuture: CompletableFuture<List<IdeaPlug
runActivity("add registry keys") {
RegistryKeyBean.addKeysFromPlugins()
}
}, AppExecutorUtil.getAppExecutorService())
}, ForkJoinPool.commonPool())
// initSystemProperties or RegistryKeyBean.addKeysFromPlugins maybe not yet performed, but it doesn't affect because not used
initConfigurationStore(app)
@@ -360,27 +346,26 @@ private fun handleExternalCommand(args: List<String>, currentDirectory: String?)
fun initApplication(rawArgs: List<String>, initUiTask: CompletionStage<*>) {
val initAppActivity = MainRunner.startupStart.endAndStart(Activities.INIT_APP)
val loadAndInitPluginFuture = CompletableFuture<List<IdeaPluginDescriptorImpl>>()
initUiTask
.thenRunAsync(Runnable {
val args = processProgramArguments(rawArgs)
EventQueue.invokeLater {
executeInitAppInEdt(args, initAppActivity, loadAndInitPluginFuture)
initUiTask.thenRunAsync(Runnable {
val args = processProgramArguments(rawArgs)
EventQueue.invokeLater {
executeInitAppInEdt(args, initAppActivity, loadAndInitPluginFuture)
}
if (!Main.isHeadless()) {
runActivity("system fonts loading") {
// editor and other UI components need the list of system fonts to implement font fallback
// this list is pre-loaded here, in parallel to other activities, to speed up project opening
// ideally, it shouldn't overlap with other font-related activities to avoid contention on JDK-internal font manager locks
loadSystemFonts()
}
if (!Main.isHeadless()) {
runActivity("system fonts loading") {
// editor and other UI components need the list of system fonts to implement font fallback
// this list is pre-loaded here, in parallel to other activities, to speed up project opening
// ideally, it shouldn't overlap with other font-related activities to avoid contention on JDK-internal font manager locks
loadSystemFonts()
}
// pre-load cursors used by drag-n-drop AWT subsystem
runActivity("DnD setup") {
DragSource.getDefaultDragSource()
}
// pre-load cursors used by drag-n-drop AWT subsystem
runActivity("DnD setup") {
DragSource.getDefaultDragSource()
}
}, AppExecutorUtil.getAppExecutorService()) // must not be executed neither in IDE main thread nor in EDT
}
}, ForkJoinPool.commonPool()) // must not be executed neither in IDE main thread nor in EDT
try {
val activity = initAppActivity.startChild("plugin descriptor init waiting")
@@ -464,38 +449,39 @@ private fun processProgramArguments(args: List<String>): List<String> {
return arguments
}
private fun createLocatorFile() {
runActivity("create locator file") {
val locatorFile = Paths.get(PathManager.getSystemPath(), ApplicationEx.LOCATOR_FILE_NAME)
try {
locatorFile.write(PathManager.getHomePath())
}
catch (e: IOException) {
LOG.warn("can't store a location in '$locatorFile'", e)
}
}
}
@ApiStatus.Internal
fun callAppInitialized(app: Application, executor: Executor): CompletableFuture<Void?> {
NonUrgentExecutor.getInstance().execute {
createLocatorFile()
}
val result = mutableListOf<CompletableFuture<Void>>()
fun callAppInitialized(app: Application): List<RecursiveAction> {
val extensionArea = app.extensionArea as ExtensionsAreaImpl
val extensionPoint = extensionArea.getExtensionPoint<ApplicationInitializedListener>("com.intellij.applicationInitializedListener")
val result = ArrayList<RecursiveAction>(extensionPoint.size())
extensionPoint.processImplementations(/* shouldBeSorted = */ false) { supplier, _ ->
CompletableFuture.runAsync(Runnable {
LOG.runAndLogException {
result.add(object : RecursiveAction() {
override fun compute() {
try {
supplier.get().componentsInitialized()
}
catch (ignore: ExtensionNotApplicableException) {
}
catch (e: Throwable) {
LOG.error(e)
}
}
}, executor)
})
}
extensionPoint.reset()
return CompletableFuture.allOf(*result.toTypedArray())
ForkJoinPool.commonPool().execute {
runActivity("create locator file") {
val locatorFile = Path.of(PathManager.getSystemPath(), ApplicationEx.LOCATOR_FILE_NAME)
try {
locatorFile.parent?.createDirectories()
Files.writeString(locatorFile, PathManager.getHomePath(), Charsets.UTF_8)
}
catch (e: IOException) {
LOG.warn("Can't store a location in '$locatorFile'", e)
}
}
}
return result
}

View File

@@ -13,7 +13,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.util.ExceptionUtilRt;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.ContainerUtil;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufOutputStream;
@@ -38,10 +37,7 @@ import java.nio.file.attribute.PosixFileAttributeView;
import java.nio.file.attribute.PosixFilePermission;
import java.util.List;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.regex.Pattern;
@@ -195,7 +191,7 @@ public final class SocketLock {
activity.end();
return server;
}, AppExecutorUtil.getAppExecutorService());
}, ForkJoinPool.commonPool());
log("exit: lock(): succeed");
return new AbstractMap.SimpleEntry<>(ActivationStatus.NO_INSTANCE, null);

View File

@@ -37,8 +37,6 @@ import com.intellij.ui.AppUIUtil;
import com.intellij.ui.IconManager;
import com.intellij.ui.scale.JBUIScale;
import com.intellij.util.EnvironmentUtil;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.concurrency.NonUrgentExecutor;
import com.intellij.util.lang.ZipFilePool;
import com.intellij.util.ui.EdtInvocationManager;
import com.intellij.util.ui.StartupUiUtil;
@@ -118,12 +116,12 @@ public final class StartupUtil {
return ourShellEnvLoaded;
}
private static @NotNull Future<@Nullable Object> loadEuaDocument(@NotNull ExecutorService executorService) {
private static @Nullable Future<@Nullable Object> loadEuaDocument() {
if (Main.isHeadless()) {
return CompletableFuture.completedFuture(null);
return null;
}
return executorService.submit(() -> {
return ForkJoinPool.commonPool().submit(() -> {
if (!ApplicationInfoImpl.getShadowInstance().isVendorJetBrains()) {
return null;
}
@@ -179,9 +177,8 @@ public final class StartupUtil {
IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool(Main.isHeadless(args));
activity = activity.endAndStart("main class loading scheduling");
ExecutorService executorService = AppExecutorUtil.getAppExecutorService();
Future<AppStarter> appStarterFuture = executorService.submit(() -> {
Future<AppStarter> appStarterFuture = ForkJoinPool.commonPool().submit(() -> {
Activity subActivity = StartUpMeasurer.startActivity("main class loading");
@SuppressWarnings("unchecked")
Class<AppStarter> aClass = (Class<AppStarter>)StartupUtil.class.getClassLoader().loadClass(mainClass);
@@ -194,11 +191,11 @@ public final class StartupUtil {
activity = activity.endAndStart("LaF init scheduling");
// EndUserAgreement.Document type is not specified to avoid class loading
Future<Object> euaDocument = loadEuaDocument(executorService);
Future<Object> euaDocument = loadEuaDocument();
if (Main.isHeadless()) {
enableHeadlessAwtGuard();
}
CompletableFuture<?> initUiTask = scheduleInitUi(args, executorService, euaDocument)
CompletableFuture<?> initUiTask = scheduleInitUi(args, euaDocument)
.exceptionally(e -> {
StartupAbortedException.processException(new StartupAbortedException("UI initialization failed", e));
return null;
@@ -237,7 +234,7 @@ public final class StartupUtil {
PluginManagerCore.scheduleDescriptorLoading();
}
NonUrgentExecutor.getInstance().execute(() -> {
ForkJoinPool.commonPool().execute(() -> {
setupSystemLibraries();
logEssentialInfoAboutIde(log, ApplicationInfoImpl.getShadowInstance());
loadSystemLibraries(log);
@@ -275,10 +272,10 @@ public final class StartupUtil {
@NotNull Logger log,
boolean configImportNeeded,
@NotNull Future<? extends AppStarter> appStarterFuture,
@NotNull Future<@Nullable Object> euaDocument) throws Exception {
@Nullable Future<@Nullable Object> euaDocument) throws Exception {
if (!Main.isHeadless()) {
Activity activity = StartUpMeasurer.startMainActivity("eua showing");
Object document = euaDocument.get();
Object document = euaDocument == null ? null : euaDocument.get();
boolean agreementDialogWasShown = document != null && showUserAgreementAndConsentsIfNeeded(log, initUiTask, (EndUserAgreement.Document)document);
if (configImportNeeded) {
@@ -341,12 +338,13 @@ public final class StartupUtil {
AWTAutoShutdown.getInstance().notifyThreadBusy(Thread.currentThread());
}
private static @NotNull CompletableFuture<?> scheduleInitUi(@NotNull String @NotNull [] args, @NotNull Executor executor, @NotNull Future<@Nullable Object> eulaDocument) {
private static @NotNull CompletableFuture<?> scheduleInitUi(@NotNull String @NotNull [] args,
@Nullable Future<@Nullable Object> eulaDocument) {
// mainly call sun.util.logging.PlatformLogger.getLogger - it takes enormous time (up to 500 ms)
// Before lockDirsAndConfigureLogger can be executed only tasks that do not require log,
// because we don't want to complicate logging. It is OK, because lockDirsAndConfigureLogger is not so heavy-weight as UI tasks.
CompletableFuture<Void> initUiFuture = new CompletableFuture<>();
executor.execute(() -> {
ForkJoinPool.commonPool().execute(() -> {
try {
checkHiDPISettings();
@@ -386,7 +384,7 @@ public final class StartupUtil {
Activity eulaActivity = prepareSplashActivity.startChild("splash eula isAccepted");
boolean isEulaAccepted;
try {
EndUserAgreement.Document document = (EndUserAgreement.Document)eulaDocument.get();
EndUserAgreement.Document document = eulaDocument == null ? null : (EndUserAgreement.Document)eulaDocument.get();
isEulaAccepted = document == null || document.isAccepted();
}
catch (InterruptedException | ExecutionException ignore) {
@@ -411,12 +409,12 @@ public final class StartupUtil {
if (!Main.isHeadless()) {
// do not wait, approach like AtomicNotNullLazyValue is used under the hood
initUiFuture.thenRunAsync(StartupUtil::updateFrameClassAndWindowIcon, executor);
initUiFuture.thenRunAsync(StartupUtil::updateFrameClassAndWindowIcon);
}
CompletableFuture<Void> instrumentationFuture = new CompletableFuture<>();
if (isUsingSeparateWriteThread()) {
executor.execute(() -> {
ForkJoinPool.commonPool().execute(() -> {
Activity activity = StartUpMeasurer.startActivity("Write Intent Lock UI class transformer loading");
try {
WriteIntentLockInstrumenter.instrument();

View File

@@ -1,7 +1,6 @@
// Copyright 2000-2020 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.
// Copyright 2000-2021 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.openapi.application;
import com.intellij.application.options.RegistryManager;
import com.intellij.diagnostic.Activity;
import com.intellij.diagnostic.ActivityCategory;
import com.intellij.diagnostic.StartUpMeasurer;
@@ -24,7 +23,6 @@ import org.jetbrains.annotations.Nullable;
import java.util.concurrent.ExecutorService;
final class Preloader implements ApplicationInitializedListener {
private static final ExtensionPointName<PreloadingActivity> EP_NAME = new ExtensionPointName<>("com.intellij.preloadingActivity");
private static final Logger LOG = Logger.getInstance(Preloader.class);
private static void checkHeavyProcessRunning() {
@@ -36,15 +34,16 @@ final class Preloader implements ApplicationInitializedListener {
@Override
public void componentsInitialized() {
Application app = ApplicationManager.getApplication();
if (app.isUnitTestMode() || app.isHeadlessEnvironment() || !RegistryManager.getInstance().is("enable.activity.preloading")) {
if (app.isUnitTestMode() || app.isHeadlessEnvironment() ||
!Boolean.parseBoolean(System.getProperty("enable.activity.preloading", "true"))) {
return;
}
EP_NAME.processWithPluginDescriptor(Preloader::preload);
new ExtensionPointName<PreloadingActivity>("com.intellij.preloadingActivity").processWithPluginDescriptor(Preloader::preload);
}
private static void preload(@NotNull PreloadingActivity activity, @Nullable PluginDescriptor descriptor) {
ExecutorService executor = AppExecutorUtil.createBoundedApplicationPoolExecutor("Preloader Pool", 1);
ExecutorService executor = AppExecutorUtil.createBoundedApplicationPoolExecutor("Preloader Pool", 1, false);
ProgressIndicator indicator = new ProgressIndicatorBase();
Disposer.register(ApplicationManager.getApplication(), indicator::cancel);

View File

@@ -11,7 +11,10 @@ import com.intellij.ide.*;
import com.intellij.ide.plugins.ContainerDescriptor;
import com.intellij.ide.plugins.IdeaPluginDescriptorImpl;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.idea.*;
import com.intellij.idea.ApplicationLoader;
import com.intellij.idea.Main;
import com.intellij.idea.MutedErrorLogger;
import com.intellij.idea.StartupUtil;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.*;
import com.intellij.openapi.application.ex.ApplicationEx;
@@ -41,7 +44,6 @@ import com.intellij.util.*;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.concurrency.AppScheduledExecutorService;
import com.intellij.util.containers.Stack;
import com.intellij.util.io.storage.HeavyProcessLatch;
import com.intellij.util.messages.Topic;
import com.intellij.util.ui.EDT;
import com.intellij.util.ui.EdtInvocationManager;
@@ -348,28 +350,21 @@ public class ApplicationImpl extends ComponentManagerImpl implements Application
List<IdeaPluginDescriptorImpl> plugins = PluginManagerCore.getLoadedPlugins(null);
registerComponents(plugins, null);
ApplicationLoader.initConfigurationStore(this);
Executor executor = ApplicationLoader.createExecutorToPreloadServices();
preloadServices(plugins, executor, false).getSyncPreloadedServices().join();
preloadServices(plugins, "", false).getSyncPreloadedServices().join();
loadComponents(null);
ApplicationLoader.callAppInitialized(this, executor).join();
ForkJoinTask.invokeAll(ApplicationLoader.callAppInitialized(this));
}
@ApiStatus.Internal
public final void loadComponents(@Nullable ProgressIndicator indicator) {
AccessToken token = HeavyProcessLatch.INSTANCE.processStarted("Loading application components"); // NON-NLS (not observable)
try {
if (indicator == null) {
// no splash, no need to to use progress manager
createComponents(null);
}
else {
ProgressManager.getInstance().runProcess(() -> createComponents(indicator), indicator);
}
StartUpMeasurer.setCurrentState(LoadingState.COMPONENTS_LOADED);
if (indicator == null) {
// no splash, no need to to use progress manager
createComponents(null);
}
finally {
token.finish();
else {
ProgressManager.getInstance().runProcess(() -> createComponents(indicator), indicator);
}
StartUpMeasurer.setCurrentState(LoadingState.COMPONENTS_LOADED);
}
@Override

View File

@@ -170,10 +170,14 @@ open class ProjectExImpl(filePath: Path, projectName: String?) : ProjectImpl(App
override fun init(preloadServices: Boolean, indicator: ProgressIndicator?) {
val app = ApplicationManager.getApplication()
// for light project preload only services that are essential (await means "project component loading activity is completed only when all such services are completed")
val servicePreloadingFuture = if (preloadServices) preloadServices(PluginManagerCore.getLoadedPlugins(null), container = this,
activityPrefix = "project ",
onlyIfAwait = isLight) else null
// for light project preload only services that are essential
// (await means "project component loading activity is completed only when all such services are completed")
val servicePreloadingFuture = if (preloadServices) {
preloadServices(PluginManagerCore.getLoadedPlugins(null), container = this, activityPrefix = "project ", onlyIfAwait = isLight)
}
else {
null
}
createComponents(indicator)
servicePreloadingFuture?.join()

View File

@@ -1,4 +1,4 @@
// 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.
// Copyright 2000-2021 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.openapi.util;
import com.intellij.openapi.extensions.ExtensionPointName;
@@ -13,7 +13,7 @@ import org.jetbrains.annotations.Nullable;
* @author gregsh
*/
public final class SystemPropertyBean implements PluginAware {
private static final ExtensionPointName<SystemPropertyBean> EP_NAME = ExtensionPointName.create("com.intellij.systemProperty");
private static final ExtensionPointName<SystemPropertyBean> EP_NAME = new ExtensionPointName<>("com.intellij.systemProperty");
private PluginDescriptor myPluginDescriptor;

View File

@@ -2,10 +2,7 @@
@file:Suppress("DeprecatedCallableAddReplaceWith")
package com.intellij.serviceContainer
import com.intellij.diagnostic.ActivityCategory
import com.intellij.diagnostic.LoadingState
import com.intellij.diagnostic.PluginException
import com.intellij.diagnostic.StartUpMeasurer
import com.intellij.diagnostic.*
import com.intellij.ide.plugins.*
import com.intellij.ide.plugins.cl.PluginAwareClassLoader
import com.intellij.idea.Main
@@ -44,10 +41,7 @@ import java.lang.reflect.Constructor
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Modifier
import java.util.*
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.ConcurrentMap
import java.util.concurrent.Executor
import java.util.concurrent.*
import java.util.concurrent.atomic.AtomicReference
internal val LOG = logger<ComponentManagerImpl>()
@@ -882,9 +876,11 @@ abstract class ComponentManagerImpl @JvmOverloads constructor(internal val paren
val syncPreloadedServices: CompletableFuture<Void?>)
@ApiStatus.Internal
fun preloadServices(plugins: List<IdeaPluginDescriptorImpl>, executor: Executor, onlyIfAwait: Boolean = false): ServicePreloadingResult {
val asyncPreloadedServices = mutableListOf<CompletableFuture<Void>>()
val syncPreloadedServices = mutableListOf<CompletableFuture<Void>>()
fun preloadServices(plugins: List<IdeaPluginDescriptorImpl>,
activityPrefix: String,
onlyIfAwait: Boolean = false): ServicePreloadingResult {
val asyncPreloadedServices = mutableListOf<RecursiveAction>()
val syncPreloadedServices = mutableListOf<RecursiveAction>()
for (plugin in plugins) {
serviceLoop@
for (service in getContainerDescriptor(plugin).services) {
@@ -913,18 +909,20 @@ abstract class ComponentManagerImpl @JvmOverloads constructor(internal val paren
asyncPreloadedServices
}
}
PreloadMode.AWAIT -> {
syncPreloadedServices
}
PreloadMode.AWAIT -> syncPreloadedServices
PreloadMode.FALSE -> continue@serviceLoop
else -> throw IllegalStateException("Unknown preload mode ${service.preload}")
}
val future = CompletableFuture.runAsync(Runnable {
if (!isServicePreloadingCancelled && !isDisposed) {
val adapter = componentKeyToAdapter.get(service.getInterface()) as ServiceComponentAdapter? ?: return@Runnable
list.add(object : RecursiveAction() {
override fun compute() {
if (isServicePreloadingCancelled || isDisposed) {
return
}
val adapter = componentKeyToAdapter.get(service.getInterface()) as ServiceComponentAdapter? ?: return
try {
adapter.getInstance<Any>(this, null)
adapter.getInstance<Any>(this@ComponentManagerImpl, null)
}
catch (ignore: AlreadyDisposedException) {
}
@@ -933,13 +931,22 @@ abstract class ComponentManagerImpl @JvmOverloads constructor(internal val paren
throw e
}
}
}, executor)
list.add(future)
})
}
}
return ServicePreloadingResult(asyncPreloadedServices = CompletableFuture.allOf(*asyncPreloadedServices.toTypedArray()),
syncPreloadedServices = CompletableFuture.allOf(*syncPreloadedServices.toTypedArray()))
return ServicePreloadingResult(
asyncPreloadedServices = CompletableFuture.runAsync({
runActivity("${activityPrefix}service async preloading") {
ForkJoinTask.invokeAll(asyncPreloadedServices)
}
}, ForkJoinPool.commonPool()),
syncPreloadedServices = CompletableFuture.runAsync({
runActivity("${activityPrefix}service sync preloading") {
ForkJoinTask.invokeAll(syncPreloadedServices)
}
}, ForkJoinPool.commonPool())
)
}
override fun isDisposed(): Boolean {

View File

@@ -1,4 +1,4 @@
// Copyright 2000-2020 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.
// Copyright 2000-2021 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
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory
@@ -17,10 +17,7 @@ import com.intellij.ui.IconManager
import com.intellij.util.SystemProperties
import com.intellij.util.concurrency.AppExecutorUtil
import java.awt.EventQueue
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
import java.util.concurrent.TimeUnit
import java.util.concurrent.TimeoutException
import java.util.concurrent.*
import java.util.function.Supplier
fun loadHeadlessAppInUnitTestMode() {
@@ -63,14 +60,12 @@ internal fun doLoadApp(setupEventQueue: () -> Unit) {
plugins = registerRegistryAndInitStore(registerAppComponents(loadedPluginFuture, app), app)
.get(40, TimeUnit.SECONDS)
val boundedExecutor = createExecutorToPreloadServices()
Registry.getInstance().markAsLoaded()
val preloadServiceFuture = preloadServices(plugins, app, activityPrefix = "", executor = boundedExecutor)
val preloadServiceFuture = preloadServices(plugins, app, activityPrefix = "")
app.loadComponents(null)
preloadServiceFuture
.thenCompose { callAppInitialized(app, boundedExecutor) }
.thenRun { ForkJoinTask.invokeAll(callAppInitialized(app)) }
.get(40, TimeUnit.SECONDS)
(PersistentFS.getInstance() as PersistentFSImpl).cleanPersistedContents()

View File

@@ -23,7 +23,6 @@ final class EdtScheduledExecutorServiceImpl extends SchedulingWrapper implements
super(EdtExecutorServiceImpl.INSTANCE, ((AppScheduledExecutorService)AppExecutorUtil.getAppScheduledExecutorService()).delayQueue);
}
@NotNull
@Override
public ScheduledFuture<?> schedule(@NotNull Runnable command, @NotNull ModalityState modalityState, long delay, TimeUnit unit) {

View File

@@ -1839,9 +1839,6 @@ idea.lazy.classloading.caches=false
idea.lazy.classloading.caches.description=Flag for UrlClassLoader to use lazy caching of package contents
idea.use.loader.for.jdk9=true
enable.activity.preloading=true
enable.activity.preloading.description=While application starts, preload classes and other resources for popular subsystems to reduce delays when they're first invoked
toolwindow.active.tab.use.contrast.background=false
toolwindow.active.tab.use.contrast.background.description=When enabled contrast color is used for selected tab background in tool windows
toolwindow.active.tab.contrast.background.color=808080

View File

@@ -7,7 +7,6 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.SystemInfoRt;
import com.intellij.openapi.util.text.StringUtilRt;
import com.intellij.util.concurrency.AppExecutorUtil;
import com.intellij.util.containers.CollectionFactory;
import com.intellij.util.io.BaseOutputReader;
import org.jetbrains.annotations.*;
@@ -23,6 +22,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicReference;
@@ -118,7 +118,7 @@ public final class EnvironmentUtil {
callback.run();
state.complete(result);
}
}, AppExecutorUtil.getAppExecutorService()));
}, ForkJoinPool.commonPool()));
return state;
}
@@ -487,7 +487,7 @@ public final class EnvironmentUtil {
}
}
private static class StreamGobbler extends BaseOutputReader {
private static final class StreamGobbler extends BaseOutputReader {
private static final Options OPTIONS = new Options() {
@Override
public SleepingPolicy policy() {
@@ -510,7 +510,7 @@ public final class EnvironmentUtil {
@Override
protected @NotNull Future<?> executeOnPooledThread(@NotNull Runnable runnable) {
return AppExecutorUtil.getAppExecutorService().submit(runnable);
return ForkJoinPool.commonPool().submit(runnable);
}
@Override