From 383e01aec2faaaebdb17bd94e737b07f40055d73 Mon Sep 17 00:00:00 2001 From: Pawel Piech Date: Fri, 25 Apr 2008 16:59:57 +0000 Subject: [PATCH] [208476] Added queuing of events to the View Model cache. --- .../expression/ExpressionVMProvider.java | 9 ++ .../register/RegisterVMProvider.java | 10 ++ .../variable/VariableVMProvider.java | 9 ++ .../dsf/ui/viewmodel/AbstractVMProvider.java | 116 ++++++++++++++++-- .../DefaultVMModelProxyStrategy.java | 17 +-- .../update/AbstractCachingVMProvider.java | 30 +---- .../ui/viewmodel/launch/LaunchVMProvider.java | 23 ++++ 7 files changed, 161 insertions(+), 53 deletions(-) diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/expression/ExpressionVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/expression/ExpressionVMProvider.java index 536b1aeab30..81dbad87923 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/expression/ExpressionVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/expression/ExpressionVMProvider.java @@ -22,6 +22,7 @@ import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register.SyncR import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable.SyncVariableDataAccess; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable.VariableVMNode; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.DefaultVMContentProviderStrategy; @@ -326,4 +327,12 @@ public class ExpressionVMProvider extends AbstractDMVMProvider } handleEvent(new ExpressionsChangedEvent(type, rootElements)); } + + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize the performance of the view when stepping rapidly, skip all + // other events when a suspended event is received, including older suspended + // events. + return newEvent instanceof ISuspendedDMEvent; + } } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/register/RegisterVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/register/RegisterVMProvider.java index 06f08e1ed0e..6d63f52debc 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/register/RegisterVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/register/RegisterVMProvider.java @@ -12,6 +12,7 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.register; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.FormattedValuePreferenceStore; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; @@ -99,4 +100,13 @@ public class RegisterVMProvider extends AbstractDMVMProvider public void propertyChange(PropertyChangeEvent event) { handleEvent(event); } + + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize the performance of the view when stepping rapidly, skip all + // other events when a suspended event is received, including older suspended + // events. + return newEvent instanceof ISuspendedDMEvent; + } + } diff --git a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/variable/VariableVMProvider.java b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/variable/VariableVMProvider.java index 226d543c45a..a80bef9ec58 100644 --- a/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/variable/VariableVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.debug.ui/src/org/eclipse/dd/dsf/debug/internal/provisional/ui/viewmodel/variable/VariableVMProvider.java @@ -10,6 +10,7 @@ package org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.variable; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.numberformat.FormattedValuePreferenceStore; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.update.BreakpointHitUpdatePolicy; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; @@ -82,4 +83,12 @@ public class VariableVMProvider extends AbstractDMVMProvider return new IVMUpdatePolicy[] { new AutomaticUpdatePolicy(), new ManualUpdatePolicy(), new BreakpointHitUpdatePolicy() }; } + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize the performance of the view when stepping rapidly, skip all + // other events when a suspended event is received, including older suspended + // events. + return newEvent instanceof ISuspendedDMEvent; + } + } diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java index c6a14553935..1ff99595544 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/AbstractVMProvider.java @@ -15,12 +15,14 @@ import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; +import java.util.ListIterator; import java.util.Map; import java.util.concurrent.RejectedExecutionException; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; import org.eclipse.dd.dsf.concurrent.DsfExecutor; import org.eclipse.dd.dsf.concurrent.IDsfStatusConstants; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.ui.concurrent.DisplayDsfExecutor; import org.eclipse.dd.dsf.ui.concurrent.ViewerDataRequestMonitor; import org.eclipse.debug.internal.ui.viewers.model.provisional.IChildrenCountUpdate; @@ -123,6 +125,13 @@ abstract public class AbstractVMProvider implements IVMProvider */ private IRootVMNode fRootNode; + private class ModelProxyEventQueue { + private boolean fProcessingEvent = false; + private List fEventQueue = new LinkedList(); + } + + private Map fEventQueues = new HashMap(); + /** * Constructs the view model provider for given DSF session. The * constructor is thread-safe to allow VM provider to be constructed @@ -198,24 +207,109 @@ abstract public class AbstractVMProvider implements IVMProvider public void handleEvent(final Object event) { for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) { if (proxyStrategy.isDeltaEvent(event)) { - proxyStrategy.createDelta( - event, - new DataRequestMonitor(getExecutor(), null) { - @Override - public void handleCompleted() { - if (isSuccess()) { - proxyStrategy.fireModelChanged(getData()); + if (!fEventQueues.containsKey(proxyStrategy)) { + fEventQueues.put(proxyStrategy, new ModelProxyEventQueue()); + } + final ModelProxyEventQueue queue = fEventQueues.get(proxyStrategy); + if (queue.fProcessingEvent) { + if (!queue.fEventQueue.isEmpty()) { + for (ListIterator itr = queue.fEventQueue.listIterator(queue.fEventQueue.size() - 1); itr.hasPrevious();) { + Object eventToSkip = itr.previous(); + if (canSkipHandlingEvent(event, eventToSkip)) { + itr.remove(); + } else { + break; } } - @Override public String toString() { - return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - }); + } + queue.fEventQueue.add(event); + } else { + doHandleEvent(queue, proxyStrategy, event); + } + } + } + + // Clean up model proxies that were removed. + List activeProxies = getActiveModelProxies(); + for (Iterator itr = fEventQueues.keySet().iterator(); itr.hasNext();) { + if (!activeProxies.contains(itr.next())) { + itr.remove(); } } } + + private void doHandleEvent(final ModelProxyEventQueue queue, final IVMModelProxy proxyStrategy, final Object event) { + queue.fProcessingEvent = true; + handleEvent( + proxyStrategy, event, + new RequestMonitor(getExecutor(), null) { + @Override + protected void handleCompleted() { + queue.fProcessingEvent = false; + if (!queue.fEventQueue.isEmpty()) { + doHandleEvent(queue, proxyStrategy, queue.fEventQueue.remove(0)); + } + } + }); + } + /** + * Handles the given event for the given proxy strategy. + *

+ * This method is called by the base {@link #handleEvent(Object)} + * implementation to handle the given event using the given model proxy. + * The default implementation of this method checks whether the given + * proxy is active and if the proxy is active, it is called to generate the + * delta which is then sent to the viewer. + *

+ * @param proxyStrategy Model proxy strategy to use to process this event. + * @param event Event to process. + * @param rm Request monitor to call when processing the event is + * completed. + */ + protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { + if (!proxyStrategy.isDisposed()) { + proxyStrategy.createDelta( + event, + new DataRequestMonitor(getExecutor(), rm) { + @Override + public void handleCompleted() { + if (isSuccess()) { + proxyStrategy.fireModelChanged(getData()); + } + super.handleCompleted(); + } + @Override public String toString() { + return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + } + }); + } else { + rm.done(); + } + } + /** + * Determines whether processing of a given event can be skipped. This + * method is called when there are multiple events waiting to be processed + * by the provider. As new events are received from the model, they are + * compared with the events in the queue using this method, events at the + * end of the queue are tested for removal. If this method returns that a + * given event can be skipped in favor of the new event, the skipped event + * is removed from the queue. This process is repeated with the new event + * until an event which cannot be stopped is found or the queue goes empty. + *

+ * This method may be overriden by specific view model provider + * implementations extending this abstract class. + *

+ * @param newEvent New event that was received from the model. + * @param eventToSkip Event which is currently at the end of the queue. + * @return True if the event at the end of the queue can be skipped in + * favor of the new event. + */ + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + return false; + } + public IRootVMNode getRootVMNode() { return fRootNode; } diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java index 9267f413caa..0e3dd13cb16 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/DefaultVMModelProxyStrategy.java @@ -336,8 +336,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { new DataRequestMonitor>(getVMProvider().getExecutor(), null) { @Override protected void handleCompleted() { - if (isDisposed()) return; - // Check for an empty list of elements. If it's empty then we // don't have to call the children nodes, so return here. // No need to propagate error, there's no means or need to display it. @@ -449,13 +447,7 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { } final MultiRequestMonitor elementsDeltasMultiRequestMon = - new MultiRequestMonitor(getVMProvider().getExecutor(), null) { - @Override - protected void handleCompleted() { - if (isDisposed()) return; - requestMonitor.done(); - } - }; + new MultiRequestMonitor(getVMProvider().getExecutor(), requestMonitor); // For each element from this node, create a new delta, // and then call all the child nodes to build their delta. @@ -508,8 +500,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { new DataRequestMonitor>(getVMProvider().getExecutor(), null) { @Override protected void handleCompleted() { - if (isDisposed()) return; - final CountingRequestMonitor multiRm = new CountingRequestMonitor(getVMProvider().getExecutor(), requestMonitor); int multiRmCount = 0; @@ -562,11 +552,6 @@ public class DefaultVMModelProxyStrategy implements IVMModelProxy { final Integer[] counts = new Integer[childNodes.length]; final MultiRequestMonitor childrenCountMultiRequestMon = new MultiRequestMonitor(getVMProvider().getExecutor(), rm) { - @Override - protected void handleCompleted() { - if (isDisposed()) return; - super.handleCompleted(); - } @Override protected void handleSuccess() { Map data = new HashMap(); diff --git a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java index fd564c17be6..fc9296d2de6 100644 --- a/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java +++ b/plugins/org.eclipse.dd.dsf.ui/src/org/eclipse/dd/dsf/ui/viewmodel/update/AbstractCachingVMProvider.java @@ -21,6 +21,7 @@ import java.util.concurrent.Executor; import org.eclipse.core.runtime.IStatus; import org.eclipse.dd.dsf.concurrent.CountingRequestMonitor; import org.eclipse.dd.dsf.concurrent.DataRequestMonitor; +import org.eclipse.dd.dsf.concurrent.RequestMonitor; import org.eclipse.dd.dsf.datamodel.IDMContext; import org.eclipse.dd.dsf.datamodel.IDMData; import org.eclipse.dd.dsf.datamodel.IDMService; @@ -555,39 +556,16 @@ public class AbstractCachingVMProvider extends AbstractVMProvider implements ICa } @Override - public void handleEvent(final Object event) { + protected void handleEvent(final IVMModelProxy proxyStrategy, final Object event, RequestMonitor rm) { IElementUpdateTester elementTester = getActiveUpdatePolicy().getTesterTester(event); List flushKeys = new LinkedList(); - List proxies = new LinkedList(); - for (final IVMModelProxy proxyStrategy : getActiveModelProxies()) { - if (proxyStrategy.isDeltaEvent(event)) { - flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); - proxies.add(proxyStrategy); - } - } + flushKeys.add(new FlushMarkerKey(proxyStrategy.getRootElement(), elementTester)); flush(flushKeys); - for (final IVMModelProxy proxyStrategy : proxies) { - if (!proxyStrategy.isDisposed() && proxyStrategy.isDeltaEvent(event)) { - proxyStrategy.createDelta( - event, - new DataRequestMonitor(getExecutor(), null) { - @Override - public void handleCompleted() { - - if (isSuccess()) { - proxyStrategy.fireModelChanged(getData()); - } - } - @Override public String toString() { - return "Result of a delta for event: '" + event.toString() + "' in VMP: '" + this + "'" + "\n" + getData().toString(); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ - } - }); - } - } + super.handleEvent(proxyStrategy, event, rm); } /** diff --git a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java index 48f526cd4d0..84e0cd40b09 100644 --- a/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java +++ b/plugins/org.eclipse.dd.gdb.ui/src/org/eclipse/dd/gdb/internal/ui/viewmodel/launch/LaunchVMProvider.java @@ -14,10 +14,14 @@ package org.eclipse.dd.gdb.internal.ui.viewmodel.launch; import java.util.concurrent.RejectedExecutionException; import org.eclipse.dd.dsf.concurrent.ThreadSafe; +import org.eclipse.dd.dsf.datamodel.DMContexts; +import org.eclipse.dd.dsf.datamodel.IDMContext; +import org.eclipse.dd.dsf.datamodel.IDMEvent; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StackFramesVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.StandardProcessVMNode; import org.eclipse.dd.dsf.debug.internal.provisional.ui.viewmodel.launch.LaunchRootVMNode.LaunchesEvent; +import org.eclipse.dd.dsf.debug.service.IRunControl.ISuspendedDMEvent; import org.eclipse.dd.dsf.service.DsfSession; import org.eclipse.dd.dsf.ui.viewmodel.AbstractVMAdapter; import org.eclipse.dd.dsf.ui.viewmodel.IRootVMNode; @@ -126,4 +130,23 @@ public class LaunchVMProvider extends AbstractDMVMProvider // shut down. } } + + @Override + protected boolean canSkipHandlingEvent(Object newEvent, Object eventToSkip) { + // To optimize view performance when stepping rapidly, skip events that came + // before the last suspended events. However, the debug view can get suspended + // events for different threads, so make sure to skip only the events if they + // were in the same hierarchy as the last suspended event. + if (newEvent instanceof ISuspendedDMEvent && eventToSkip instanceof IDMEvent) { + IDMContext newEventDmc = ((IDMEvent)newEvent).getDMContext(); + IDMContext eventToSkipDmc = ((IDMEvent)eventToSkip).getDMContext(); + + if (newEventDmc.equals(eventToSkipDmc) || DMContexts.isAncestorOf(eventToSkipDmc, newEventDmc)) { + return true; + } + } + + return false; + } + }