| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> |
| <html> |
| <head> |
| <title>Towards a more responsive Eclipse UI</title> |
| <link rel="stylesheet" href="http://dev.eclipse.org/default_style.css" type="text/css"> |
| </head> |
| <body text="#000000" bgcolor="#FFFFFF"> |
| |
| <h1>Towards a more responsive Eclipse UI</h1> |
| |
| <font size="-1">Last modified: June 4, 2003</font> |
| <p>Eclipse is well known as a powerful integrated development environment, |
| but it is perceived by users as sometimes being unwieldy or unresponsive |
| to work with. The goal of this work is to uncover the underlying causes of |
| the unresponsiveness and provide Eclipse developers with the tools they need |
| to focus on making their code responsive. </p> |
| |
| <p>To begin with, it is important to note that, responsiveness is not the |
| same as performance, and to some extent they are contradictory:</p> |
| |
| <p>The <i>performance</i> of an application is a measure of how much work |
| it can do in a given length of time. For example, the Eclipse Platform can |
| operate on thousands of files per minute on a typical desktop system. One |
| way to achieve high performance is to ensure that all available resources |
| are dedicated to each task until it is complete. Since most modern window |
| systems require applications to regularly call system code to keep their |
| user interfaces active, dedicating all processing resources to a non-user-interface |
| task will cause the user interface to become unresponsive.</p> |
| |
| <p>The <i>responsiveness</i> of an application is a measure of how often |
| its user interface is in a state where the user can interact with it, how |
| often those interactions can trigger new tasks being initiated, and how often |
| the information the user interface is displaying accurately reflects the state |
| of the system it is modeling. Implementing a responsive system will require |
| the system resources to be split across multiple concurrent tasks, so although |
| the user will typically be more productive, the time it takes the system |
| to complete a particular task will be longer (i.e. Its performance on <u>that |
| task</u> will be lower).</p> |
| |
| <p>In order to increase the responsiveness of the Eclipse Platform we will |
| be looking at the following two areas:</p> |
| |
| <ol> |
| <li> |
| <p>all of the user interface "features" of the Eclipse Platform will |
| be investigated to remove any inherent limitations which prevent them from |
| being used in a responsive fashion. We have not begun work on this aspect |
| of the problem, so it is difficult to provide any definitive examples. However, |
| some likely candidates for investigation, at least, would be:</p> |
| </li> |
| </ol> |
| <ul> |
| <li> |
| <p>the startup sequence, since the time between when the user starts |
| the application and when they can start working is very important to their |
| perception of its responsiveness.</p> |
| </li> |
| <li> |
| <p>SWT widgets like the Table, Tree, and List whose API make it difficult |
| to code in an "on demand" style where the contents are requested by the |
| widget when they are required for display, rather than up front by the application.</p> |
| </li> |
| <li> |
| <p>the Java text editor, which takes significantly longer to get to |
| the point where the contents can be edited than the simple text editor.</p> |
| </li> |
| </ul> |
| |
| <ol start="2"> |
| <li> |
| <p>certain operations like builds and searches which currently run synchronously |
| and block the user (at the UI) from doing other work until they are completed |
| will be modified to run asynchronously in the background. Implementing this |
| requires an improved concurrency architecture. The remainder of this document |
| describes the work which has been done so far in that area.</p> |
| </li> |
| </ol> |
| |
| <h2>Overview of current problems</h2> |
| |
| <ul> |
| <li> Use of modal progress dialogs is pervasive in the UI, preventing the |
| user from doing any other work (or even browsing) while long running tasks |
| are processing. </li> |
| <li> Very long running operations only update the UI once at the very end. |
| For example, when searching, no search results are available for viewing |
| until the entire search is complete. When importing or checking out large |
| projects, the project doesn't appear in the UI until every file in the project |
| has been created. </li> |
| <li> Many components have their own mechanism for managing background activity. |
| Examples include: search indexing, UI decoration, Java editor reconciling, |
| and workspace snapshot. Each component should not have to roll their own |
| concurrency architecture for off-loading work into background threads. </li> |
| <li>The current workspace lock is heavy handed. There is a single write |
| lock for the entire workspace, and it is generally acquired for significant |
| periods of time. This can block other processes for several minutes. When |
| the lock is acquired, no other threads can modify the workspace in any way. |
| </li> |
| <li> The workspace locking mechanism is currently tied to the mechanism |
| for batching workspace changes. We widely advertise that compound workspace |
| changes should be done within an IWorkspaceRunnable. The workspace is always |
| locked for the duration of the IWorkspaceRunnable even if it is not making |
| changes to the workspace. </li> |
| <li> Various plugins have their own locking mechanisms. Since plugins don't |
| always know about each other, these locks can conflict in unforeseeable ways, |
| making Eclipse prone to deadlock. </li> |
| |
| <p> </p> |
| </ul> |
| |
| <h2>Proposed solutions</h2> |
| |
| <h3>Job scheduling mechanism</h3> |
| |
| <p> Platform core (runtime plugin) will introduce a new job manager API for |
| background work. This API will allow clients to: </p> |
| <ul> |
| <li> Schedule <i>Job</i> instances, units of runnable background activity. |
| Jobs can be scheduled either for immediate execution, or execution after |
| some specified delay. The platform will maintain a queue for waiting jobs, |
| and will manage a pool of worker threads for running the jobs. </li> |
| <li> Specify job scheduling priority, as well as explicit dependencies between |
| jobs (Job A must run after Job B but before Job C, etc). </li> |
| <li> Specify job scheduling rules, which will allow implicit constraints |
| to be created between jobs that don't know about each other. For example, |
| a Job can say: "While I'm running, I require exclusive access to resource |
| X. Don't run me until it's safe to do so, and don't run any other jobs that |
| might conflict with me until I'm done". The constraint system will be generic |
| at the level of the job scheduling API, but other plugins can introduce standard |
| constraints that apply to their components. </li> |
| <li> Query, cancel and change priority of jobs that are waiting to run. This |
| allows clients to cancel jobs that have become irrelevant before they had |
| a chance to run. (Example: cancel pending indexing or decoration jobs on |
| a project when the project is deleted). </li> |
| <li> Group jobs into families, and query, cancel, and manage entire job |
| families as a unit. </li> |
| <li> Register for notification when jobs are scheduled, started, finished, |
| canceled, etc. Clients can register for notification on a single job, or |
| on all jobs. </li> |
| <li> Provide a mechanism to allow jobs to carry their work over to another |
| thread and finish asynchronously. This is needed to allow jobs to asyncExec |
| into the UI, but maintain scheduling rules and avoid notifiying listeners until |
| the async block has returned. |
| </li> |
| <li> Add listeners to be hooked to the progress monitor callbacks of the |
| running jobs. This allows the UI to report progress on jobs that would otherwise |
| have no way of connecting with the UI (such as indexing or snapshot jobs). |
| </li> |
| |
| </ul> |
| |
| <p> This scheduling mechanism will replace most (if not all) existing background |
| thread mechanisms in the SDK. This includes: editor reconcilers, UI decoration, |
| search and Java indexing, workspace snapshot, and various threads used in the launch/debug |
| framework: JDI thread for communicating with the VM, threads for monitoring |
| input and output streams, debug view update thread, and the thread waiting |
| for VM termination. </p> |
| |
| <p> Also, the scheduling facility will make it easier for more components |
| to off-load work into background threads, in order to free up the UI thread |
| for responding to the user. This includes all jobs that currently run in |
| the context of a modal progress indicator, but also other processing work |
| that currently executes in the UI. Examples of activity that can be offloaded |
| into jobs: decorating editors (marker ruler, overview ruler), type hierarchy |
| computation, structure compare in compare editors, auto-refresh with file |
| system, etc. </p> |
| |
| <p> |
| Scalability of the job manager mechanism will be a concern for some applications |
| that are processing large numbers of very small work items, such as the decoration |
| thread and the indexer thread. Creating a separate job for each work item would |
| severely degrade the scheduler, and could result in an unwanted level of concurrency. |
| For example, if several indexing jobs happen concurrently, then they may complete |
| in the wrong order and corrupt the index files. |
| </p> |
| <p> |
| This can be solved by creating a single master job that maintains its own queue of |
| smaller work items. The master job would run as long as work items remained in its |
| private queue. If work items are added when the master job is not running, it can be |
| scheduled lazily. If these systems still have to maintain their own queue, then why |
| bother use the job manager at all? There are still some benefits: |
| <ul> |
| <li>The user will be aware that background work is going on. Giving the user some |
| feedback when the system is busy and a hint about when it might finish will make it |
| easier for them to accept a temporary degradation of responsiveness.</li> |
| <li> |
| The job manager scheduling rules can be used to manage the relationship between |
| the indexing or decoration master job and other running jobs. For example, the job |
| manager could ensure that the indexer didn't run at the same time as a search job. |
| </li> |
| <li> |
| Core runtime can provide some infrastructure pieces, such as a thread-safe queue, |
| that simplifies the work required by components to implement this pattern.</li> |
| </ul> |
| </p> |
| |
| <h3>New UI look and feel for long running activity</h3> |
| |
| <p> Long running operations will generally be run without a modal progress indicator |
| by scheduling them with the core job manager API. Most jobs currently using a |
| modal progress dialog will switch to this new non-modal way of running. |
| The platform UI will provide a view from which users can see the list of waiting and |
| running background jobs, along with their current progress. This is a view rather than |
| a dialog so the user can continue to manipulate the UI while background jobs are |
| running. This view will likely take the form of a tree so that expanding a job will |
| give more detailed progress information. The UI will also provide some ubiquitous |
| feedback device (much like the page loading indicator in popular web browsers or the |
| Macintosh user interface), that will indicate when background activity is happening. |
| </p> |
| <p>Users will be able to cancel any background activity from the progress view. |
| Users will also be able to pause, resume, or fast forward (increase priority |
| of) any waiting job. Since we can never know which of several background jobs |
| the user is most anxious to complete, this puts some power in the user's hands |
| to influence the order of execution of waiting background jobs.</p> |
| |
| <p> |
| The platform UI will introduce a special job called a UI job, which is simply a job that |
| needs to be run in the UI Thread. We define this type of job as a convenience for those |
| who do not want to keep looking for a Display to asyncExec in. Casting UI work |
| as jobs will allow the framework to control scheduling based on priority and user |
| defined scheduling rules. Note that although UI jobs should generally be brief |
| in duration, they may require locks and thus the framework must have a strategy |
| for avoiding deadlock when the UI thread is waiting for a lock. |
| |
| <h3>Minimize use of long term workspace locks</h3> |
| |
| <p> We will actively discourage clients from acquiring the workspace lock |
| for indefinite periods of time. <code>IWorkspaceRunnable</code> is the current |
| mechanism that allows clients to lock the workspace for the duration of a |
| runnable. This API will be deprecated. Clients that require exclusive |
| access to portions of the workspace should schedule background jobs with |
| appropriate scheduling rules. Scheduling rules can specify smaller portions |
| of the workspace, allowing clients to "lock" only the resources they need. |
| Longer running workspace API methods will be broken up as much as possible |
| to avoid locking the workspace for extended periods. Clients that do not |
| run as jobs, or that run as jobs without the appropriate scheduling rules, |
| will have to be tolerant of concurrent modifications to the workspace. </p> |
| |
| <h3>New resource change notification and autobuild strategy</h3> |
| |
| <p> The current mechanism for batching resource changes and auto-building |
| is based on the <code>IWorkspaceRunnable</code> API. This approach has two |
| problems: </p> |
| <ol> |
| <li> Clients sometimes forget to use it, which results in severe performance |
| problems because notifications and auto-builds happen more often than necessary. |
| </li> |
| <li> This can become too coarse-grained for long running operations. If |
| the user begins an operation that will take several minutes, it would be |
| nice to perform some incremental updates (notifications) while the operation |
| is still running. </li> |
| |
| </ol> |
| |
| <p></p> |
| |
| <p> The resources plugin will adopt new heuristics for when builds and notifications |
| should happen. These heuristics will likely require some fine-tuning and |
| may need to be customizable, but generally: </p> |
| <ul> |
| <li>Resource change notifications will always start within a bounded period |
| after the workspace has changed (such as five seconds). This will ensure notifications |
| occur periodically during long operations. </li> |
| <li> Notification will begin immediately if there have been no workspace |
| changing jobs in the job queue for a short period (such as 500 milliseconds). |
| This ensures timely user feedback when background activity has stopped. |
| There will be a lower bound on the frequency of notifications to prevent |
| listeners from hogging the CPU. </li> |
| <li>There will be API for forcing an immediate notification if clients know |
| it is either necessary or desirable for a notification to occur. (actually, |
| this mechanism has existed since Eclipse 1.0 in the method <code>IWorkspace.checkpoint</code>). |
| UI actions will use this for indicating when a user action has completed. |
| Other clients that absolutely depend on the results of notifications can |
| also use this mechanism (for example clients that depend on the java model |
| being up to date). </li> |
| <li> Autobuilds will begin (if needed) when the work queue has been idle |
| for a sufficient period of time (such as 1 second). If a background job |
| that requires write access to the workspace is scheduled before autobuild |
| completes, then auto-build will be canceled automatically. Existing builders |
| will need to improve their cancelation behaviour so that a minimal amount |
| of work is lost. </li> |
| <li> There will still be a mechanism to allow users or API clients to force |
| a build to occur, and these explicit builds will not be canceled automatically |
| by conflicting background activity. </li> |
| <li> Both builders and listeners could adapt automatically if they start |
| interfering with ongoing work by increasing their wait period. This would |
| allow builders and listeners to adapt to changes in activity levels. </li> |
| |
| </ul> |
| |
| <p></p> |
| |
| <p> Unless explicitly requested, builds and resource change listeners will |
| always be run asynchronously in a different thread from the one that initiated |
| the change. This will improve the responsiveness of workspace changing operations |
| that are initiated from the UI thread. </p> |
| |
| <h3>Centralized locking mechanism</h3> |
| |
| <p> Platform core (runtime plugin) will introduce a smart locking facility. |
| Clients that require exclusive access to a code region should use these |
| locks as a replacement for Java object monitors in code that may interact |
| with other locks. This will allow the platform to detect and break potential |
| deadlocks. Note that these locks are orthogonal to the job scheduling rules |
| described earlier. Job scheduling rules typically ensure that only non conflicting |
| jobs are running, but cannot guarantee protection from malicious or incorrect |
| code. </p> |
| These locks will have the following features: |
| <ul> |
| <li>They will be reentrant. A single thread can acquire a given lock more |
| than once, and it will only be released when the number of acquires equals |
| the number of releases. </li> |
| <li>They will automatically manage interaction with the SWT synchronizer |
| to avoid deadlocking in the face of a syncExec. I.e., if the UI thread |
| tries to acquire a lock, and another thread holding that lock tries to perform |
| a syncExec, the UI thread will service the syncExec work and then continue |
| to wait for the lock. </li> |
| <li>They will avoid deadlocking with each other. I.e., if thread A acquires |
| lock 1, then waits on lock 2, while thread B acquires lock 2 and waits on |
| lock 1, deadlock would normally ensue. The platform locking facility will |
| employ a release and wait protocol to ensure that threads waiting for locks |
| do not block other threads. </li> |
| |
| </ul> |
| |
| <h2>Milestone targets</h2> |
| |
| <ul> |
| <li> M1: Core runtime job manager API defined and implemented. UI API defined |
| with reference implementation. Prototype UI implementation of progress view |
| and progress animation. All components should begin looking into thread safety |
| issues with their API. </li> |
| <li>M2: In a branch, a significant subset of the Eclipse platform converted |
| to use the new mechanisms. Ongoing work in all components to become thread |
| safe and to port existing components to job manager API (reconciler, indexer, |
| decorator, debug events). </li> |
| <li> M3: all platform work moved from branch to HEAD at beginning of M3 |
| cycle. Goal for end of M3 is some level of stability across entire SDK |
| in new concurrent world. All component API must be thread safe. </li> |
| |
| </ul> |
| <p> |
| This schedule is aggressive but the intent is to wrap up platform work by |
| end of M3. This allows plenty of time to shake out threading bugs and allow |
| other components to stabilize by M4. |
| </p> |
| <p> |
| Go <a href="../planning/3.0/plan_concurrency.html">back to concurrency home</a>. |
| </p> |
| (Plan item bug reference: <a |
| href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=36957">36957</a>)<br> |
| </body> |
| </html> |