Bug 569918 - UI freezes in EditorRegistry.getSystemExternalEditorImageDescriptor
Summary: UI freezes in EditorRegistry.getSystemExternalEditorImageDescriptor
Status: NEW
Alias: None
Product: Platform
Classification: Eclipse Project
Component: UI (show other bugs)
Version: 4.19   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: Platform-UI-Inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2020-12-24 11:32 EST by Michael Keppler CLA
Modified: 2023-04-14 09:59 EDT (History)
3 users (show)

See Also:


Attachments
profiler screenshot (54.82 KB, image/png)
2020-12-24 11:32 EST, Michael Keppler CLA
no flags Details
AssocQueryString consumes all the time (47.00 KB, image/png)
2020-12-27 10:53 EST, Michael Keppler CLA
no flags Details

Note You need to log in before you can comment on or make changes to this bug.
Description Michael Keppler CLA 2020-12-24 11:32:17 EST
Created attachment 285107 [details]
profiler screenshot

Reproduction:
* Have 100 pom.xml files in the workspace.
* Try to scroll from one file to the next and continue.

Eclipse shows UI freezes and "application does not respond" quite often. The root cause seems to be that the "base icon" for file types not handled by eclipse is re-computed from scratch every time a tree item in the package explorer changes.

With the profiler attached to the IDE, I've collected several seconds of CPU time in org.eclipse.ui.internal.registry.EditorRegistry.getSystemExternalEditorImageDescriptor(String) during 20 seconds of just browsing the package explorer (see attached profiler output).

We should probably have some kind of caching for the external editor image instead of requesting it over and over again from the operating system.

The UI freezes are all reported similar to this stack trace:
Stack Trace
	at org.eclipse.swt.internal.win32.OS.AssocQueryString(Native Method)
	at org.eclipse.swt.internal.win32.OS.AssocQueryString(OS.java:1988)
	at org.eclipse.swt.program.Program.assocQueryString(Program.java:48)
	at org.eclipse.swt.program.Program.findProgram(Program.java:89)
	at org.eclipse.ui.internal.registry.EditorRegistry.getSystemExternalEditorImageDescriptor(EditorRegistry.java:1181)
	at org.eclipse.ui.internal.registry.EditorRegistry.getImageDescriptor(EditorRegistry.java:1373)
	at org.eclipse.ui.internal.ide.model.WorkbenchFile.getBaseImage(WorkbenchFile.java:67)
	at org.eclipse.ui.internal.ide.model.WorkbenchResource.getImageDescriptor(WorkbenchResource.java:46)
	at org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider.getWorkbenchImageDescriptor(JavaElementImageProvider.java:193)
	at org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider.computeDescriptor(JavaElementImageProvider.java:133)
	at org.eclipse.jdt.internal.ui.viewsupport.JavaElementImageProvider.getImageLabel(JavaElementImageProvider.java:108)
	at org.eclipse.jdt.internal.ui.viewsupport.JavaUILabelProvider.getImage(JavaUILabelProvider.java:144)
	at org.eclipse.jdt.internal.ui.packageview.PackageExplorerLabelProvider.getImage(PackageExplorerLabelProvider.java:139)
	at org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.getImage(DelegatingStyledCellLabelProvider.java:198)
	at org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider.getImage(DecoratingStyledCellLabelProvider.java:171)
	at org.eclipse.jface.viewers.DelegatingStyledCellLabelProvider.update(DelegatingStyledCellLabelProvider.java:124)
	at org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider.update(DecoratingStyledCellLabelProvider.java:134)
	at org.eclipse.jface.viewers.ViewerColumn.refresh(ViewerColumn.java:144)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:959)
	at org.eclipse.jface.viewers.AbstractTreeViewer$UpdateItemSafeRunnable.run(AbstractTreeViewer.java:126)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.JFaceUtil$$Lambda$121/0x00000008002b2c40.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
	at org.eclipse.jface.viewers.AbstractTreeViewer.doUpdateItem(AbstractTreeViewer.java:1037)
	at org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer.doUpdateItem(ProblemTreeViewer.java:74)
	at org.eclipse.jdt.internal.ui.viewsupport.ResourceToItemsMapper.updateItem(ResourceToItemsMapper.java:78)
	at org.eclipse.jdt.internal.ui.viewsupport.ResourceToItemsMapper.resourceChanged(ResourceToItemsMapper.java:66)
	at org.eclipse.jdt.internal.ui.viewsupport.ProblemTreeViewer.handleLabelProviderChanged(ProblemTreeViewer.java:192)
	at org.eclipse.jface.viewers.ContentViewer$1.labelProviderChanged(ContentViewer.java:95)
	at org.eclipse.jface.viewers.BaseLabelProvider$1.run(BaseLabelProvider.java:75)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.JFaceUtil$$Lambda$121/0x00000008002b2c40.run(Unknown Source)
	at org.eclipse.jface.util.SafeRunnable.run(SafeRunnable.java:174)
	at org.eclipse.jface.viewers.BaseLabelProvider.fireLabelProviderChanged(BaseLabelProvider.java:72)
	at org.eclipse.jface.viewers.DecoratingStyledCellLabelProvider$$Lambda$555/0x0000000800e47840.labelProviderChanged(Unknown Source)
	at org.eclipse.ui.internal.decorators.DecoratorManager$1.run(DecoratorManager.java:349)
	at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:45)
	at org.eclipse.ui.internal.decorators.DecoratorManager.fireListener(DecoratorManager.java:346)
	at org.eclipse.ui.internal.decorators.DecorationScheduler$3.runInUIThread(DecorationScheduler.java:525)
	at org.eclipse.ui.progress.UIJob.lambda$0(UIJob.java:95)
	at org.eclipse.ui.progress.UIJob$$Lambda$787/0x0000000801102c40.run(Unknown Source)
	at org.eclipse.swt.widgets.RunnableLock.run(RunnableLock.java:40)
	at org.eclipse.swt.widgets.Synchronizer.runAsyncMessages(Synchronizer.java:185)
	at org.eclipse.swt.widgets.Display.runAsyncMessages(Display.java:4001)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3629)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$5.run(PartRenderingEngine.java:1157)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:1046)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:155)
	at org.eclipse.ui.internal.Workbench.lambda$3(Workbench.java:644)
	at org.eclipse.ui.internal.Workbench$$Lambda$141/0x0000000800344c40.run(Unknown Source)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:338)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:551)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:156)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:152)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:203)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:134)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:104)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:401)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:255)
	at java.base@14.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base@14.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at java.base@14.0.2/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base@14.0.2/java.lang.reflect.Method.invoke(Method.java:564)
	at app//org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:653)
	at app//org.eclipse.equinox.launcher.Main.basicRun(Main.java:590)
	at app//org.eclipse.equinox.launcher.Main.run(Main.java:1461)
Comment 1 Rolf Theunissen CLA 2020-12-26 04:58:50 EST
Inside org.eclipse.ui.internal.registry.EditorRegistry.getImageDescriptor(String, IContentType) line 1377-1387:
		
  // for dynamic UI - comment out the next line
  // extensionImages.put(key, anImage);

Which is the caching you are referring to. This is commented out from the initial contribution of this code, Bug 37668 for Eclipse 3.1. Be sure that we don't loose the 'dynamic UI' (whatever that should be).
Comment 2 Michael Keppler CLA 2020-12-27 10:52:37 EST
I wouldn't want to cache the _overall_ icon lookup, but rather just the external icons. So activating an eclipse plugin with an editor for some file extension would still change the result, but installing a Windows application for the same extension outside eclipse would not change the result anymore (for the running eclipse session).

Therefore only the result of getSystemExternalEditorImageDescriptor() would be cached.

I've been looking into the profiler a bit more closely. The slowness is caused by SWT using the Windows registry information to look for the associated executable, it's document name, and the icon of the application. All the time is spent in OS.AssocQueryString(), which maps directly to a native Windows function. So I guess there is not much to be optimized in that method itself. (see second screenshot).
Comment 3 Michael Keppler CLA 2020-12-27 10:53:53 EST
Created attachment 285115 [details]
AssocQueryString consumes all the time
Comment 4 Thomas Wolf CLA 2020-12-28 13:36:17 EST
EGit does that already; see org.eclipse.egit.ui.UIUtils.getEditorImage(). The reason is the same: EditorRegistry.getSystemExternalEditorImageDescriptor() is slow at least on Windows and on Linux. See bug 464891.

"dynamic UI" probably refers to changes made in the OS-level default editor associations resulting in showing a new icon as soon as possible (on the next refresh?) in Eclipse.
Comment 5 Thomas Wolf CLA 2020-12-28 13:54:39 EST
Re comment 1:

The commenting out of the caching and the dynamic UI comment were added in commit dbe9382347d3b20e300466542572c8892e05fb91 on 2004-01-08 "First cut of adding dynamic UIs to the workbench". No bug linked.

[1] https://git.eclipse.org/r/plugins/gitiles/platform/eclipse.platform.ui/+/dbe9382347d3b20e300466542572c8892e05fb91%5E%21/#F17
Comment 6 Thomas Wolf CLA 2020-12-28 14:10:37 EST
From old mailing list messages, "dynamic UI" could also refer to being able to load and unload UI bundles dynamically without having to restart Eclipse, and still have a sane and usable UI. See e.g. the thread starting at [1].

If that was the intention:

* I don't think not caching icons for external editors was correct; and
* has unloading a loaded and activated UI bundle with open views or editors
  ever worked? 

[1] https://www.eclipse.org/lists/platform-ui-dev/msg01275.html