diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java index e544e7744b9..87c12ef4462 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Application.java @@ -64,6 +64,7 @@ import org.eclipse.e4.ui.internal.workbench.ResourceHandler; import org.eclipse.e4.ui.internal.workbench.SelectionAggregator; import org.eclipse.e4.ui.internal.workbench.SelectionServiceImpl; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.e4.ui.internal.workbench.URIHelper; import org.eclipse.e4.ui.internal.workbench.WorkbenchLogger; import org.eclipse.e4.ui.model.application.MAddon; @@ -140,6 +141,7 @@ public Display getApplicationDisplay() { @Override public Object start(IApplicationContext applicationContext) throws Exception { + long tStart = StartupTrace.begin(); // set the display name before the Display is // created to ensure the app name is used in any // platform menus, etc. See @@ -148,7 +150,9 @@ public Object start(IApplicationContext applicationContext) throws Exception { if (product != null && product.getName() != null) { Display.setAppName(product.getName()); } + long tDisp = StartupTrace.begin(); Display display = getApplicationDisplay(); + StartupTrace.record("E4Application.start/getApplicationDisplay", tDisp); //$NON-NLS-1$ Location instanceLocation = null; try { E4Workbench workbench = createE4Workbench(applicationContext, display); @@ -160,11 +164,15 @@ public Object start(IApplicationContext applicationContext) throws Exception { // place it off so it's not visible shell.setLocation(0, 10000); } - if (!checkInstanceLocation(instanceLocation, shell, workbench.getContext())) { + long tCheck = StartupTrace.begin(); + boolean ok = checkInstanceLocation(instanceLocation, shell, workbench.getContext()); + StartupTrace.record("E4Application.start/checkInstanceLocation", tCheck); //$NON-NLS-1$ + if (!ok) { return EXIT_OK; } // Create and run the UI (if any) + StartupTrace.record("E4Application.start (pre-createAndRunUI)", tStart); //$NON-NLS-1$ workbench.createAndRunUI(workbench.getApplication()); saveModel(); @@ -210,9 +218,12 @@ public void saveModel() { } public E4Workbench createE4Workbench(IApplicationContext applicationContext, final Display display) { + long tTotal = StartupTrace.begin(); args = (String[]) applicationContext.getArguments().get(IApplicationContext.APPLICATION_ARGS); + long tCtx = StartupTrace.begin(); IEclipseContext appContext = createDefaultContext(); + StartupTrace.record("E4Application.createE4Workbench/createDefaultContext", tCtx); //$NON-NLS-1$ appContext.set(Display.class, display); appContext.set(Realm.class, DisplayRealm.getRealm(display)); appContext.set(UISynchronize.class, new DisplayUISynchronize(display)); @@ -227,6 +238,7 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin // Install the life-cycle manager for this session if there's one // defined + long tLc = StartupTrace.begin(); Optional lifeCycleURI = getArgValue(IWorkbench.LIFE_CYCLE_URI_ARG, applicationContext, false); lifeCycleURI.ifPresent(lifeCycleURIValue -> { lcManager = factory.create(lifeCycleURIValue, appContext); @@ -235,6 +247,7 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin ContextInjectionFactory.invoke(lcManager, PostContextCreate.class, appContext, null); } }); + StartupTrace.record("E4Application.createE4Workbench/lifecycle manager (PostContextCreate)", tLc); //$NON-NLS-1$ Optional forcedPerspectiveId = getArgValue(PERSPECTIVE_ARG_NAME, applicationContext, false); forcedPerspectiveId.ifPresent(forcedPerspectiveIdValue -> appContext.set(E4Workbench.FORCED_PERSPECTIVE_ID, @@ -246,7 +259,9 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin } // Create the app model and its context + long tModel = StartupTrace.begin(); MApplication appModel = loadApplicationModel(applicationContext, appContext); + StartupTrace.record("E4Application.createE4Workbench/loadApplicationModel", tModel); //$NON-NLS-1$ appModel.setContext(appContext); boolean isRtl = ((Window.getDefaultOrientation() & SWT.RIGHT_TO_LEFT) != 0); @@ -263,21 +278,34 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin appContext.set(MApplication.class, appModel); // adds basic services to the contexts + long tSvc = StartupTrace.begin(); initializeServices(appModel); + StartupTrace.record("E4Application.createE4Workbench/initializeServices", tSvc); //$NON-NLS-1$ // let the life cycle manager add to the model if (lcManager != null) { + long tLc2 = StartupTrace.begin(); ContextInjectionFactory.invoke(lcManager, ProcessAdditions.class, appContext, null); ContextInjectionFactory.invoke(lcManager, ProcessRemovals.class, appContext, null); + StartupTrace.record("E4Application.createE4Workbench/lifecycle ProcessAdditions+Removals", tLc2); //$NON-NLS-1$ } // Create the addons + long tAddons = StartupTrace.begin(); + long tQuery = StartupTrace.begin(); IEclipseContext addonStaticContext = EclipseContextFactory.create(); - for (MAddon addon : appModel.getAddons()) { + List addons = appModel.getAddons(); + StartupTrace.record("create addons/query extension registry", tQuery); //$NON-NLS-1$ + long tInstantiate = StartupTrace.begin(); + int addonCount = 0; + for (MAddon addon : addons) { addonStaticContext.set(MAddon.class, addon); Object obj = factory.create(addon.getContributionURI(), appContext, addonStaticContext); addon.setObject(obj); + addonCount++; } + StartupTrace.record("create addons/instantiate addons (count=" + addonCount + ")", tInstantiate); //$NON-NLS-1$ //$NON-NLS-2$ + StartupTrace.record("E4Application.createE4Workbench/create addons", tAddons); //$NON-NLS-1$ // Parse out parameters from both the command line and/or the product // definition (if any) and put them in the context @@ -287,7 +315,9 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin }); + long tCss = StartupTrace.begin(); setCSSContextVariables(applicationContext, appContext); + StartupTrace.record("E4Application.createE4Workbench/setCSSContextVariables", tCss); //$NON-NLS-1$ Optional rendererFactoryURI = getArgValue(E4Workbench.RENDERER_FACTORY_URI, applicationContext, false); rendererFactoryURI.ifPresent(rendererFactoryURIValue -> { @@ -300,7 +330,11 @@ public E4Workbench createE4Workbench(IApplicationContext applicationContext, fin // Instantiate the Workbench (which is responsible for // 'running' the UI (if any)... - return workbench = new E4Workbench(appModel, appContext); + long tCtor = StartupTrace.begin(); + E4Workbench wb = new E4Workbench(appModel, appContext); + StartupTrace.record("E4Application.createE4Workbench/new E4Workbench(ctor)", tCtor); //$NON-NLS-1$ + StartupTrace.record("E4Application.createE4Workbench (total)", tTotal); //$NON-NLS-1$ + return workbench = wb; } private void setCSSContextVariables(IApplicationContext applicationContext, IEclipseContext context) { @@ -378,10 +412,14 @@ private MApplication loadApplicationModel(IApplicationContext appContext, IEclip IContributionFactory factory = eclipseContext.get(IContributionFactory.class); + long tHandler = StartupTrace.begin(); handler = (IModelResourceHandler) factory.create(resourceHandler, eclipseContext); + StartupTrace.record("loadApplicationModel/create IModelResourceHandler", tHandler); //$NON-NLS-1$ eclipseContext.set(IModelResourceHandler.class, handler); + long tLoad = StartupTrace.begin(); Resource resource = handler.loadMostRecentModel(); + StartupTrace.record("loadApplicationModel/handler.loadMostRecentModel (XMI parse)", tLoad); //$NON-NLS-1$ return (MApplication) resource.getContents().get(0); } @@ -509,21 +547,37 @@ public void stop() { // TODO This should go into a different bundle public static IEclipseContext createDefaultHeadlessContext() { + long tCreate = StartupTrace.begin(); IEclipseContext serviceContext = E4Workbench.getServiceContext(); + StartupTrace.record("createDefaultContext/EclipseContextFactory.create", tCreate); //$NON-NLS-1$ + long tCore = StartupTrace.begin(); + long coreCifNs = 0L; + int coreCifCount = 0; IExtensionRegistry registry = RegistryFactory.getRegistry(); ExceptionHandler exceptionHandler = new ExceptionHandler(); serviceContext.set(IContributionFactory.class, new ReflectionContributionFactory()); serviceContext.set(IExceptionHandler.class, exceptionHandler); serviceContext.set(IExtensionRegistry.class, registry); - serviceContext.set(Adapter.class, ContextInjectionFactory.make(EclipseAdapter.class, serviceContext)); + long tCif1 = StartupTrace.begin(); + EclipseAdapter adapter = ContextInjectionFactory.make(EclipseAdapter.class, serviceContext); + coreCifNs += System.nanoTime() - tCif1; + coreCifCount++; + serviceContext.set(Adapter.class, adapter); // No default log provider available if (serviceContext.get(ILoggerProvider.class) == null) { - serviceContext.set(ILoggerProvider.class, - ContextInjectionFactory.make(DefaultLoggerProvider.class, serviceContext)); + long tCif2 = StartupTrace.begin(); + DefaultLoggerProvider loggerProvider = ContextInjectionFactory.make(DefaultLoggerProvider.class, serviceContext); + coreCifNs += System.nanoTime() - tCif2; + coreCifCount++; + serviceContext.set(ILoggerProvider.class, loggerProvider); } + StartupTrace.record( + "createDefaultContext/register core services/ContextInjectionFactory.make (count=" + coreCifCount + ")", //$NON-NLS-1$ //$NON-NLS-2$ + System.nanoTime() - coreCifNs); + StartupTrace.record("createDefaultContext/register core services", tCore); //$NON-NLS-1$ return serviceContext; } @@ -532,12 +586,25 @@ public static IEclipseContext createDefaultHeadlessContext() { public static IEclipseContext createDefaultContext() { IEclipseContext serviceContext = createDefaultHeadlessContext(); + + long tUi = StartupTrace.begin(); + long uiCifNs = 0L; + int uiCifCount = 0; final IEclipseContext appContext = serviceContext.createChild("WorkbenchContext"); //$NON-NLS-1$ // make application context available for dependency injection under the E4Application.APPLICATION_CONTEXT_KEY key appContext.set(IWorkbench.APPLICATION_CONTEXT_KEY, appContext); - appContext.set(Logger.class, ContextInjectionFactory.make(WorkbenchLogger.class, appContext)); - appContext.set(EModelService.class, ContextInjectionFactory.make(ModelServiceImpl.class, appContext)); + long tCif3 = StartupTrace.begin(); + WorkbenchLogger logger = ContextInjectionFactory.make(WorkbenchLogger.class, appContext); + uiCifNs += System.nanoTime() - tCif3; + uiCifCount++; + appContext.set(Logger.class, logger); + + long tCif4 = StartupTrace.begin(); + ModelServiceImpl modelService = ContextInjectionFactory.make(ModelServiceImpl.class, appContext); + uiCifNs += System.nanoTime() - tCif4; + uiCifCount++; + appContext.set(EModelService.class, modelService); appContext.set(EPlaceholderResolver.class, new PlaceholderResolver()); // setup for commands and handlers @@ -571,6 +638,10 @@ public void setClassnameAndId(Object widget, String classname, String id) { // translation initializeLocalization(appContext); + StartupTrace.record( + "createDefaultContext/register UI services/ContextInjectionFactory.make (count=" + uiCifCount + ")", //$NON-NLS-1$ //$NON-NLS-2$ + System.nanoTime() - uiCifNs); + StartupTrace.record("createDefaultContext/register UI services", tUi); //$NON-NLS-1$ return appContext; } diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelAssembler.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelAssembler.java index 581e1243588..a7928583b53 100644 --- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelAssembler.java +++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ModelAssembler.java @@ -41,6 +41,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; @@ -314,11 +315,17 @@ public void processModel(boolean initial) { IExtension[] extensions = new ExtensionsSort().sort(extPoint.getExtensions()); // run processors which are marked to run before fragments + long tProcBefore = StartupTrace.begin(); runProcessors(extensions, initial, false); + StartupTrace.record("handler.loadMostRecentModel/processor.process", tProcBefore); //$NON-NLS-1$ // process fragments (and resolve imports) + long tFrag = StartupTrace.begin(); processFragments(extensions, initial); + StartupTrace.record("handler.loadMostRecentModel/fragments.process", tFrag); //$NON-NLS-1$ // run processors which are marked to run after fragments + long tProcAfter = StartupTrace.begin(); runProcessors(extensions, initial, true); + StartupTrace.record("handler.loadMostRecentModel/processor.process", tProcAfter); //$NON-NLS-1$ } // once we are done, any further handling in the tracker can't be initial diff --git a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ResourceHandler.java b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ResourceHandler.java index e763473da1f..7ec02987848 100644 --- a/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ResourceHandler.java +++ b/bundles/org.eclipse.e4.ui.workbench/src/org/eclipse/e4/ui/internal/workbench/ResourceHandler.java @@ -31,6 +31,7 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.core.runtime.URIUtil; import org.eclipse.e4.core.contexts.ContextInjectionFactory; import org.eclipse.e4.core.contexts.IEclipseContext; @@ -139,6 +140,7 @@ private boolean hasTopLevelWindows(Resource applicationResource) { @Override public Resource loadMostRecentModel() { + long tResolve = StartupTrace.begin(); File workbenchData = null; URI restoreLocation = null; @@ -160,10 +162,13 @@ public Resource loadMostRecentModel() { // boolean restore = restoreLastModified > lastApplicationModification; boolean restore = restoreLastModified > 0; boolean initialModel; + StartupTrace.record("handler.loadMostRecentModel/resolve applicationXMI URI", tResolve); //$NON-NLS-1$ resource = null; if (restore && saveAndRestore) { - resource = loadResource(restoreLocation); + long tDeltas = StartupTrace.begin(); + resource = loadResource(restoreLocation, "handler.loadMostRecentModel/merge deltas"); //$NON-NLS-1$ + StartupTrace.record("handler.loadMostRecentModel/merge deltas (if persisted state exists)", tDeltas); //$NON-NLS-1$ // If the saved model does not have any top-level windows, Eclipse will exit // immediately, so throw out the persisted state and reinitialize with the defaults. if (!hasTopLevelWindows(resource)) { @@ -175,7 +180,9 @@ public Resource loadMostRecentModel() { } } if (resource == null) { - Resource applicationResource = loadResource(applicationDefinitionInstance); + long tLoad = StartupTrace.begin(); + Resource applicationResource = loadResource(applicationDefinitionInstance, null); + StartupTrace.record("handler.loadMostRecentModel/load default model (XMIResource.load)", tLoad); //$NON-NLS-1$ MApplication theApp = (MApplication) applicationResource.getContents().get(0); resource = createResourceWithApp(theApp); context.set(E4Workbench.NO_SAVED_MODEL_FOUND, Boolean.TRUE); @@ -257,10 +264,14 @@ private File getBaseLocation() { } // Ensures that even models with error are loaded! - private Resource loadResource(URI uri) { + private Resource loadResource(URI uri, String tracePhasePrefix) { Resource resource; try { + long tLoad = StartupTrace.begin(); resource = getResource(uri); + if (tracePhasePrefix != null) { + StartupTrace.record(tracePhasePrefix + "/load delta resource", tLoad); //$NON-NLS-1$ + } } catch (Exception e) { // TODO We could use diagnostics for better analyzing the error logger.error(e, "Unable to load resource " + uri); //$NON-NLS-1$ @@ -270,13 +281,19 @@ private Resource loadResource(URI uri) { // TODO once we switch from deltas, we only need this once on the default model? String contributorURI = URIHelper.EMFtoPlatform(uri); if (contributorURI != null) { + long tApply = StartupTrace.begin(); + int count = 0; TreeIterator it = EcoreUtil.getAllContents(resource.getContents()); while (it.hasNext()) { EObject o = it.next(); if (o instanceof MApplicationElement) { ((MApplicationElement) o).setContributorURI(contributorURI); + count++; } } + if (tracePhasePrefix != null) { + StartupTrace.record(tracePhasePrefix + "/apply delta (count=" + count + ")", tApply); //$NON-NLS-1$ //$NON-NLS-2$ + } } return resource; } diff --git a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java index 77bb2dbda2c..8caeadf235c 100644 --- a/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java +++ b/bundles/org.eclipse.ui.ide.application/src/org/eclipse/ui/internal/ide/application/IDEApplication.java @@ -34,6 +34,7 @@ import java.util.Map; import java.util.Properties; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExecutableExtension; import org.eclipse.core.runtime.IProduct; @@ -148,68 +149,77 @@ public IDEApplication() { @Override public Object start(IApplicationContext appContext) throws Exception { - // Suspend the job manager to prevent background jobs from running. This - // is done to reduce resource contention during startup. - // The job manager will be resumed by the - // IDEWorkbenchAdvisor.postStartup method. - Job.getJobManager().suspend(); + long tStart = StartupTrace.begin(); + try { + // Suspend the job manager to prevent background jobs from running. This + // is done to reduce resource contention during startup. + // The job manager will be resumed by the + // IDEWorkbenchAdvisor.postStartup method. + Job.getJobManager().suspend(); - Display display = createDisplay(); + Display display = createDisplay(); - initializeDefaultTheme(display); + long tProduct = StartupTrace.begin(); + initializeDefaultTheme(display); - // processor must be created before we start event loop - DelayedEventsProcessor processor = new DelayedEventsProcessor(display); + // processor must be created before we start event loop + DelayedEventsProcessor processor = new DelayedEventsProcessor(display); - try { + try { - // look and see if there's a splash shell we can parent off of - Shell shell = WorkbenchPlugin.getSplashShell(display); - if (shell != null) { - // should should set the icon and message for this shell to be the - // same as the chooser dialog - this will be the guy that lives in - // the task bar and without these calls you'd have the default icon - // with no message. - shell.setText(ChooseWorkspaceDialog.getWindowTitle()); - shell.setImages(Window.getDefaultImages()); - } + // look and see if there's a splash shell we can parent off of + Shell shell = WorkbenchPlugin.getSplashShell(display); + if (shell != null) { + // should should set the icon and message for this shell to be the + // same as the chooser dialog - this will be the guy that lives in + // the task bar and without these calls you'd have the default icon + // with no message. + shell.setText(ChooseWorkspaceDialog.getWindowTitle()); + shell.setImages(Window.getDefaultImages()); + } + StartupTrace.record("IDEApplication.start/initializeProduct", tProduct); //$NON-NLS-1$ + + long tCheck = StartupTrace.begin(); + Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments()); + StartupTrace.record("IDEApplication.start/checkInstanceLocation", tCheck); //$NON-NLS-1$ + if (instanceLocationCheck != null) { + WorkbenchPlugin.unsetSplashShell(display); + return instanceLocationCheck; + } - Object instanceLocationCheck = checkInstanceLocation(shell, appContext.getArguments()); - if (instanceLocationCheck != null) { - WorkbenchPlugin.unsetSplashShell(display); - return instanceLocationCheck; - } + // Reset early dark theme styling before the workbench starts; + // the ThemeEngine will apply the correct theme from here on. + resetEarlyDarkTheme(display); + + // create the workbench with this advisor and run it until it exits + // N.B. createWorkbench remembers the advisor, and also registers + // the workbench globally so that all UI plug-ins can find it using + // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench() + int returnCode = PlatformUI.createAndRunWorkbench(display, + new IDEWorkbenchAdvisor(processor)); + + // the workbench doesn't support relaunch yet (bug 61809) so + // for now restart is used, and exit data properties are checked + // here to substitute in the relaunch return code if needed + if (returnCode != PlatformUI.RETURN_RESTART) { + return EXIT_OK; + } - // Reset early dark theme styling before the workbench starts; - // the ThemeEngine will apply the correct theme from here on. - resetEarlyDarkTheme(display); - - // create the workbench with this advisor and run it until it exits - // N.B. createWorkbench remembers the advisor, and also registers - // the workbench globally so that all UI plug-ins can find it using - // PlatformUI.getWorkbench() or AbstractUIPlugin.getWorkbench() - int returnCode = PlatformUI.createAndRunWorkbench(display, - new IDEWorkbenchAdvisor(processor)); - - // the workbench doesn't support relaunch yet (bug 61809) so - // for now restart is used, and exit data properties are checked - // here to substitute in the relaunch return code if needed - if (returnCode != PlatformUI.RETURN_RESTART) { - return EXIT_OK; + // if the exit code property has been set to the relaunch code, then + // return that code now, otherwise this is a normal restart + return EXIT_RELAUNCH.equals(Integer.getInteger(Workbench.PROP_EXIT_CODE)) ? EXIT_RELAUNCH + : EXIT_RESTART; + } finally { + if (display != null) { + display.dispose(); + } + Location instanceLoc = Platform.getInstanceLocation(); + if (instanceLoc != null) { + instanceLoc.release(); + } } - - // if the exit code property has been set to the relaunch code, then - // return that code now, otherwise this is a normal restart - return EXIT_RELAUNCH.equals(Integer.getInteger(Workbench.PROP_EXIT_CODE)) ? EXIT_RELAUNCH - : EXIT_RESTART; } finally { - if (display != null) { - display.dispose(); - } - Location instanceLoc = Platform.getInstanceLocation(); - if (instanceLoc != null) { - instanceLoc.release(); - } + StartupTrace.record("IDEApplication.start (total)", tStart); //$NON-NLS-1$ } } @@ -532,6 +542,8 @@ private static boolean isDevLaunchMode(Map args) { */ private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData, boolean force) { + long tPrompt = StartupTrace.begin(); + try { URL url = null; do { @@ -586,6 +598,9 @@ private URL promptForWorkspace(Shell shell, ChooseWorkspaceData launchData, } return url; } while (true); + } finally { + StartupTrace.record("IDEApplication.start/promptForWorkspace", tPrompt); //$NON-NLS-1$ + } } /** diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java index 71910c2c7b1..1101faf7817 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/Workbench.java @@ -226,6 +226,7 @@ import org.eclipse.ui.internal.menus.WorkbenchMenuService; import org.eclipse.ui.internal.misc.Policy; import org.eclipse.ui.internal.misc.StatusUtil; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.ui.internal.misc.UIStats; import org.eclipse.ui.internal.model.ContributionService; import org.eclipse.ui.internal.progress.ProgressManager; @@ -579,6 +580,7 @@ public static Workbench getInstance() { * IWorkbench.restart}; other values reserved for future use */ public static int createAndRunWorkbench(final Display display, final WorkbenchAdvisor advisor) { + long tOuter = StartupTrace.begin(); final int[] returnCode = new int[1]; Realm.runWithDefault(DisplayRealm.getRealm(display), () -> { boolean showProgress = PrefUtil.getAPIPreferenceStore() @@ -592,7 +594,9 @@ public static int createAndRunWorkbench(final Display display, final WorkbenchAd System.setProperty(org.eclipse.e4.ui.workbench.IWorkbench.XMI_URI_ARG, "org.eclipse.ui.workbench/LegacyIDE.e4xmi"); //$NON-NLS-1$ + long tGetApp = StartupTrace.begin(); Object obj = getApplication(Platform.getCommandLineArgs()); + StartupTrace.record("createAndRunWorkbench/getApplication", tGetApp); //$NON-NLS-1$ IPreferenceStore store = WorkbenchPlugin.getDefault().getPreferenceStore(); if (!store.isDefault(IPreferenceConstants.LAYOUT_DIRECTION)) { @@ -600,13 +604,17 @@ public static int createAndRunWorkbench(final Display display, final WorkbenchAd Window.setDefaultOrientation(orientation); } if (obj instanceof E4Application e4app) { + long tE4Wb = StartupTrace.begin(); E4Workbench e4Workbench = e4app.createE4Workbench(getApplicationContext(), display); + StartupTrace.record("createAndRunWorkbench/E4Application.createE4Workbench", tE4Wb); //$NON-NLS-1$ MApplication appModel = e4Workbench.getApplication(); IEclipseContext context = e4Workbench.getContext(); // create the workbench instance + long tCtor = StartupTrace.begin(); Workbench workbench = new Workbench(display, advisor, appModel, context); + StartupTrace.record("createAndRunWorkbench/new Workbench(ctor)", tCtor); //$NON-NLS-1$ Dictionary properties = new Hashtable<>(); properties.put(Constants.SERVICE_RANKING, Integer.valueOf(Integer.MAX_VALUE - 1)); @@ -667,7 +675,9 @@ public void update() { setSearchContribution(appModel, true); // run the legacy workbench once + long tRunUI = StartupTrace.begin(); returnCode[0] = workbench.runUI(); + StartupTrace.record("createAndRunWorkbench/workbench.runUI", tRunUI); //$NON-NLS-1$ if (AUTOSCALE_ADAPTATION.isMonitorSpecificScalingDisabledForIncompatibility()) { display.asyncExec(() -> { @@ -681,6 +691,8 @@ public void update() { if (serviceListener.get() != null) { WorkbenchPlugin.getDefault().getBundleContext().removeServiceListener(serviceListener.get()); } + StartupTrace.mark("startup.complete (marker)"); //$NON-NLS-1$ + scheduleStartupTraceAutoExit(display); e4Workbench.createAndRunUI(e4Workbench.getApplication()); } if (returnCode[0] != PlatformUI.RETURN_UNSTARTABLE) { @@ -698,9 +710,38 @@ public void update() { } } }); + StartupTrace.record("createAndRunWorkbench (outer total)", tOuter); //$NON-NLS-1$ return returnCode[0]; } + /** + * If the {@code startup.trace.autoExitSeconds} system property is set to a + * positive integer, schedule a graceful workbench close after that many + * seconds. Used for unattended batch collection of startup traces; no-op + * if the property is unset or invalid. + */ + private static void scheduleStartupTraceAutoExit(Display display) { + String raw = System.getProperty("startup.trace.autoExitSeconds"); //$NON-NLS-1$ + if (raw == null) { + return; + } + int seconds; + try { + seconds = Integer.parseInt(raw.trim()); + } catch (NumberFormatException ignored) { + return; + } + if (seconds <= 0) { + return; + } + display.timerExec(seconds * 1000, () -> { + if (!PlatformUI.getWorkbench().isClosing()) { + PlatformUI.getWorkbench().close(); + } + }); + System.err.println("[StartupTrace] auto-exit scheduled in " + seconds + "s"); //$NON-NLS-1$ //$NON-NLS-2$ + } + private static void setSearchContribution(MApplication app, boolean enabled) { for (MTrimContribution contribution : app.getTrimContributions()) { if ("org.eclipse.ui.ide.application.trimcontribution.QuickAccess".contains(contribution //$NON-NLS-1$ @@ -760,6 +801,7 @@ static Object getApplication(@SuppressWarnings("unused") String[] args) { * @return the display */ public static Display createDisplay() { + long tTotal = StartupTrace.begin(); // setup the application name used by SWT to lookup resources on some platforms String applicationName = System.getProperty("eclipse.appName", WorkbenchPlugin.getDefault().getAppName()); //$NON-NLS-1$ if (applicationName != null) { @@ -769,6 +811,7 @@ public static Display createDisplay() { AUTOSCALE_ADAPTATION.setRescaleAtRuntimePropertyFromPreference(); // create the display + long tNew = StartupTrace.begin(); Display newDisplay = Display.getCurrent(); if (newDisplay == null) { if (Policy.DEBUG_SWT_GRAPHICS || Policy.DEBUG_SWT_DEBUG) { @@ -784,6 +827,7 @@ public static Display createDisplay() { newDisplay = new Display(); } } + StartupTrace.record("Workbench.createDisplay/new Display", tNew); //$NON-NLS-1$ // workaround for 1GEZ9UR and 1GF07HN newDisplay.setWarnings(false); @@ -792,8 +836,11 @@ public static Display createDisplay() { // than the JobManager. Thread.currentThread().setPriority(Math.min(Thread.MAX_PRIORITY, Thread.NORM_PRIORITY + 1)); + long tImg = StartupTrace.begin(); initializeImages(); + StartupTrace.record("Workbench.createDisplay/initializeImages (window icons)", tImg); //$NON-NLS-1$ + StartupTrace.record("Workbench.createDisplay (total)", tTotal); //$NON-NLS-1$ return newDisplay; } @@ -1724,6 +1771,7 @@ public ILocalWorkingSetManager createLocalWorkingSetManager() { * @return true if init succeeded. */ private boolean init() { + long tInit = StartupTrace.begin(); // setup debug mode if required. if (WorkbenchPlugin.getDefault().isDebugging()) { WorkbenchPlugin.DEBUG = true; @@ -1751,7 +1799,9 @@ public void runWithException() { // Initialize the activity support. + long t = StartupTrace.begin(); activityHelper = ActivityPersistanceHelper.getInstance(); + StartupTrace.record("Workbench.init/ActivityPersistanceHelper.getInstance", t); //$NON-NLS-1$ StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override @@ -1767,8 +1817,12 @@ public void runWithException() { introDescriptor = (IntroDescriptor) introRegistry.getIntroForProduct(product.getId()); } } + t = StartupTrace.begin(); initializeDefaultServices(); + StartupTrace.record("Workbench.init/initializeDefaultServices", t); //$NON-NLS-1$ + t = StartupTrace.begin(); initializeFonts(); + StartupTrace.record("Workbench.init/initializeFonts", t); //$NON-NLS-1$ initializeApplicationColors(); // now that the workbench is sufficiently initialized, let the advisor @@ -1777,7 +1831,9 @@ public void runWithException() { @Override public void runWithException() { + long t2 = StartupTrace.begin(); advisor.internalBasicInitialize(getWorkbenchConfigurer()); + StartupTrace.record("Workbench.init/advisor.internalBasicInitialize", t2); //$NON-NLS-1$ } }); @@ -1804,26 +1860,36 @@ public void runWithException() { // attempt to restore a previous workbench state try { UIStats.start(UIStats.RESTORE_WORKBENCH, "Workbench"); //$NON-NLS-1$ + long tRestore = StartupTrace.begin(); final boolean bail[] = new boolean[1]; StartupThreading.runWithoutExceptions(new StartupRunnable() { @Override public void runWithException() throws Throwable { + long t2 = StartupTrace.begin(); advisor.preStartup(); + StartupTrace.record("Workbench.init/advisor.preStartup", t2); //$NON-NLS-1$ // TODO compat: open the windows here/instantiate the model // TODO compat: instantiate the WW around the model initializationDone = true; - if (isClosing() || !advisor.openWindows()) { - // if (isClosing()) { + if (isClosing()) { bail[0] = true; + } else { + if (!advisor.openWindows()) { + bail[0] = true; + } } + long t4 = StartupTrace.begin(); restoreWorkbenchState(); + StartupTrace.record("Workbench.init/restoreWorkbenchState", t4); //$NON-NLS-1$ } }); + StartupTrace.record("Workbench.init/restore+openWindows (total)", tRestore); //$NON-NLS-1$ if (bail[0]) { + StartupTrace.record("Workbench.init (total, bailed)", tInit); //$NON-NLS-1$ return false; } @@ -1831,6 +1897,7 @@ public void runWithException() throws Throwable { UIStats.end(UIStats.RESTORE_WORKBENCH, this, "Workbench"); //$NON-NLS-1$ } + StartupTrace.record("Workbench.init (total)", tInit); //$NON-NLS-1$ return true; } @@ -2333,8 +2400,10 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); Command.DEBUG_COMMAND_EXECUTION = Policy.DEBUG_COMMANDS; commandManager = e4Context.get(CommandManager.class); + StartupTrace.record("initializeDefaultServices/commandManager", t); //$NON-NLS-1$ } }); @@ -2343,8 +2412,9 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); commandService[0] = initializeCommandService(e4Context); - + StartupTrace.record("initializeDefaultServices/initializeCommandService", t); //$NON-NLS-1$ } }); @@ -2352,12 +2422,16 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); ContextManager.DEBUG = Policy.DEBUG_CONTEXTS; contextManager = e4Context.get(ContextManager.class); + StartupTrace.record("initializeDefaultServices/contextManager", t); //$NON-NLS-1$ } }); + long tCxs = StartupTrace.begin(); IContextService cxs = ContextInjectionFactory.make(ContextService.class, e4Context); + StartupTrace.record("initializeDefaultServices/ContextService.make", tCxs); //$NON-NLS-1$ final IContextService contextService = cxs; @@ -2365,6 +2439,7 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); contextManager.addContextManagerListener(contextManagerEvent -> { if (contextManagerEvent.isContextChanged()) { String id = contextManagerEvent.getContextId(); @@ -2375,6 +2450,7 @@ public void runWithException() { }); EContextService ecs = e4Context.get(EContextService.class); ecs.activateContext(IContextService.CONTEXT_ID_DIALOG_AND_WINDOW); + StartupTrace.record("initializeDefaultServices/contextManager listener+activate", t); //$NON-NLS-1$ } }); @@ -2386,21 +2462,27 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); BindingManager.DEBUG = Policy.DEBUG_KEY_BINDINGS; bindingManager = e4Context.get(BindingManager.class); bindingService[0] = ContextInjectionFactory.make(BindingService.class, e4Context); + StartupTrace.record("initializeDefaultServices/bindingManager+bindingService", t); //$NON-NLS-1$ } }); // bindingService[0].readRegistryAndPreferences(commandService[0]); serviceLocator.registerService(IBindingService.class, bindingService[0]); + long tCmdImg = StartupTrace.begin(); final CommandImageManager commandImageManager = new CommandImageManager(); final CommandImageService commandImageService = new CommandImageService(commandImageManager, commandService[0]); commandImageService.readRegistry(); + StartupTrace.record("initializeDefaultServices/commandImageService.readRegistry", tCmdImg); //$NON-NLS-1$ serviceLocator.registerService(ICommandImageService.class, commandImageService); + long tMenuCtor = StartupTrace.begin(); final WorkbenchMenuService menuService = new WorkbenchMenuService(serviceLocator, e4Context); + StartupTrace.record("initializeDefaultServices/new WorkbenchMenuService", tMenuCtor); //$NON-NLS-1$ serviceLocator.registerService(IMenuService.class, menuService); // the service must be registered before it is initialized - its @@ -2410,7 +2492,9 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); menuService.readRegistry(); + StartupTrace.record("initializeDefaultServices/menuService.readRegistry", t); //$NON-NLS-1$ } }); @@ -2427,7 +2511,10 @@ public void runWithException() { @Override public void runWithException() { // this currently instantiates all players ... sigh + long tRead = StartupTrace.begin(); sourceProviderService.readRegistry(); + StartupTrace.record("initializeDefaultServices/sourceProviderService.readRegistry", tRead); //$NON-NLS-1$ + long tAdd = StartupTrace.begin(); ISourceProvider[] sourceproviders = sourceProviderService.getSourceProviders(); for (ISourceProvider sp : sourceproviders) { evaluationService.addSourceProvider(sp); @@ -2435,6 +2522,7 @@ public void runWithException() { contextService.addSourceProvider(sp); } } + StartupTrace.record("initializeDefaultServices/register source providers", tAdd); //$NON-NLS-1$ } }); @@ -2464,13 +2552,17 @@ public void runWithException() { @Override public void runWithException() { + long t = StartupTrace.begin(); handlerService[0] = new LegacyHandlerService(e4Context); e4Context.set(IHandlerService.class, handlerService[0]); handlerService[0].readRegistry(); + StartupTrace.record("initializeDefaultServices/handlerService.readRegistry", t); //$NON-NLS-1$ } }); workbenchContextSupport = new WorkbenchContextSupport(this, contextManager); + long tCmdResolver = StartupTrace.begin(); initializeCommandResolver(); + StartupTrace.record("initializeDefaultServices/initializeCommandResolver", tCmdResolver); //$NON-NLS-1$ bindingManager.addBindingManagerListener(bindingManagerListener); diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPlugin.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPlugin.java index 1d4037a9d08..87455743e0f 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPlugin.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/WorkbenchPlugin.java @@ -58,6 +58,7 @@ import org.eclipse.ui.internal.help.HelpServiceImpl; import org.eclipse.ui.internal.intro.IIntroRegistry; import org.eclipse.ui.internal.intro.IntroRegistry; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.ui.internal.misc.StatusUtil; import org.eclipse.ui.internal.operations.WorkbenchOperationSupport; import org.eclipse.ui.internal.progress.ProgressManager; @@ -1253,7 +1254,9 @@ public Object compute(IEclipseContext context, String contextKey) { @Override public Object compute(IEclipseContext context, String contextKey) { if (viewRegistry == null) { + long t = StartupTrace.begin(); viewRegistry = ContextInjectionFactory.make(ViewRegistry.class, e4Context); + StartupTrace.record("ContextFunction.compute/ViewRegistry (first touch)", t); //$NON-NLS-1$ } return viewRegistry; } @@ -1324,7 +1327,6 @@ public Object compute(IEclipseContext context, String contextKey) { PlatformUI.getWorkbench()); registryReader.loadFromRegistry(Platform.getExtensionRegistry()); preferenceManager.addPages(registryReader.getTopLevelNodes()); - } return preferenceManager; } @@ -1343,9 +1345,11 @@ public Object compute(IEclipseContext context, String contextKey) { @Override public Object compute(IEclipseContext context, String contextKey) { if (themeRegistry == null) { + long t = StartupTrace.begin(); themeRegistry = new ThemeRegistry(); ThemeRegistryReader reader = new ThemeRegistryReader(); reader.readThemes(Platform.getExtensionRegistry(), themeRegistry); + StartupTrace.record("ContextFunction.compute/ThemeRegistry (first touch)", t); //$NON-NLS-1$ } return themeRegistry; } @@ -1354,8 +1358,10 @@ public Object compute(IEclipseContext context, String contextKey) { @Override public Object compute(IEclipseContext context, String contextKey) { if (workingSetManager == null) { + long t = StartupTrace.begin(); workingSetManager = new WorkingSetManager(bundleContext); workingSetManager.restoreState(); + StartupTrace.record("ContextFunction.compute/WorkingSetManager (first touch)", t); //$NON-NLS-1$ } return workingSetManager; } @@ -1374,7 +1380,9 @@ public Object compute(IEclipseContext context, String contextKey) { @Override public Object compute(IEclipseContext context, String contextKey) { if (editorRegistry == null) { + long t = StartupTrace.begin(); editorRegistry = new EditorRegistry(Platform.getContentTypeManager()); + StartupTrace.record("ContextFunction.compute/EditorRegistry (first touch)", t); //$NON-NLS-1$ } return editorRegistry; } diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/EditorRegistry.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/EditorRegistry.java index 022f2652142..abd89d2e4db 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/EditorRegistry.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/EditorRegistry.java @@ -76,6 +76,7 @@ import org.eclipse.ui.internal.WorkbenchImages; import org.eclipse.ui.internal.WorkbenchMessages; import org.eclipse.ui.internal.WorkbenchPlugin; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.ui.internal.editorsupport.ComponentSupport; import org.eclipse.ui.internal.misc.ExternalProgramImageDescriptor; import org.eclipse.ui.internal.misc.ProgramImageDescriptor; @@ -610,14 +611,18 @@ private void addSystemEditors(Map map) { * overrides. */ private void initializeFromStorage() { + long tTotal = StartupTrace.begin(); typeEditorMappings = new EditorMap(); extensionImages = new HashMap<>(); // Get editors from the registry + long tRead = StartupTrace.begin(); EditorRegistryReader registryReader = new EditorRegistryReader(); registryReader.addEditors(this); + StartupTrace.record("EditorRegistry.initializeFromStorage/addEditors (registry read)", tRead); //$NON-NLS-1$ sortInternalEditors(); rebuildInternalEditorMap(); + StartupTrace.record("EditorRegistry.initializeFromStorage (total)", tTotal); //$NON-NLS-1$ IPreferenceStore store = PlatformUI.getPreferenceStore(); String defaultEditors = store.getString(IPreferenceConstants.DEFAULT_EDITORS); diff --git a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/ViewRegistry.java b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/ViewRegistry.java index cd955cd7ef8..195542f95f8 100644 --- a/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/ViewRegistry.java +++ b/bundles/org.eclipse.ui.workbench/eclipseui/org/eclipse/ui/internal/registry/ViewRegistry.java @@ -38,6 +38,7 @@ import org.eclipse.ui.IWorkbench; import org.eclipse.ui.activities.WorkbenchActivityHelper; import org.eclipse.ui.internal.IWorkbenchConstants; +import org.eclipse.core.internal.runtime.StartupTrace; import org.eclipse.ui.internal.e4.compatibility.CompatibilityPart; import org.eclipse.ui.internal.menus.MenuHelper; import org.eclipse.ui.part.ViewPart; @@ -88,6 +89,7 @@ public class ViewRegistry implements IViewRegistry { @PostConstruct void postConstruct() { + long tTotal = StartupTrace.begin(); IExtensionPoint point = extensionRegistry.getExtensionPoint("org.eclipse.ui.views"); //$NON-NLS-1$ for (IExtension extension : point.getExtensions()) { // find the category first @@ -110,6 +112,7 @@ void postConstruct() { categories.put(miscCategory.getId(), new ViewCategory(miscCategory.getId(), miscCategory.getLabel())); } + long tPass2 = StartupTrace.begin(); for (IExtension extension : point.getExtensions()) { for (IConfigurationElement element : extension.getConfigurationElements()) { if (element.getName().equals(IWorkbenchRegistryConstants.TAG_VIEW)) { @@ -120,6 +123,8 @@ void postConstruct() { } } } + StartupTrace.record("ViewRegistry.postConstruct/pass2 views", tPass2); //$NON-NLS-1$ + StartupTrace.record("ViewRegistry.postConstruct (total)", tTotal); //$NON-NLS-1$ } private void createDescriptor(IConfigurationElement element, boolean e4View) {