Remaining Eclipse 3.0 responsiveness issues

Last modified: November 6, 2003

This document outlines the remaining UI responsiveness issues at the start of the 3.0 M5 cycle. A dynamic team has been set up with representatives from Platform Core, Platform UI, JDT Core, JDT UI, and Team to address these remaining issues during the M5 development cycle.

Consistent progress API

There are currently at least three different APIs for reporting progress on a blocking (modal) operation: the SWT BusyIndicator, ProgressMonitorDialog, and IStatusLineManager. There are many more ad-hoc mechanisms used by different components, as well as various dialogs (such as wizard dialog) that have their own progress mechanisms. This results in inconsistent progress presentation for blocking operations. Furthermore, BusyIndicator operates in the UI thread, and the other APIs provide an option to run in the current thread (fork=false).

Proposed solution:

  1. Introduce new progress API that doesn't commit to a particular presentation. Prototype API is included in current 3.0 stream I-builds. See IWorkbench.getProgressManager and IProgressManager.busyCursorWhile. This should probably be renamed to IProgressService to be more consistent with other workbench APIs, and avoid committing to the busy cursor in the method name (e.g., IProgressService.busyRun(IRunnableWithProgress)).
  2. Decide what to do with remaining APIs. Most likely deprecate. It may be possible to port some old APIs to forward to new APIs, but not BusyIndicator, and not ModalContext in fork=false case.
  3. Port all existing uses of old progress mechanisms to use new progress service (TBD).

Presentation of blocking operation progress

How should long running progress be presented by this new progress API? The two likely candidates are progress dialog or status line progress indicator. Tendency has been to move away from a modal dialog to the status line because a modal dialog has usability problems: breaks user's task concentration, hides information the user may currently be reading. Requirements for a progress presentation are:

The current prototype uses a busy cursor, followed by a progress monitor dialog after a sufficient delay. This avoids the distraction of a popping dialog for most cases, but gives enough room to describe the progress for longer running cases and blocked operations.

We also need a story for how dialogs with embedded progress indicators will work (e.g.: wizards, launch configuration dialog, preference dialog). Having a nested progress dialog within another dialog does not look nice. Need to revisit all implementors of IRunnableContext to see if new API is needed. Dirk suggested keeping IRunnableContext for consistency, possibly just changing the javadoc to indicate that the "cancel" parameter may be ignored (cancelation should always be possible).

Presentation of non-modal progress

We are learning about a number of situations where background operations are causing presentation problems in views. The following are descriptions of usability problems introduced by background activty. We are looking for input from other teams on other scenarios not covered here.

1. Incomplete/busy views

Some background jobs cause information to be incrementally added to a view. This results in a state where the view is "e;busy"e; for the duration of the job. During that period, the user needs to know that the information they are seeing is possibly incomplete. They also need to be aware that the view is in a state where it may change suddenly, causing unexpected flashing and scrolling. There also needs to be visible feedback when the view is no longer in this state.

Examples:

This new functionality should have a generic component that provides a uniform presentation of a busy view. Possible solutions include an icon overlay, changing title bar gradient, changing appearance of part pane border, and changing the cursor. Could also use a *brief* flashing title bar to indicate completion of long running task. The mechanism should have a hook method on WorkbenchPart that allows subclasses to add additional busyness indicators within the view body.

2. Stale views

Many views contain information that is *possibly* incorrect during a background job. The important distinction from the busy view scenario is that the information in the view during the job may actually be valid before, during, and after the job has been run. It is generally too much work to decide in advance what information is invalid so it can be hidden or removed. Generally, the job is currently doing the work to decide whether the information needs to be updated. This leads to errors when the user tries to perform actions on this stale information (for example jumping to a missing marker, or open a missing file).

Examples:

3. Inadequate indication of background activity

The current indication of background activity is weak. It is important that the user is aware when background operations are going on. If they know that something is happening, they are more likely to tolerate stale information, busy views, pauses, etc. Most applications use an animated 32x32 icon in the upper right hand corner of the window. Eclipse currently uses a 16x16 icon in the lower left corner, due to layout problems on certain platforms (i.e. Mac) with icons in the upper right. Even people working on the responsive UI have been in a state where they did not notice that background activity was happening, and were frustrated by stale information as a result.

Suggestion from discussions this week: the "3.0 look" group should look into this. An indicator that "breaks out" of the workbench window using the new SWT non-rectangular shell support might give enough feedback (in addition to looking slick).

Long running activity in UI thread

Currently many "short" (1-10 seconds) operations run directly in the UI thread. This causes the entire view to become unresponsive (no painting). Further, this leaves absolutely no way for the UI to inform the user that they are blocked by background activity, and no way for the user to cancel. For these reasons, any operation that may be blocked by a very long running activity must be run outside the UI thread. This includes all operations that modify resources and markers.

As of I20031029, marker changes no longer require any scheduling rule. This means there is nothing that will block marker changes for extended periods due to conflicts with ongoing background activity. The remaining problem is that almost all marker changes are wrapped within an IWorkspaceRunnable, which for backwards compatibility reasons must lock the entire workspace. A new IWorkspace.run method is now available that takes a resource scheduling rule. This method is used for finer-grained locking of resources during the invocation of an IWorkspaceRunnable. A 3.0 porting guide section will be needed to describe why clients should update their calls to IWorkspace.run to use the method that supports finer-grained locking. UI clients will need to do a sweep to begin using this method where applicable.

Since marker changes are now less likely to block, it is ok for them to run in the UI thread. However, it is still the case that all resource (file, folder) changes should be moved into a background thread using the new UI progress service. This will allow users to cancel where the change is not compatible with background activity.

A suggestion was made to resolve this issue by shifting the burden to the implementors of background operations. If the UI thread tries to make a change that conflicts with the background operation, the background operation could be suspended to allow the UI thread to proceed. This would require that we provide the background operation with a resource delta describing what changes occurred while it was suspended. It could then decide whether it should proceed, abort, or rollback depending on the nature of the conflicting change. However, even a resource delta would not always provide sufficient information for it to make a decision. If the operation was in the middle of making a series of changes to a file when interrupted, it would not be able to rollback correctly without a binary delta describing how the file changed while it was interrupted. These transaction semantics would be extremely difficult to implement. Another approach is to require the background operation to break up long running work into small transactions, and require the operation to support cancelation after each transaction. This is the approach taken by the automatic cancelation support in background autobuild. To be effective, each transaction would need to be of sufficiently small duration that locking the UI for that duration would be acceptable. It is not clear in the general case that all background operations could be implemented in this way.

We also discussed the possibility of hacking in support for cancelation even when operations are run in the UI thread. This can be sold as a "backwards compatibility" story for UI components that do not move their long running operations out of the UI thread. This can be achieved by adding a method to IProgressProvider to specify a default progress monitor when none is provided by the operation. This monitor can then spin the event loop (ala EventLoopProgressMonitor), and open a dialog when the foreground operation is blocked.

A suggestion was raised that this support could work by opening a second display with its own event loop, just for the purpose of giving some form of progress feedback when people writing long running code in the UI thread. Mcq believes this will not work on all platforms.

Slow computer preference

In 3.0 M4 a slider preference was introduced to allow the user to indicate that they have a slow computer. The intent is that highly CPU intensive features should consult this preference before deciding whether they should run. This can also be used to throttle the amount of background activity, and to increase the sleep times used by non-critical background activities such as decoration, editor reconciling, and indexing. We need to identify what features should use this preference, and begin making use of it.

Periodic notifications

One of the items in the builders and listeners proposal was to introduce resource change notifications during long running operations. There are several motivations for this:

Drawbacks of more frequent notifications include:

The new IWorkspace.run method now also takes a "style bit" that can be used to specify that periodic notifications are not wanted. This allows clients to provide a hint to core that it doesn't make sense to perform resource change notfications during that operation. The old run method forwards to the new method and allows specifies the AVOID_UPDATE flag. So, clients calling the old API will get old style batching for free. This flag is phrased as a hint because notifications are sometimes required when multiple operations run concurrently. I.e, if two threads are modifying the workspace, one using AVOID_UPDATE and the other not, then periodic notifications will occur for the duration of the operation that did not specify AVOID_UPDATE.

Another suggestion was to provide partial workspace updates. If a notifying operation runs concurrently with a non-notifying operation, the workspace could broadcast a partial delta reflecting only the changes made by the notifying operation. See the bug report discussion on this proposal. In short, this would be quite complex to implement and would open up new breaking changes for listeners.

Porting guide

Enumerate API breakages and deprecations, and major non-API behaviour changes that may impact 2.1-based clients. Begin drafting of 3.0 porting guide chapters for the responsive UI work.

Miscellaneous

Posting behind current operation

Dirk to provide more detail here since the phone connection was breaking up. The issue is when you want to "post" a chunk of code to run after the current operation is completed. This is currently accomplished using asyncExec, but if the operation is run in the UI thread, then the asyncExec may be processed before the operation completes due to hacks like EventLoopProgressMonitor. This is possible with operations built on the 3.0 jobs API, but not for foreground (non-job) operations. For jobs, clients can call IJobManager.currentJob to find the currently running job, then hook a listener on the job to fire another job/operation when the first job completes. There were no recommendations for how to handle this for clients not using the jobs API.

Concurrency test harness

The core concurrency test harness may have some pieces that can be generalized and pushed down into the test.harness project, to help other components in writing concurrency tests.


Go back to concurrency home.

(Plan item bug reference: 36957)