KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > ui > internal > ide > IDEIdleHelper


1 /*******************************************************************************
2  * Copyright (c) 2005, 2006 IBM Corporation and others.
3  * All rights reserved. This program and the accompanying materials
4  * are made available under the terms of the Eclipse Public License v1.0
5  * which accompanies this distribution, and is available at
6  * http://www.eclipse.org/legal/epl-v10.html
7  *
8  * Contributors:
9  * IBM Corporation - initial API and implementation
10  *******************************************************************************/

11 package org.eclipse.ui.internal.ide;
12
13 import org.eclipse.core.runtime.IProgressMonitor;
14 import org.eclipse.core.runtime.IStatus;
15 import org.eclipse.core.runtime.Platform;
16 import org.eclipse.core.runtime.Status;
17 import org.eclipse.core.runtime.jobs.Job;
18 import org.eclipse.swt.SWT;
19 import org.eclipse.swt.SWTException;
20 import org.eclipse.swt.widgets.Display;
21 import org.eclipse.swt.widgets.Event;
22 import org.eclipse.swt.widgets.Listener;
23 import org.eclipse.ui.PlatformUI;
24 import org.eclipse.ui.application.IWorkbenchConfigurer;
25
26 /**
27  * The idle helper detects when the system is idle in order to perform garbage
28  * collection in a way that minimizes impact on responsiveness of the UI.
29  * The algorithm for determining when to perform a garbage collection
30  * is as follows:
31  *
32  * - Never gc if there is a test harness present
33  * - Don't gc if background jobs are running
34  * - Don't gc if the keyboard or mouse have been active within IDLE_INTERVAL
35  * - Don't gc if there has been a GC within the minimum gc interval (system property PROP_GC_INTERVAL)
36  * - After a gc, don't gc again until (duration * GC_DELAY_MULTIPLIER) has elapsed.
37  * For example, if a GC takes 100ms and the multiplier is 60, don't gc for at least five seconds
38  * - Never gc again if any single gc takes longer than system property PROP_GC_MAX
39  */

40 class IDEIdleHelper {
41
42     /**
43      * The default minimum time between garbage collections.
44      */

45     private static final int DEFAULT_GC_INTERVAL = 60000;
46
47     /**
48      * The default maximum duration for a garbage collection, beyond which
49      * the explicit gc mechanism is automatically disabled.
50      */

51     private static final int DEFAULT_GC_MAX = 8000;
52
53     /**
54      * The multiple of the last gc duration before we will consider doing
55      * another one.
56      */

57     private static final int GC_DELAY_MULTIPLIER = 60;
58
59     /**
60      * The time interval of no keyboard or mouse events after which the system
61      * is considered idle.
62      */

63     private static final int IDLE_INTERVAL = 5000;
64
65     /**
66      * The name of the boolean system property that specifies whether explicit
67      * garbage collection is enabled.
68      */

69     private static final String JavaDoc PROP_GC = "ide.gc"; //$NON-NLS-1$
70

71     /**
72      * The name of the integer system property that specifies the minimum time
73      * interval in milliseconds between garbage collections.
74      */

75     private static final String JavaDoc PROP_GC_INTERVAL = "ide.gc.interval"; //$NON-NLS-1$
76

77     /**
78      * The name of the integer system property that specifies the maximum
79      * duration for a garbage collection. If this duration is ever exceeded, the
80      * explicit gc mechanism is disabled for the remainder of the session.
81      */

82     private static final String JavaDoc PROP_GC_MAX = "ide.gc.max"; //$NON-NLS-1$
83

84     protected IWorkbenchConfigurer configurer;
85
86     private Listener idleListener;
87
88     /**
89      * The last time we garbage collected.
90      */

91     private long lastGC = System.currentTimeMillis();
92
93     /**
94      * The maximum gc duration. If this value is exceeded, the
95      * entire explicit gc mechanism is disabled.
96      */

97     private int maxGC = DEFAULT_GC_MAX;
98     /**
99      * The minimum time interval until the next garbage collection
100      */

101     private int minGCInterval = DEFAULT_GC_INTERVAL;
102
103     /**
104      * The time interval until the next garbage collection
105      */

106     private int nextGCInterval = DEFAULT_GC_INTERVAL;
107     
108     private Job gcJob;
109
110     private Runnable JavaDoc handler;
111     
112     /**
113      * Creates and initializes the idle handler
114      * @param aConfigurer The workbench configurer.
115      */

116     IDEIdleHelper(IWorkbenchConfigurer aConfigurer) {
117         this.configurer = aConfigurer;
118         //don't gc while running tests because performance tests are sensitive to timing (see bug 121562)
119
if (PlatformUI.getTestableObject().getTestHarness() != null) {
120             return;
121         }
122         String JavaDoc enabled = System.getProperty(PROP_GC);
123         //gc is turned on by default if property is missing
124
if (enabled != null && enabled.equalsIgnoreCase(Boolean.FALSE.toString())) {
125             return;
126         }
127         //init gc interval
128
Integer JavaDoc prop = Integer.getInteger(PROP_GC_INTERVAL);
129         if (prop != null && prop.intValue() >= 0) {
130             minGCInterval = nextGCInterval = prop.intValue();
131         }
132
133         //init max gc interval
134
prop = Integer.getInteger(PROP_GC_MAX);
135         if (prop != null) {
136             maxGC = prop.intValue();
137         }
138         
139         createGarbageCollectionJob();
140
141         //hook idle handler
142
final Display display = configurer.getWorkbench().getDisplay();
143         handler = new Runnable JavaDoc() {
144                     public void run() {
145                         if (!display.isDisposed() && !configurer.getWorkbench().isClosing()) {
146                             int nextInterval;
147                             final long start = System.currentTimeMillis();
148                             //don't garbage collect if background jobs are running
149
if (!Platform.getJobManager().isIdle()) {
150                                 nextInterval = IDLE_INTERVAL;
151                             } else if ((start - lastGC) < nextGCInterval) {
152                                 //don't garbage collect if we have collected within the specific interval
153
nextInterval = nextGCInterval - (int) (start - lastGC);
154                             } else {
155                                 gcJob.schedule();
156                                 nextInterval = minGCInterval;
157                             }
158                             display.timerExec(nextInterval, this);
159                         }
160                     }
161                 };
162         idleListener = new Listener() {
163             public void handleEvent(Event event) {
164                 display.timerExec(IDLE_INTERVAL, handler);
165             }
166         };
167         display.addFilter(SWT.KeyUp, idleListener);
168         display.addFilter(SWT.MouseUp, idleListener);
169     }
170
171     /**
172      * Creates the job that performs garbage collection
173      */

174     private void createGarbageCollectionJob() {
175         gcJob = new Job(IDEWorkbenchMessages.IDEIdleHelper_backgroundGC) {
176             protected IStatus run(IProgressMonitor monitor) {
177                 final Display display = configurer.getWorkbench().getDisplay();
178                 if (display != null && !display.isDisposed()) {
179                     final long start = System.currentTimeMillis();
180                     System.gc();
181                     System.runFinalization();
182                     lastGC = start;
183                     final int duration = (int) (System.currentTimeMillis() - start);
184                     if (Policy.DEBUG_GC) {
185                         System.out.println("Explicit GC took: " + duration); //$NON-NLS-1$
186
}
187                     if (duration > maxGC) {
188                         if (Policy.DEBUG_GC) {
189                             System.out.println("Further explicit GCs disabled due to long GC"); //$NON-NLS-1$
190
}
191                         shutdown();
192                     } else {
193                         //if the gc took a long time, ensure the next gc doesn't happen for awhile
194
nextGCInterval = Math.max(minGCInterval, GC_DELAY_MULTIPLIER * duration);
195                         if (Policy.DEBUG_GC) {
196                             System.out.println("Next GC to run in: " + nextGCInterval); //$NON-NLS-1$
197
}
198                     }
199                 }
200                 return Status.OK_STATUS;
201             }
202         };
203         gcJob.setSystem(true);
204     }
205
206     /**
207      * Shuts down the idle helper, removing any installed listeners, etc.
208      */

209     void shutdown() {
210         if (idleListener == null) {
211             return;
212         }
213         final Display display = configurer.getWorkbench().getDisplay();
214         if (display != null && !display.isDisposed()) {
215             try {
216                 display.asyncExec(new Runnable JavaDoc() {
217                     public void run() {
218                         display.timerExec(-1, handler);
219                         display.removeFilter(SWT.KeyUp, idleListener);
220                         display.removeFilter(SWT.MouseUp, idleListener);
221                     }
222                 });
223             } catch (SWTException ex) {
224                 // ignore (display might be disposed)
225
}
226         }
227     }
228 }
Popular Tags