Bug 127793 - Improve Headless startup performance (osgi and core runtime side)
diff --git a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobActivator.java b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobActivator.java
index de73153..b738a6a 100644
--- a/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobActivator.java
+++ b/bundles/org.eclipse.core.jobs/src/org/eclipse/core/internal/jobs/JobActivator.java
@@ -20,6 +20,12 @@
public class JobActivator implements BundleActivator {
/**
+ * Eclipse property. Set to <code>false</code> to avoid registering JobManager
+ * as an OSGi service.
+ */
+ private static final String PROP_REGISTER_JOB_SERVICE = "eclipse.service.jobs"; //$NON-NLS-1$
+
+ /**
* The bundle associated this plug-in
*/
private static BundleContext bundleContext;
@@ -35,7 +41,10 @@
public void start(BundleContext context) throws Exception {
bundleContext = context;
JobOSGiUtils.getDefault().openServices();
- registerServices();
+
+ boolean shouldRegister = !"false".equalsIgnoreCase(context.getProperty(PROP_REGISTER_JOB_SERVICE)); //$NON-NLS-1$
+ if (shouldRegister)
+ registerServices();
}
/**
diff --git a/bundles/org.eclipse.core.runtime/META-INF/MANIFEST.MF b/bundles/org.eclipse.core.runtime/META-INF/MANIFEST.MF
index 0dc7b68..3e7c9bb 100644
--- a/bundles/org.eclipse.core.runtime/META-INF/MANIFEST.MF
+++ b/bundles/org.eclipse.core.runtime/META-INF/MANIFEST.MF
@@ -6,14 +6,14 @@
Bundle-Vendor: %providerName
Bundle-Activator: org.eclipse.core.internal.runtime.PlatformActivator
Bundle-Localization: plugin
-Export-Package: org.eclipse.core.internal.preferences;x-internal:=true,
+Export-Package: org.eclipse.core.internal.preferences.legacy;x-internal:=true,
org.eclipse.core.internal.runtime;x-friends:="org.eclipse.core.runtime.compatibility",
org.eclipse.core.runtime
-Require-Bundle: org.eclipse.equinox.registry;visibility:=reexport,
+Require-Bundle: org.eclipse.osgi;visibility:=reexport,
+ org.eclipse.equinox.common;visibility:=reexport,
org.eclipse.core.jobs;visibility:=reexport,
+ org.eclipse.equinox.registry;visibility:=reexport,
org.eclipse.equinox.preferences;visibility:=reexport,
org.eclipse.core.contenttype;visibility:=reexport,
- org.eclipse.equinox.common;visibility:=reexport,
- org.eclipse.osgi;bundle-version="[3.1.0,4.0.0)";visibility:=reexport,
org.eclipse.core.runtime.compatibility.auth;resolution:=optional
Eclipse-LazyStart: true
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/InitLegacyPreferences.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/InitLegacyPreferences.java
similarity index 94%
rename from bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/InitLegacyPreferences.java
rename to bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/InitLegacyPreferences.java
index ff286d9..c726892 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/InitLegacyPreferences.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/InitLegacyPreferences.java
@@ -8,8 +8,9 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.core.internal.preferences;
+package org.eclipse.core.internal.preferences.legacy;
+import org.eclipse.core.internal.preferences.exchange.ILegacyPreferences;
import org.eclipse.core.internal.runtime.InternalPlatform;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Plugin;
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/PreferenceForwarder.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/PreferenceForwarder.java
similarity index 99%
rename from bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/PreferenceForwarder.java
rename to bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/PreferenceForwarder.java
index 8d27ba3..135cb48 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/PreferenceForwarder.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/PreferenceForwarder.java
@@ -8,11 +8,12 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.core.internal.preferences;
+package org.eclipse.core.internal.preferences.legacy;
import java.io.*;
import java.util.Iterator;
import java.util.Properties;
+import org.eclipse.core.internal.preferences.*;
import org.eclipse.core.internal.runtime.RuntimeLog;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.preferences.DefaultScope;
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/ProductPreferencesService.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/ProductPreferencesService.java
similarity index 96%
rename from bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/ProductPreferencesService.java
rename to bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/ProductPreferencesService.java
index ba2cc21..ebf2e4b 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/ProductPreferencesService.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/preferences/legacy/ProductPreferencesService.java
@@ -8,13 +8,14 @@
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
-package org.eclipse.core.internal.preferences;
+package org.eclipse.core.internal.preferences.legacy;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Properties;
+import org.eclipse.core.internal.preferences.exchange.IProductPreferencesService;
import org.eclipse.core.internal.runtime.InternalPlatform;
import org.eclipse.core.runtime.*;
import org.osgi.framework.Bundle;
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManagerListener.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManagerListener.java
index 7c5fbac..632e377 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManagerListener.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/AdapterManagerListener.java
@@ -19,7 +19,7 @@
*
* @since org.eclipse.core.runtime 3.2
*/
-public final class AdapterManagerListener implements IRegistryChangeListener {
+public final class AdapterManagerListener implements IRegistryChangeListener, IAdapterManagerProvider {
public static final String ADAPTER_POINT_ID = "org.eclipse.core.runtime.adapters"; //$NON-NLS-1$
private AdapterManager theAdapterManager;
@@ -29,8 +29,7 @@
*/
public AdapterManagerListener() {
theAdapterManager = AdapterManager.getDefault();
- registerFactoryProxies();
- RegistryFactory.getRegistry().addRegistryChangeListener(this);
+ theAdapterManager.registerLazyFactoryProvider(this);
}
/**
@@ -38,13 +37,25 @@
* the plug-in registry. Note that the actual factory implementations
* are loaded lazily as they are needed.
*/
- private void registerFactoryProxies() {
+ public boolean addFactories(AdapterManager adapterManager) {
IExtensionPoint point = RegistryFactory.getRegistry().getExtensionPoint(ADAPTER_POINT_ID);
if (point == null)
- return;
+ return false;
+
+ boolean factoriesAdded = false;
IExtension[] extensions = point.getExtensions();
- for (int i = 0; i < extensions.length; i++)
- registerExtension(extensions[i]);
+ for (int i = 0; i < extensions.length; i++) {
+ IConfigurationElement[] elements = extensions[i].getConfigurationElements();
+ for (int j = 0; j < elements.length; j++) {
+ AdapterFactoryProxy proxy = AdapterFactoryProxy.createProxy(elements[j]);
+ if (proxy != null) {
+ adapterManager.registerFactory(proxy, proxy.getAdaptableType());
+ factoriesAdded = true;
+ }
+ }
+ }
+ RegistryFactory.getRegistry().addRegistryChangeListener(this);
+ return factoriesAdded;
}
private void registerExtension(IExtension extension) {
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
index 508d688..4864ed7 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/internal/runtime/InternalPlatform.java
@@ -15,7 +15,10 @@
import java.net.MalformedURLException;
import java.net.URL;
import java.util.*;
-import org.eclipse.core.internal.preferences.*;
+import org.eclipse.core.internal.preferences.exchange.ILegacyPreferences;
+import org.eclipse.core.internal.preferences.exchange.IProductPreferencesService;
+import org.eclipse.core.internal.preferences.legacy.InitLegacyPreferences;
+import org.eclipse.core.internal.preferences.legacy.ProductPreferencesService;
import org.eclipse.core.internal.runtime.auth.AuthorizationHandler;
import org.eclipse.core.runtime.*;
import org.eclipse.core.runtime.content.IContentTypeManager;
@@ -110,6 +113,8 @@
public static final String PROP_SYSPATH = "osgi.syspath"; //$NON-NLS-1$
public static final String PROP_USER_AREA = "osgi.user.area"; //$NON-NLS-1$
public static final String PROP_WS = "osgi.ws"; //$NON-NLS-1$
+ public static final String PROP_ACTIVATE_PLUGINS = "eclipse.activateRuntimePlugins"; //$NON-NLS-1$
+
private static final InternalPlatform singleton = new InternalPlatform();
private static final String UPDATE = "-update"; //$NON-NLS-1$
@@ -341,6 +346,16 @@
public Location getConfigurationLocation() {
assertInitialized();
+ if (configurationLocation == null) {
+ Filter filter = null;
+ try {
+ filter = context.createFilter(Location.CONFIGURATION_FILTER);
+ } catch (InvalidSyntaxException e) {
+ // ignore this. It should never happen as we have tested the above format.
+ }
+ configurationLocation = new ServiceTracker(context, filter, null);
+ configurationLocation.open();
+ }
return (Location) configurationLocation.getService();
}
@@ -360,7 +375,7 @@
public EnvironmentInfo getEnvironmentInfoService() {
if (environmentTracker == null) {
if (context == null)
- return null;
+ return null;
environmentTracker = new ServiceTracker(context, EnvironmentInfo.class.getName(), null);
environmentTracker.open();
}
@@ -393,6 +408,16 @@
public Location getInstallLocation() {
assertInitialized();
+ Filter filter = null;
+ if (installLocation == null) {
+ try {
+ filter = context.createFilter(Location.INSTALL_FILTER);
+ } catch (InvalidSyntaxException e) {
+ // ignore this. It should never happen as we have tested the above format.
+ }
+ installLocation = new ServiceTracker(context, filter, null);
+ installLocation.open();
+ }
return (Location) installLocation.getService();
}
@@ -407,6 +432,16 @@
public Location getInstanceLocation() {
assertInitialized();
+ if (instanceLocation == null) {
+ Filter filter = null;
+ try {
+ filter = context.createFilter(Location.INSTANCE_FILTER);
+ } catch (InvalidSyntaxException e) {
+ // ignore this. It should never happen as we have tested the above format.
+ }
+ instanceLocation = new ServiceTracker(context, filter, null);
+ instanceLocation.open();
+ }
return (Location) instanceLocation.getService();
}
@@ -633,7 +668,7 @@
}
public IExtensionRegistry getRegistry() {
- return RegistryFactory.getRegistry();
+ return RegistryFactory.getRegistry();
}
public ResourceBundle getResourceBundle(Bundle bundle) {
@@ -693,6 +728,16 @@
public Location getUserLocation() {
assertInitialized();
+ if (userLocation == null) {
+ Filter filter = null;
+ try {
+ filter = context.createFilter(Location.USER_FILTER);
+ } catch (InvalidSyntaxException e) {
+ // ignore this. It should never happen as we have tested the above format.
+ }
+ userLocation = new ServiceTracker(context, filter, null);
+ userLocation.open();
+ }
return (Location) userLocation.getService();
}
@@ -728,41 +773,6 @@
}
}
- private void initializeLocationTrackers() {
- Filter filter = null;
- try {
- filter = context.createFilter(Location.CONFIGURATION_FILTER);
- } catch (InvalidSyntaxException e) {
- // ignore this. It should never happen as we have tested the above format.
- }
- configurationLocation = new ServiceTracker(context, filter, null);
- configurationLocation.open();
-
- try {
- filter = context.createFilter(Location.USER_FILTER);
- } catch (InvalidSyntaxException e) {
- // ignore this. It should never happen as we have tested the above format.
- }
- userLocation = new ServiceTracker(context, filter, null);
- userLocation.open();
-
- try {
- filter = context.createFilter(Location.INSTANCE_FILTER);
- } catch (InvalidSyntaxException e) {
- // ignore this. It should never happen as we have tested the above format.
- }
- instanceLocation = new ServiceTracker(context, filter, null);
- instanceLocation.open();
-
- try {
- filter = context.createFilter(Location.INSTALL_FILTER);
- } catch (InvalidSyntaxException e) {
- // ignore this. It should never happen as we have tested the above format.
- }
- installLocation = new ServiceTracker(context, filter, null);
- installLocation.open();
- }
-
public boolean isFragment(Bundle bundle) {
PackageAdmin packageAdmin = getBundleAdmin();
if (packageAdmin == null)
@@ -967,7 +977,6 @@
*/
public void start(BundleContext runtimeContext) {
this.context = runtimeContext;
- initializeLocationTrackers();
splashHandler = getSplashHandler();
processCommandLine(getEnvironmentInfoService().getNonFrameworkArgs());
initializeDebugFlags();
@@ -978,6 +987,16 @@
addLogListener(platformLog);
adapterManagerListener = new AdapterManagerListener(); // after extension registry
startServices();
+
+ // See if need to activate rest of the runtime plugins. Plugins are "gently" activated by touching
+ // a class from the corresponding plugin(s).
+ boolean shouldActivate = !"false".equalsIgnoreCase(context.getProperty(PROP_ACTIVATE_PLUGINS)); //$NON-NLS-1$
+ if (shouldActivate) {
+ // activate Preferences plugin by creating a class from it:
+ new org.eclipse.core.runtime.preferences.DefaultScope();
+ // activate Jobs plugin by creating a class from it:
+ org.eclipse.core.runtime.jobs.Job.getJobManager();
+ }
}
/**
@@ -1021,8 +1040,14 @@
}
private void startServices() {
+ // The check for getProduct() is relatively expensive (about 3% of the headless startup),
+ // so we don't want to enforce it here.
customPreferencesService = getBundleContext().registerService(IProductPreferencesService.class.getName(), new ProductPreferencesService(), new Hashtable());
- legacyPreferencesService = getBundleContext().registerService(ILegacyPreferences.class.getName(), new InitLegacyPreferences(), new Hashtable());
+
+ // Only register this interface if compatibility is installed - the check for a bundle presence
+ // is a quick test that doesn't consume much.
+ if (getBundle(CompatibilityHelper.PI_RUNTIME_COMPATIBILITY) != null)
+ legacyPreferencesService = getBundleContext().registerService(ILegacyPreferences.class.getName(), new InitLegacyPreferences(), new Hashtable());
}
private void stopServices() {
diff --git a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
index f9c8640..e64c91d 100644
--- a/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
+++ b/bundles/org.eclipse.core.runtime/src/org/eclipse/core/runtime/Plugin.java
@@ -15,12 +15,9 @@
import java.lang.reflect.Method;
import java.net.URL;
import java.util.Map;
-import org.eclipse.core.internal.preferences.PreferenceForwarder;
import org.eclipse.core.internal.runtime.*;
-import org.eclipse.core.runtime.preferences.InstanceScope;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
-import org.osgi.service.prefs.BackingStoreException;
/**
* The abstract superclass of all plug-in runtime class
@@ -107,11 +104,14 @@
/**
* String constant used for the default scope name for legacy
- * Eclipse plug-in preferences.
+ * Eclipse plug-in preferences. The value of <code>PLUGIN_PREFERENCE_SCOPE</code> should
+ * match the InstanceScope's variable SCOPE from org.eclipse.core.runtime.preferences.
+ * The value is copied in this file to prevent unnecessary activation of
+ * the Preferences plugin on startup.
*
* @since 3.0
*/
- public static final String PLUGIN_PREFERENCE_SCOPE = InstanceScope.SCOPE;
+ public static final String PLUGIN_PREFERENCE_SCOPE = "instance"; //$NON-NLS-1$
/**
* The bundle associated this plug-in
@@ -158,7 +158,7 @@
*
* @since 2.0
*/
- private PreferenceForwarder preferences = null;
+ private Preferences preferences = null;
/**
* Creates a new plug-in runtime object. This method is called by the platform
@@ -338,7 +338,19 @@
if (InternalPlatform.DEBUG_PLUGIN_PREFERENCES)
InternalPlatform.message("Loading preferences for plugin: " + bundle.getSymbolicName()); //$NON-NLS-1$
- preferences = new PreferenceForwarder(this, bundle.getSymbolicName());
+
+ // Performance: isolate PreferenceForwarder into an inner class so that it mere presence
+ // won't force the PreferenceForwarder class to be loaded (which triggers Preferences plugin
+ // activation).
+ final Bundle bundleCopy = bundle;
+ final Preferences[] preferencesCopy = new Preferences[1];
+ Runnable innerCall = new Runnable() {
+ public void run() {
+ preferencesCopy[0] = new org.eclipse.core.internal.preferences.legacy.PreferenceForwarder(this, bundleCopy.getSymbolicName());
+ }
+ };
+ innerCall.run();
+ preferences = preferencesCopy[0];
return preferences;
}
@@ -359,12 +371,22 @@
// need to save them because someone else might have
// made changes via the OSGi APIs.
getPluginPreferences();
- try {
- preferences.flush();
- } catch (BackingStoreException e) {
- IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR, Messages.preferences_saveProblems, e);
- InternalPlatform.getDefault().log(status);
- }
+
+ // Performance: isolate PreferenceForwarder and BackingStoreException into
+ // an inner class to avoid class loading (and then activation of the Preferences plugin)
+ // as the Plugin class is loaded.
+ final Preferences preferencesCopy = preferences;
+ Runnable innerCall = new Runnable() {
+ public void run() {
+ try {
+ ((org.eclipse.core.internal.preferences.legacy.PreferenceForwarder) preferencesCopy).flush();
+ } catch (org.osgi.service.prefs.BackingStoreException e) {
+ IStatus status = new Status(IStatus.ERROR, Platform.PI_RUNTIME, IStatus.ERROR, Messages.preferences_saveProblems, e);
+ InternalPlatform.getDefault().log(status);
+ }
+ }
+ };
+ innerCall.run();
}
/**
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/PreferenceForwarderTest.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/PreferenceForwarderTest.java
index 4a113aa..770ca14 100644
--- a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/PreferenceForwarderTest.java
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/PreferenceForwarderTest.java
@@ -14,7 +14,7 @@
import java.util.*;
import junit.framework.Test;
import junit.framework.TestSuite;
-import org.eclipse.core.internal.preferences.PreferenceForwarder;
+import org.eclipse.core.internal.preferences.legacy.PreferenceForwarder;
import org.eclipse.core.runtime.Preferences;
/**
diff --git a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/perf/AllTests.java b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/perf/AllTests.java
index ff0ab39..f503ab8 100644
--- a/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/perf/AllTests.java
+++ b/tests/org.eclipse.core.tests.runtime/src/org/eclipse/core/tests/runtime/perf/AllTests.java
@@ -30,7 +30,16 @@
fail("Unable to create warm up test");
}
- suite.addTest(new PerformanceSessionTestSuite(RuntimeTestsPlugin.PI_RUNTIME_TESTS, 5, StartupTest.class));
+ // For this test to take advantage of the new runtime processing, we set "-eclipse.activateRuntimePlugins=false"
+ try {
+ PerformanceSessionTestSuite headlessSuite = new PerformanceSessionTestSuite(RuntimeTestsPlugin.PI_RUNTIME_TESTS, 5, StartupTest.class);
+ Setup headlessSetup = headlessSuite.getSetup();
+ headlessSetup.setSystemProperty("eclipse.activateRuntimePlugins", "false");
+ suite.addTest(headlessSuite);
+ } catch (SetupException e) {
+ fail("Unable to setup headless startup performance test");
+ }
+
suite.addTest(new UIPerformanceSessionTestSuite(RuntimeTestsPlugin.PI_RUNTIME_TESTS, 5, UIStartupTest.class));
suite.addTest(BenchPath.suite());
suite.addTest(ContentTypePerformanceTest.suite());